Pho*_*nix 33 java singleton volatile double-checked-locking thread-synchronization
private volatile static Singleton uniqueInstance
Run Code Online (Sandbox Code Playgroud)
在单独使用双锁方法进行同步时,为什么单个实例声明为volatile?我可以在不将其声明为volatile的情况下实现相同的功能吗?
das*_*ght 54
在volatile防止记忆被重新排序写道,使它不可能为其他线程通过单的指针读你单身的未初始化的领域.
考虑这种情况:线程A发现uniqueInstance == null锁定,确认它仍然存在null,并调用singleton的构造函数.构造函数XYZ在Singleton中写入成员,然后返回.线程A现在将对新创建的单例的引用写入uniqueInstance,并准备释放其锁.
正如线程A准备释放其锁定一样,线程B出现,并发现uniqueInstance不是null.线程B访问uniqueInstance.XYZ认为它已被初始化,但由于CPU已重新排序写入,线程A写入的数据XYZ尚未对线程B可见.因此,线程B内部看到不正确的值XYZ,这是错误的.
标记uniqueInstancevolatile时,会插入内存屏障.uniqueInstance在uniqueInstance修改之前启动的所有写入将在修改之前完成,从而防止上述重新排序情况.
Mar*_*ers 26
没有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...
}
Run Code Online (Sandbox Code Playgroud)
一般情况下,如果可能的话,应该避免重复检查锁定,因为很难做到正确,如果你弄错了,很难找到错误.请尝试这种更简单的方法:
如果辅助对象是静态的(每个类加载器一个),则另一种选择是按需定位器习惯用法初始化
// 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;
}
}
Run Code Online (Sandbox Code Playgroud)
Pet*_*rey 11
为避免使用双重锁定或易失性,我使用以下内容
enum Singleton {
INSTANCE;
}
Run Code Online (Sandbox Code Playgroud)
创建实例很简单,延迟加载和线程安全.
| 归档时间: |
|
| 查看次数: |
21487 次 |
| 最近记录: |