【多线程】多线程下的七种单例模式

一、饿汉式

此方式的关键在于instance作为类变量并且直接得到了初始化

public class SingletonObject1 {
    private static final SingletonObject1 instance=new SingletonObject1();
    public static SingletonObject1 getInstance(){
        return instance;
    }
}

缺点: 不能懒加载(占用内存)

二、懒汉式

懒汉式就是使用类实例的时候再去创建,避免出现类在初始化的时候提前创建

public class SingletonObject2 {
    // 定义实例,但不进行初始化
    private static SingletonObject2 intance;
    public static SingletonObject2 getInstance(){
        if (null==intance){
            intance= new SingletonObject2();
        }
        return SingletonObject2.intance;
    }
}

缺点: 懒汉式可以保证实例的懒加载,但是无法保证实例的唯一性。

三、懒汉式+同步方法

在多线程的情况下,多个线程同时访问instance(共享资源)需要保证数据的一致性,增加同步的约束。

public class SingletonObject3 {
    // 定义实例,但不进行初始化
    private static SingletonObject3 intance;
    // 向getInstance方法加入同步控制,每次只能有一个线程能够进入
    public synchronized static SingletonObject3 getInstance(){
        if (null==intance){
            intance= new SingletonObject3();
        }
        return SingletonObject3.intance;
    }
}

缺点:尽管synchornized已经进行了优化,但是此关键字依旧导致getInstance方法只能在同一时刻被一个线程访问,降低了性能。

四、Double-Check

此种方式提供了一种高效的数据同步策略,就是首次初始化时加锁。

public class SingletonObject6 {
    // 定义实例,但不进行初始化
    private static SingletonObject6 instance;
    
    public static SingletonObject6 getInstance(){
        // 当instance为null的时候,进入代码块,同时判读那避免每次都需要进入同步代码块,可以提高效率
        if (null==instance){
            synchronized (SingletonObject6.class){
                // 判断instance是否被创建
                if(null==instance){
                    instance=new SingletonObject6();
                }
            }
        }
        return SingletonObject6.instance;
    }
}

缺点:在多线程的情况下可能会引起空指针异常

五、volatile+Double-Check

加入volatile关键字防止jvm在运行时指令重排序

public class SingletonObject5 {
   // 定义实例,但不进行初始化,加volatile使其对象可见
    private volatile static SingletonObject5 instance;
   
    public static SingletonObject5 getInstance(){
        // 当instance为null的时候,进入代码块,同时判读那避免每次都需要进入同步代码块,可以提高效率
        if (null==instance){
            synchronized (SingletonObject5.class){
                // 判断instance是否被创建
                if(null==instance){
                    instance=new SingletonObject5();
                }
            }
        }
        return SingletonObject5.instance;
    }
}

六、静态内部类的方式

借助类加载的特点,对单例进行重构。在Singleton类中没有instance的静态成员,而是将其放到了静态内部类中,以保证在Singleton类初始化过程中不会创建Singleton的实例,在静态内部类中定了singleton的静态变量,并且直接进行了初始化。

public class SingletonObject3 {
    // 在静态内部类中吃有Singleton的实例,并且可以被直接初始化
    private static class InstanceHolder{
        private static SingletonObject3 instance=new SingletonObject3();
    }
    // 调用getInstance方法,事实上是获得静态内部类的instance静态属性
    public static SingletonObject3 getInstance(){
        return InstanceHolder.instance;
    }
 }

七、枚举的方式

推荐使用的一种方式,枚举类型不允许被继承,同样是线程安全的且只能被实例化一次,但是枚举类型不能进行懒加载,对Singleton主动使用。

public class SingletonObject4 {
    // 枚举本身就是final的,不允许被继承
    private enum EnumSingleton{
        // 实例变量
        INSTSNCE;
        private SingletonObject4 instance;

        EnumSingleton(){
            this.instance=new SingletonObject4();
        }

        public SingletonObject4 getInstance(){
            return instance;
        }
    }
    public static SingletonObject4 getInstance(){
        return EnumSingleton.INSTSNCE.getInstance();
    }
  }

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章