【发布时间】:2019-07-10 06:49:46
【问题描述】:
单例模式的代码:
class Singleton
{
private volatile static Singleton obj;
private Singleton() {}
public static Singleton getInstance()
{
if (obj == null)
{
synchronized (Singleton.class)
{
if (obj==null)
obj = new Singleton();
}
}
return obj;
}
}
上面代码中的obj被标记为Volatile,这意味着每当在代码中使用obj时,它总是从主内存中获取,而不是使用缓存的值。因此,每当需要执行if(obj==null) 时,它都会从主内存中获取 obj,尽管它的值是在上一次运行中设置的。这是使用 volatile 关键字的性能开销。我们如何避免它?
【问题讨论】:
-
如果不需要,请避免仔细检查。!
-
首先,您混淆了
volatile和synchronized块。两者都提供原子性(意味着一个线程所做的更改对其他人可见)但synchronized块还提供互斥,这意味着它不允许超过一个线程一次访问它。我的观点是volatile用于当你想要原子性但又不想互斥时。您可能不应该将两者结合使用,因为它违背了使用volatile关键字的目的。 -
我想他是想避免多线程发现obj为null的情况下的双重初始化。
-
要添加到@MushifAliNawaz,您可能想要的是
volatile而不是synchronized。从技术上讲,通过检查实现此getInstance()的唯一安全方法是使用synchronized块 - 如果您希望确保只调用一次构造函数。这就是你想在构建重量级时使用的模式,或者由于其他原因应该只发生一次。这也是正确的。但是,通常,出于其他原因,您想要一个该类型的对象 - 只要只使用一个,构造两个就可以了。然后跳过synchronized并使用volatile。 -
@MushifAliNawaz “两者都提供原子性” - 不,应该是“两者都提供可见性”,易失性变量不是原子的。还有“你可能不应该同时使用两者,因为它违背了使用 volatile 关键字的目的。” - 这就像说不要使用 DCL,这至少是不准确的。
标签: java design-patterns static singleton volatile