java - 下面的 java 代码在没有 volatile 的情况下是线程安全的吗?

标签 java multithreading parallel-processing synchronization volatile

public static Singleton singleton;

public static Singleton get(){
    synchronized (Singleton.class) {  
        if (singleton == null) {  
            singleton = new Singleton();  
        }  
    } 
    return singleton;
}

有人说 singleton 变量没有 volatile 是错误的。但我认为这是创建单例对象的正确代码。我想知道这段代码是否有线程安全?

最佳答案

作为anatolyg指出,您应该将字段 singleton 设为私有(private),以避免对该字段进行不必要的非线程安全访问。

此外,即使在:

public static Singleton get(){
    synchronized (Singleton.class) {  
        if (singleton == null) {  
            singleton = new Singleton();  
        }  
    } 
    return singleton;
} 

return singleton;synchronized block 之外,这段代码仍然是线程安全的 因为其余代码在 synchronized block ,因此,该 block 中的所有线程都将强制执行 happens-before 关系(即,如果实例已正确设置)。

话虽如此,但请注意:引用 Holger

As long as the actual write to singleton happens-before the beginning of the synchronized block, everything works. It only works because there is at most one write, definitely performed before the return. If more writes were possible, they could happen concurrently to the return statement that is outside the synchronized block.

有一个完整的SO Thread这解决了为什么将 return singleton 留在 synchronized block 之外是线程安全的。

尽管如此,我也同意其他用户的相同意见,例如 this one

since the return doesn't take any CPU or anything, there is no reason why it shouldn't be inside of the synchronized block. If it was then the method can be marked as synchronized if we are in the Singleton class here. This would be cleaner and better in case singleton gets modified elsewhere.

话虽如此,您不需要 volatile 子句,因为您正在同步变量 singleton 的初始化。在这种情况下,synchronized 子句不仅保证多个线程不会访问:

    if (singleton == null) {  
        singleton = new Singleton();  
    }  

而且每个线程都能看到 singleton 字段的最新引用。因此,不会发生多个线程将不同对象实例分配给单例字段的竞争条件

Some one say that no volatile for singleton variable is wrong.

可能此人将您的代码误认为是 double-checked locking pattern ,这是对您显示的版本的性能优化。在您的版本中,线程将在每次调用方法 get 时进行同步,这在变量 singleton 已正确初始化后没有必要。这是双重检查锁定模式试图避免的开销。要实现这一点,需要 volatile(您可以阅读关于此 SO Thread 的深入解释),可以找到有关此双重检查锁定模式的更多信息 here .

关于java - 下面的 java 代码在没有 volatile 的情况下是线程安全的吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66654063/

相关文章:

java - 使用流将多个 HashMap 的内容相加

asp.net - .Net MVC线程长时间运行的过程

java - AWS Lambda : return type String is not compatible with POJOClass

java - HTTP 错误 407 需要代理身份验证

java - Jar 不通过双击启动,而是从命令行启动

java - Java Boolean对象中的值赋值会导致内存重新分配吗

c++ - absl::Mutex 的条件临界区如何处理读者唤醒

c++ - 使用 CUDA 有效计算排序数组中元素发生变化的位置

c# - BlockingCollection with Parallel.For 挂起?

parallel-processing - 并行创建稀疏矩阵