在Effective Java一书中提到double-check模式,并指出该模式在java中通常并不适用。该模式的结构如下
public Resource getResource(){ if(resource==null){ synchronized(this){ if(resource==null){ resource = new Resource(); } } } return resource; }
该模式是对下面代码的改进
public synchonized Resource getResource(){ if(resource == null){ resource = new Resource(); } return resource; }
为什么要有这个改进呢?首先第二段代码是对resource延迟初始化,等到第一次调用getResource()方法时才初始化。但是以后每次调用此方法都需要同步,而其实这个对象只会初始化一次。于是有了上面的改进
在java中double-check模式无效的原因是不同步情况下引用类型不是线程安全的。不过对于除了long和double的基本类型,double-check模式是使用的。
但是java的内存模式是不断改进的。Doug Lea在它的文章中写道“根据最新的JSR133的java内存模型,如果将引用类型声明为volatile,double-check模式就可以工作了”
如下
private volatile Resource resource; public Resource getResource(){ if (resource == null){ synchronized(this){ if (resource==null){ resource = new Resource(); } } } return resource; }
想起写过的一段代码异曲同工,有一个synchronized void start()方法,内部逻辑只走一次。有一个isStarted变量用于判断start()逻辑是否走过,代码如下
if(!isStarted){ synchronized void start(){ if(!isStarted){ 逻辑实现 isStarted = true; } } };