欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

单例模式的一些认识

程序员文章站 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,即使使用反射机制也无法多次实例化一个枚举量