java - 以下java代码线程安全没有volatile吗?
问题描述
public static Singleton singleton;
public static Singleton get(){
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
return singleton;
}
有人说singleton
变量没有 volatile 是错误的。但我认为这是创建单例对象的正确代码。我想知道这段代码是否具有线程安全性?
解决方案
正如anatolyg指出的那样,您应该将该字段singleton
设为私有,以避免对该字段进行不必要的非线程安全访问。
此外,即使在:
public static Singleton get(){
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
return singleton;
}
在块return singleton;
之外,这段代码仍然是线程安全的,因为剩余的代码在块内,因此,该块内的所有线程都将强制发生之前的关系(即,如果线程无法返回 null实例已正确设置)。synchronized
synchronized
话虽如此,请注意:引用Holger
只要对单例的实际写入发生在同步块开始之前,一切正常。它之所以有效,是因为最多只有一次 write,肯定是在返回之前执行的。如果可以进行更多写入,则它们可能会同时发生在同步块之外的 return 语句中。
有一个完整的SO Thread解决了为什么离开块return singleton
外部是线程安全的synchronized
。
尽管如此,我与其他用户(例如这个用户)有着相同的看法
由于返回不占用任何 CPU 或任何东西,因此没有理由不应该在同步块内。如果是,那么如果我们在此处的 Singleton 类中,则可以将该方法标记为同步。如果单例在其他地方被修改,这会更干净更好。
话虽如此,您不需要volatile子句,因为您正在同步变量的初始化singleton
。在这种情况下,该synchronized
子句不仅保证多个线程不会访问:
if (singleton == null) {
singleton = new Singleton();
}
singleton
而且每个线程都可以看到该字段的最新参考。因此,不会发生多个线程将不同对象实例分配给该字段的竞争条件。singleton
有人说单例变量没有 volatile 是错误的。
可能这个人将您的代码误认为是双重检查锁定模式,这是对您展示的版本的性能优化。在您的版本中,线程将在每次调用方法时进行同步get
,这在变量正确初始化后就没有必要了。singleton
这是双重检查锁定模式试图避免的开销。为了实现需要volatile (您可以阅读有关此SO Thread的深入解释),可以在此处找到有关此双重检查锁定模式的更多信息。
推荐阅读
- sql - 没有声明语句的 SQL 代码中的前值利用
- python - 模板提供了错误的媒体目录路径,Django 找不到图像
- performance - 鉴于它仅在 1 和 0 上运行,如何提高用 Java 构建的元胞自动机算法的性能?
- java - 从整数中获取二维数组位置
- javascript - 反应 useReducer 不更新状态
- .net-core - 生成了 UserID 子声明,但从 Identity Server 4 令牌中消失,导致 UserManager.GetUser 失败
- java - 尝试在测试用例中计算字符串中的元音时得到错误的输出
- python-3.x - Python 3 - 如果目标文件夹中不存在文件,则复制文件
- r - rmd 重新运行 read_csv 的所有块
- javascript - 如何选择 div 并从选定的 div 中仅获取唯一 ID?角