单例模式的一些认识
程序员文章站
2022-06-03 19:07:15
...
private AAA(){
}
1 饿汉式 (线程安全,不能延迟实例化,浪费内存空间)
private static AAA aaa = new AAA();
public static AAA getInstance(){
return aaa;
}
2 懒汉式 (线程安全,延迟实例化)
private static AAA instance;
public static synchronized AAA getInstance(){
if(instance==null){
instance = new AAA();
}
return instance;
}
3 Double Check Lock(双重锁机制,线程安全,延迟实例化,效率高)
private static volatile AAA instance;
public static AAA getInstance(){
if(instance == null){
synchronized (AAA.class){
if (instance ==null){
instance = new AAA();
}
}
}
return instance;
}
关于此方式中的volatile作用
(1)禁止指令重排序
主要是因为
instance = new AAA();不是一个原子操作
下面这个链接清楚的解释了指令重排序的问题。
https://www.jianshu.com/p/1c72a061b40e
(2)保证可见性
线程A在自己工作线程中创建了实例,但还未同步到主存中,线程B判断主存中instance还是null,那么线程B又将在自己工作线程中创建一个实例,这样就会创建多个实例。
4 静态内部类(线程安全,延迟实例化,效率高)
private static class BBB{
private static final AAA aaa = new AAA();
}
public static AAA getInstance(){
return BBB.aaa;
}
静态内部类的加载方式:
内部静态类不会自动初始化,只有调用静态内部类的方法,静态域,或者构造方法的时候才会加载静态内部类。
5、枚举(线程安全,调用效率高,不能延时加载,可以天然的防止反射和反序列化调用)
举个栗子:一旦你实现了serializable接口,他们就不再是单例的了,因为readObject()方法总是返回一个 新的实例对象,就像java中的构造器一样。
public enum BBC { //枚举元素本身就是单例 INSTANCE; private BBC() { } //添加自己需要的操作 public void singletonOperation(){ } }
/** * 使用方法 */ boolean bl = BBC.INSTANCE.singletonOperation();
枚举完成的单例有一下几个优点:
1,线程安全
2,*序列化
3,即使使用反射机制也无法多次实例化一个枚举量