java - AtomicBoolean 可以替换 volatile boolean 吗?

标签 java concurrency

给出以下代码,其中我在运行某些代码之前检查 boolean 值 isInitialised。如果不是
private static volatile boolean isInitialised;,我用
private static final AtomicBoolean isInitialised = new AtomicBoolean(false);,
它应该实现相同的结果,甚至性能差异可以忽略不计?

public class DclSingleton {

    private static volatile boolean isInitialised;
    //private static final AtomicBoolean isInitialised = new AtomicBoolean(false);

    public static void doInit() {
        if (!isInitialised) {
            synchronized (DclSingleton.class) {
                if (!isInitialised) {
                    // do init
                    
                    isInitialised = true;
                }
            }
        }
    }

}

如果我使用 AtomicBoolean,下面的代码会达到同样的效果吗?

public class DclSingleton {

    // private static volatile boolean isInitialised;
    private static final AtomicBoolean isInitialised = new AtomicBoolean(false);

    public static void doInit() {
        if (isInitialised.compareAndSet(false, true)) {
            // do init            
        }
    }

}

最佳答案

您的两个示例之间有两个重要区别。

首先,很明显:第一个示例中的 doInit() 方法仅设置 isInitialized=true after 初始化单例。但是,在您的第二个示例中,它将 AtomicBoolean 实例设置为 true before 它初始化单例。如果第二个线程在设置标志之后但在初始化完成之前获得对单例的引用,则可能会出现问题。

第二个问题不太明显:在你的第二个例子中设置标志后没有同步。在初始化代码和其他线程中发生的任何事情之间没有建立发生在之间的关系。在您的第一个示例中,初始化发生在 isInitialized=true 之前,并且isInitialized=true 发生在 任何其他线程之前测试 if(!isInitialized)...

在你的第二个例子中,如果两个线程同时调用doInit(),Atomic操作确保只有其中一个可以进入初始化代码。但是,即使获胜者(纯属偶然)实际上在*另一个线程开始使用单例对象之前完成了初始化代码,在执行初始化的第一个线程和执行初始化的第一个线程之间仍然没有正式的先于关系第二个线程访问单例。


* 实时“之前”(又名挂钟时间)。如果某个事件 A 实际上实时发生在事件 B 之前,但是两个事件之间没有正式的发生在关系,那么其他线程可能会看到这两个事件的影响好像它们以不同的顺序发生。

关于java - AtomicBoolean 可以替换 volatile boolean 吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69806119/

相关文章:

java - Spring @Transactional 并发

java - jackson 的嵌套映射

java - MySQL连接和hibernate c3p0设置,8小时后超时?

java - 如何在 Java 中克隆 URI

java - Map<String, List> 或 List<List> 的 Hibernate 注释

java - 我是否必须同步访问 Java 中封装的线程安全数据结构?

java - 给定一个数组,请判断它是否包含三个总和等于0的数字

java - 为什么 Cache.asMap() 与 Cache.size() 不一致?

asp.net-mvc - 带有并发检查的 ASP.NET MVC + Entity Framework

java - 如何修改类设计以使其线程安全