使用双锁时使单例实例易变的重点是什么?

private volatile static Singleton uniqueInstance 

在单独使用双锁方法进行同步时,为什么单个实例声明为volatile? 我可以在不将其声明为volatile的情况下实现相同的function吗?

没有volatile ,代码无法正常使用多个线程。

来自维基百科的双重锁定 :

从J2SE 5.0开始,此问题已得到修复。 volatile关键字现在可确保多个线程正确处理单例实例。 这个新的成语在“双重锁定已破损”声明中有所描述:

 // Works with acquire/release semantics for volatile // Broken under Java 1.4 and earlier semantics for volatile class Foo { private volatile Helper helper = null; public Helper getHelper() { Helper result = helper; if (result == null) { synchronized(this) { result = helper; if (result == null) { helper = result = new Helper(); } } } return result; } // other functions and members... } 

一般来说,如果可能的话,你应该避免重复检查锁定,因为很难做到正确,如果你弄错了,很难找到错误。 请尝试这种更简单的方法:

如果辅助对象是静态的(每个类加载器一个),则另一种选择是按需初始化持有者习惯用法

 // Correct lazy initialization in Java @ThreadSafe class Foo { private static class HelperHolder { public static Helper helper = new Helper(); } public static Helper getHelper() { return HelperHolder.helper; } } 

volatile阻止内存写入被重新排序,这使得其他线程无法通过单例指针读取单例的未初始化字段。

考虑这种情况:线程A发现uniqueInstance == null ,锁定,确认它仍为null ,并调用singleton的构造函数。 构造函数在Singleton中写入成员XYZ ,然后返回。 线程A现在将对新创建的单例的引用写入uniqueInstance ,并准备释放其锁定。

正如线程A准备释放其锁定一样,线程B出现,并发现uniqueInstance不为null 。 线程B访问uniqueInstance.XYZ认为它已被初始化,但由于CPU已重新排序写入,线程A写入XYZ的数据尚未对线程B可见。因此,线程B在XYZ内部看到不正确的值,这是错的。

标记uniqueInstance volatile时,会插入内存屏障 。 在uniqueInstance之前启动的所有写入将在uniqueInstance被修改之前完成,从而防止上述重新排序情况。

为避免使用双重锁定或易失性我使用以下

 enum Singleton { INSTANCE; } 

创建实例很简单,延迟加载和线程安全。

写入易失性字段将在任何读取操作之前发生。 以下是更好理解的示例代码:

 private static volatile ResourceService resourceInstance; //lazy Initialiaztion public static ResourceService getInstance () { if (resourceInstance == null) { // first check synchronized(ResourceService.class) { if (resourceInstance == null) { // double check // creating instance of ResourceService for only one time resourceInstance = new ResourceService (); } } } return resourceInstance; } 

这个链接可以更好地为您服务http://javarevisited.blogspot.com/2011/06/volatile-keyword-java-example-tutorial.html

您可以使用以下代码:

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