private volatile static Singleton uniqueInstance
在单独使用双锁方法进行同步时,为什么单个实例声明为volatile?我可以在不将其声明为易失性的情况下实现相同的功能吗?
答案 0 :(得分:49)
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
之前完成,从而防止上述重新排序情况。
答案 1 :(得分:24)
没有volatile
,代码无法正常使用多个线程。
来自维基百科的Double-checked locking:
从J2SE 5.0开始,此问题已得到修复。 volatile关键字现在确保多个线程正确处理单例实例。 The "Double-Checked Locking is Broken" Declaration:
中描述了这个新的习语
// 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...
}
一般情况下,如果可能的话,应该避免重复检查锁定,因为很难做到正确,如果你弄错了,很难找到错误。请尝试这种更简单的方法:
如果辅助对象是静态的(每个类加载器一个),则另一种选择是initialization on demand holder idiom
// 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;
}
}
答案 2 :(得分:11)
为避免使用双重锁定或易失性,请使用以下
enum Singleton {
INSTANCE;
}
创建实例很简单,延迟加载和线程安全。
答案 3 :(得分:0)
在任何读取操作之前写入易失性字段。 以下是更好理解的示例代码:
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
答案 4 :(得分:-1)
您可以使用以下代码:
private static Singleton uniqueInstance;
public static synchronized Singleton getInstance(){
if(uniqueInstance == null){
uniqueInstance = new Singleton();
}
return uniqueInstance
}