private volatile static Singleton uniqueInstance
在单例模式中,使用双重锁定方法进行同步时,为什么需要将单个实例声明为volatile?如果不声明为volatile是否可以实现相同的功能?
private volatile static Singleton uniqueInstance
在单例模式中,使用双重锁定方法进行同步时,为什么需要将单个实例声明为volatile?如果不声明为volatile是否可以实现相同的功能?
volatile
关键字可以防止内存写入被重新排序,这样其他线程就不可能通过单例的指针读取未初始化的字段。
考虑这种情况:线程A发现uniqueInstance == null
,锁定并确认它仍然是null
,然后调用单例的构造函数。构造函数将在Singleton内部的成员XYZ
中进行写操作,然后返回。现在,线程A将对新创建的单例的引用写入uniqueInstance
,并准备释放锁。
就在线程A准备释放锁的时候,线程B出现了,并发现uniqueInstance
不为null
。线程B访问uniqueInstance.XYZ
,认为已经被初始化,但由于CPU已经重新排序写操作,因此线程A写入XYZ
中的数据还没有对线程B可见。因此,线程B看到的XYZ
中的值是错误的。
当你使用volatile
标记uniqueInstance
时,会插入一个内存屏障。在修改uniqueInstance
之前启动的所有写操作都将完成,从而防止上述重新排序的情况。
uniqueInstance
,2)XYZ
得到了有意义的内容。 - lcninstance = new Instance()
,而是应该先定义一个本地变量 tmp = new Instance()
,然后再进行检查,最后再将其赋值给 instance
。可以参考 Mark 在被采纳的答案中的代码。 - Sergey Kalinichenko没有使用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;
}
}
synchronized
块不是确保检索非缓存字段的值吗?这意味着 volatile
部分不再需要了吗?即使今天,这仍然是必需的吗? - android developerenum Singleton {
INSTANCE;
}
创建实例很简单,采用惰性加载方式并且是线程安全的。
对于volatile字段的写操作会发生在任何读操作之前。 以下是一个示例代码,以便更好地理解:
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
}