单例模式:
单例模式可以确保系统中某个类只有一个实例,该类自行实例化并向整个系统提供这个实例的公共访问点,除了该公共访问点,不能通过其他途径访问该实例。单例模式的优点在于:
- 系统中只存在一个共用的实例对象,无需频繁创建和销毁对象,节约了系统资源,提高系统的性能
- 可以严格控制客户怎么样以及何时访问单例对象。
单例模式的写法有好几种,主要有三种:
- 懒汉式单例
- 饿汉式单例
- 登记式单例
实现代码:
package com.model.singleton;
/**
* 单例模式
*
* @author haveman.lv
*/
public class Singleton {
private static Singleton lazySingleton = null;
private static volatile Singleton volatileLazySingleton = null;
private static final Singleton HUNGRY_SINGLETON = new Singleton();
private Singleton(){
}
/**
* 饿汉模式
*/
/*public static Singleton getInstance() {
return HUNGRY_SINGLETON;
}*/
/**
* 存在线程安全问题
*/
public static Singleton getInstance() {
if (lazySingleton == null){
lazySingleton = new Singleton();
}
return lazySingleton;
}
/**
* 同步锁<br>
* 线程安全,性能低
*/
public static synchronized Singleton getInstanceBySync() {
if (lazySingleton == null) {
lazySingleton = new Singleton();
}
return lazySingleton;
}
/**
* 双重锁定检查,没有性能问题<br>
* 需要用到 volatile 关键字,禁止指定重排序<br>
* <br>
* 指定重排序:由于构造方法不是一个原子操作,编译后会生成多条字节码指令,<br>
* 由于 JAVA的 指令重排序,可能会先执行 singleton 的赋值操作,<br>
* 该操作实际只是在内存中开辟一片存储对象的区域后直接返回内存的引用,<br>
* 之后 singleton 便不为空了,但是实际的初始化操作却还没有执行。<br>
* 如果此时线程B进入,就会拿到一个不为空的但是没有完成初始化的singleton 对象
*/
public static Singleton getInstanceByDbCheck() {
if (volatileLazySingleton == null) {
synchronized (Singleton.class) {
if (volatileLazySingleton == null) {
volatileLazySingleton = new Singleton();
}
}
}
return volatileLazySingleton;
}
/**
* 静态内部类,提供实例化支持<br>
* 线程安全,无性能问题
*
* @author haveman.lv
*/
public static class LazyHolder {
private static final Singleton INSTANCE = new Singleton();
}
public static final Singleton getInstanceByInnerClass() {
return LazyHolder.INSTANCE;
}
// ================server method===============
public void sayHello() {
System.out.println("Hello World!");
}
}
package com.model.singleton;
import java.util.HashMap;
import java.util.Map;
/**
* 单例管理器
*
* @author haveman.lv
*/
public class SingletonManagement {
private static Map<String, Singleton> map = new HashMap<>();
public static String DEFAULT_SINGLE_NAME = "default";
private SingletonManagement(){
}
public static Singleton getInstance(String name) {
if (name == null || name.length() <= 0){
name = DEFAULT_SINGLE_NAME;
}
if (map.get(name) == null){
map.put(name, Singleton.getInstanceByInnerClass());
System.out.println("initial singleton by management, name is " + name);
}
return map.get(name);
}
}
测试:
package com.model.singleton;
public class Test {
public static void main(String[] args) {
Singleton s1 = SingletonManagement.getInstance(null);
s1.sayHello();
Singleton s2 = SingletonManagement.getInstance("s2");
s2.sayHello();
Singleton s3 = SingletonManagement.getInstance(null);
s3.sayHello();
}
}
输出结果:
initial singleton by management, name is default
Hello World!
initial singleton by management, name is s2
Hello World!
Hello World!