双重检测锁的缺陷

双重检测锁实现的单例模式看起来非常完美,实则会出现同步问题。

public MyObject{
    private static MyObect instance;
    private Date d = new Data();
    public Data getD(){return this.d;}
    public static MyObect getInstance(){
        if(instance == null){
            synchronized(MyObect .class){ // 1
                if(instance == null) // 2
                    instance = new MyObject(); // 3
            }
        }
        return instance;
    }
}

1处会将线程进行同步。

2处会再次检查是否已经被其他线程实例化。

3处会出现JVM内存模型允许所谓的无序写入,如下

1: mem = allocate();        //Allocate memory for Singleton object.
2: instance = mem;          //Note that instance is now non-null, but
                         //has not been initialized.
3: ctorSingleton(instance); //Invoke constructor for Singleton passing

在2之后 instance 给了一个空白空间 mem,已经不为空。
因为此时线程未离开 synchronized 块,所有 instance 所有的数据都未初始化且未同步。

当线程1离开 synchronized 块,如果由于线程间可见性问题可能导致其他线程 获取的 instance对象对应的 mem空间可能是 线程1未写回的空白空间,这时访问 getD()为空
这便是同步缺陷。

也可以使用贪婪方式,直接在类加载时初始化instance。

public MyObject{
    private static MyObect instance = new MyObject();
    private Date d = new Data();
    public Data getD(){return this.d;}
    public static getInstance(){
        return instance;
    }
}

Lazy-init的同步实现其实可以让jvm去实现。如下

public MyObject{

    private static class InstanceHoder{ //内部私有的类。
        static MyObject instance = new MyObject();
    }
    private Date d = new Data();
    public Data getD(){return this.d;}
    public static MyObect getInstance(){
           return InstanceHoder.instance;
    }
}

InstanceHoder内部类只有在使用到时候才会加载。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 错误的双重检查锁 在Java多线程的程序中,为了降低初始化类和创建对象的开销,经常会使用延迟初始化的方式,延迟初始...
    WeiAzure阅读 466评论 0 0
  • 双重锁的由来 单例模式中,有一个DCL(双重锁)的实现方式。在Java程序中,有时候可能需要推迟一些高开销的对象初...
    小愚笨阅读 832评论 0 0
  • 定义:整个系统只允许存在一个实例首先 我们一般都这样 但这样在多线程时会存在问题多个线程同时运行到if (inst...
    桑榆非晚95阅读 860评论 0 3
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,767评论 18 399
  • 在Java多线程程序中,有时候需要采用延迟初始化来降低初始化类和创建对象的开销。双重检查锁定是常见的延迟初始化技术...
    ycyoes阅读 452评论 0 0