【问题标题】:Is synchronized volatile boolean equal to atomicBoolean?同步的 volatile 布尔值是否等于 atomicBoolean?
【发布时间】:2013-06-13 17:50:50
【问题描述】:

当我们只对变量执行读取操作时,应该使用 Volatile,因为一个线程更新的值将对另一个线程可见,即使前一个线程失去 CPU 并退出同步块。那是对的吗?当需要使用原子行为时,将使用原子原语。例如 -

if (volatileBoolean) {
    volatileBoolean = !volatileBoolean;
}

假设 volatileBoolean 的值为真。一个线程检查 volatileBoolean 为真并进入 if 块,第二个线程看到 volatileBoolean 的值为真,也进入 if 块。现在,让我们假设第一个线程将错误值(!volatileBoolean)分配给 volatileBoolean 变量并失去 CPU,因此退出 if 块。第二个线程将 volatileBoolean 视为 false,将其分配回 true。

在这种情况下应该使用 AtomicBoolean 吗?如果是,为什么不能使用同步来处理?

synchronized(this){
        if (volatileBoolean) {
            volatileBoolean = !volatileBoolean;
        }
}

【问题讨论】:

    标签: java volatile atomicboolean


    【解决方案1】:

    在这种情况下应该使用 AtomicBoolean 吗?

    是的。

    如果是,为什么不能使用同步来处理?

    它在功能上是等价的,但是 AtomicBoolean 不使用锁,在适度的争用下可以更有效。请参阅此other question - 它着眼于 AtomicInteger,但结论也直接适用于 AromicBoolean。

    【讨论】:

      【解决方案2】:

      是的,这就是您想要使用 AtomicBoolean 的情况。这是实现您提到的那种同步(而不是自己做)的一种非常好的和安全的方法,而且速度要快得多。另请参阅 this link 与使用 volatile boolean 作为替代方法的比较。

      【讨论】:

        【解决方案3】:

        当我们只对变量执行读取操作时,应该使用 Volatile,因为一个线程更新的值将对另一个线程可见,即使前一个线程失去 CPU 并退出同步块。对吗?

        • volatile 与同步块没有任何依赖关系。 volatile 变量不被线程缓存。因此,一个线程的更改将对其他线程可见。
        • 因此,当对变量的写入/更新由单线程完成时,可以使用 volatile 变量,并且更新需要立即对访问该变量的所有其他线程可见。 volatile 仅确保可见性而非原子性。

        在这种情况下应该使用 AtomicBoolean 吗?如果是,为什么不能使用同步来处理?

        • 是的,如果您使用同步块,我们不需要在内部使用 volatile 变量,因为同步块将确保共享数据的可见性和原子性。在大多数当前处理器架构上,易失性读取的成本略高于非易失性读取。

        关于 AtomicBoolean

        AtomicBoolean 在内部使用 volatile int 和 CAS 操作来提供可见性和原子性。

        AtomicBoolean.java

        public class AtomicBoolean implements java.io.Serializable {
          
          private volatile int value;
        
           /**
            * Creates a new {@code AtomicBoolean} with the given initial value.
            *
            * @param initialValue the initial value
            */
           public AtomicBoolean(boolean initialValue) {
               value = initialValue ? 1 : 0;
           }
        

        来自 Java Concurrency In Practice 一书,关于 volatile 变量。

        Java 语言还提供了另一种较弱的同步形式,即 volatile 变量,以确保 对变量的更新可预测地传播到其他线程。当一个字段被声明为 volatile 时,编译器和 运行时注意这个变量是共享的,对它的操作不应该与其他变量重新排序 内存操作。 只有在简化同步策略的实施和验证时才使用 volatile 变量;避免使用 验证正确性时的 volatile 变量需要对可见性进行微妙的推理。 volatile 的良好用途 变量包括确保他们自己的状态的可见性,他们引用的对象的可见性,或者表明一个 发生了重要的生命周期事件(例如初始化或关闭)。

        【讨论】:

          【解决方案4】:

          AtomicBoolean 和任何 AtomicSomething 都是使用 volatile 实现的。唯一的区别是那些 AtomicSomething 包含一些没有同步关键字的同步方法,例如 compareAndSet 或lazySet。所以你可能应该在你的情况下使用 AtomicBoolean 。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2020-10-11
            • 2014-12-13
            • 1970-01-01
            • 1970-01-01
            • 2014-06-26
            • 1970-01-01
            • 2011-08-30
            • 2014-12-05
            相关资源
            最近更新 更多