资讯详情

DCL单例模式

一、对象的创建过程

视频教程

创建->初始化->建立连接

1.先申请内存,赋值默认值0

2.构造方法赋值初始值,8

三、建立连接,t->T

二、DCL单例

public class Singleton {     private static Singleton instance = null;     public static Singleton getInstance() {         if(null == instance) {                    // line A             instance = new Singleton();        // line B         }          return instance;      } }

假设这样的场景:

并发调用两个线程Singleton.getInstance()假设线程先判断instance是否为null,即代码中line A进入到line B位置。判断后,JVM将CPU向线程二切换资源,

由于线程1尚未执行line B,所以instance还是空的,所以线程二执行了new Singleton()操作。过了一会儿,当线程再次被唤醒时,它仍然执行new Singleton()操作,

这样来了,new出了两个instance,这还能叫单例吗?

public class Singleton {     private static Singleton instance = null;     public synchronized static Singleton getInstance() {         if(null == instance) {             instance = new Singleton();         }          return instance;      } }

与第一段代码相比,方法中只有一个synchronized现在可以保证不会出线程问题。

但是这里有一个很大的性能问题(至少耗时很大)。

public class Singleton {     private static Singleton instance = null;     public  static Singleton getInstance() {         synchronized (Singleton.class) {             if(null == instance) {                 instance = new Singleton();             }         }          return instance;      } }

基本上,把synchronized移动到代码内部是没有意义的。每次调用getInstance()还是要进行同步。

同步本身没有问题,但我们只想第一次创建它instance例子同步,所以有以下写法——

public class Singleton {     private static Singleton instance = null;     public  static Singleton getInstance() {         if(null == instance) {    // 检测到线程二instance不为空             synchronized (Singleton.class) {                 if(null == instance) {                     instance = new Singleton();    // 线程一被指示重排,首先执行执行,但结构函数(即初始化未完成)尚未完成。                 }             }         }          return instance;    // 执行后面的线程2将导致对象尚未初始化错误      } }

除了第一次创建对象外,其他访问似乎已经满足了要求。if回来,所以不会走到同步块,完美吗?

如上代码段注释:假设线程一执行到instance = new Singleton()这句话在这里看起来像一句话,但实际上是编译后的JVM执行对应的会变代码发现,这句话被编译成8个汇编指令,大致做了三件事:

1)给instance实例分配内存;

2)初始化instance的构造器;

3)将instance对象指向分配的内存空间(注意到这步时instance就非null了)

。这样,当程序真正运行时,上述指令执行顺序可能是这样的:

a)给instance实例分配内存;

b)将instance对象指向分配的内存空间;

c)初始化instance的构造器;

此时,当线程一执行时b)完成,执行c)此时,它被切换到线程2instance判断为非空,线程二直接来retrn instance语句,拿走instance然后使用,接着就顺理成章地报错()。

  

  根据以上分析可知,

public class Singleton {
    private volatile static Singleton instance = null;
    public  static Singleton getInstance() {
        if(null == instance) {
            synchronized (Singleton.class) {
                if(null == instance) {
                    instance = new Singleton();
                }
            }
        }

        return instance;

    }
}

将变量instance使用volatile修饰即可实现单例模式的线程安全。

参考博客、视频教程

标签: dcl光伏电抗器三相功率电感器

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台