private volatile static Singleton uniqueInstance
在使用双锁方法进行同步的单例中,为什么将单个实例声明为 volatile ?我可以在不将其声明为 volatile 的情况下实现相同的功能吗?
private volatile static Singleton uniqueInstance
在使用双锁方法进行同步的单例中,为什么将单个实例声明为 volatile ?我可以在不将其声明为 volatile 的情况下实现相同的功能吗?
这volatile
可以防止内存写入被重新排序,从而使其他线程无法通过单例的指针读取单例的未初始化字段。
考虑这种情况:线程 A 发现uniqueInstance == null
,锁定,确认它仍然是null
,并调用单例的构造函数。XYZ
构造函数对Singleton 内部的成员进行写入,然后返回。线程 A 现在将对新创建的单例的引用写入uniqueInstance
,并准备释放它的锁。
就在线程 A 准备释放它的锁时,线程 B 出现了,发现它uniqueInstance
不是null
. 线程B
访问uniqueInstance.XYZ
时以为自己已经初始化了,但是由于 CPU 对写入进行了重新排序,线程 A 写入的数据XYZ
并没有对线程 B 可见。因此,线程 B 在 内部看到了不正确的值XYZ
,这是错误的。
当您标记uniqueInstance
volatile 时,会插入一个内存屏障。之前启动的所有写入uniqueInstance
都将在uniqueInstance
修改之前完成,从而防止上述重新排序情况。
如果没有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;
}
}
为避免使用双重锁定或易失性,我使用以下
enum 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
}