繁体   English   中英

AtomicBoolean 可以替换 volatile 布尔值吗?

[英]Can AtomicBoolean replace volatile 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 但是,在您的第二个示例中,它初始化单例之前AtomicBoolean实例设置为true 如果第二个线程在设置标志之后但在初始化完成之前获得对单例的引用,这可能是一个问题。

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

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


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

是的,它可以。 可见性是保证。

AtomicBoolean 与 synchronized 类似,但由于 CPU 缓存的 compareAndSwap 实用程序,它被认为比同步更好。

小的区别是它不能确保同步时多个线程之间的执行顺序。

AtomicXxxx 封装了一个 volatile 所以它们基本相同,不同之处在于它提供了更高级别的操作,例如用于实现增量的 CompareAndSwap。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM