单例模式线程安全吗《十二》

单例模式线程安全吗?

单例模式作为一种常见的设计模式,在程序中非常常见,主要是为了保证一个类只有一个唯一的对象。

从简单的“饿汉式”、“懒汉式”→利用 synchronized 和 复杂的“双重校验DCL模式”,是一个考虑线程安全的过程
那么单例模式线程安全吗
1. 静态的饿汉式单例模式是线程安全的

那非静态的饿汉单例模式呢?
答案是:没有非静态的饿汉单例模式


// 线程安全

 public class EhanMonitor {


    private  static EhanMonitor ehanMonitor =new EhanMonitor();

    private  EhanMonitor (){

    }

    public  static  EhanMonitor getEhanMonitor(){
        return  ehanMonitor ;
    }

}
2. 在方法前面加synchronized的懒汉单例模式是线程安全的,但是效率低
 //线程安全
 
public class Singleton2 {

    private Singleton2(){

    }

    private static Singleton2 instance;

    public static synchronized Singleton2 getInstance(){
        if(instance == null) {//1
            instance = new Singleton2();//2
        }
        return instance;
    }

}
3. 双重校验DCL模式的懒汉单例模式不是线程安全的
//不是线程安全


public class Monitor {

    private  static   Monitor monitor =null ;

    private  Monitor(){}

    public static Monitor getMonitor(){
        if(monitor ==null){
            synchronized (Monitor.class){
                if(monitor ==null){
                    monitor =new Monitor();
                }
            }
        }
        return monitor ;
    }


因为下面的2,3步骤会重排序

mem = allocate();             //为单例对象分配内存空间.
instance = mem;               //注意,instance 引用现在是非空,但还未初始化
ctorSingleton(instance);    //为单例对象通过instance调用构造函数
 
4. 双重校验的volatile DCL模式是线程安全的

添加volatile 可以禁止2,3步骤的重排序

//线程安全


public class Monitor {

    private  static  volatile  Monitor monitor =null ;

    private  Monitor(){}

    public static Monitor getMonitor(){
        if(monitor ==null){
            synchronized (Monitor.class){
                if(monitor ==null){
                    monitor =new Monitor();
                }
            }
        }
        return monitor ;
    }

5. 静态内部类实现的单例模式是线程安全的
//线程安全


public class   ClassMonitor {
 private static class MonitorCreator {
        private static ClassMonitor classMonitor = new ClassMonitor();

    }

    private ClassMonitor() {
        System.out.println("构造方法初始化");
    }

    public static ClassMonitor getInstance() {
        System.out.println("静态内部类获取");
        return MonitorCreator.classMonitor;
    }

你可能感兴趣的:(设计模式,多线程示例)