是否有必要让 `AtomicBoolean` 也成为 `volatile`?

Is it necessary to make `AtomicBoolean` also `volatile`?

我的理解:声明一个变量 volatile 可以保证 可见性 其他线程对该变量的写入。本质上,每个 write 到 volatile 变量 发生在 之后的 reads.

我理解 AtomicBoolean.compareAndSet() 的原子性,以及它如何提供 read+write 操作的原子性,而 volatile 没有。但是我没有看到任何文档通过 AtomicBoolean 提供 visibility 保证,如下所示:

  1. AtomicBoolean.compareAndSet() 的每个成功 write 最终都将对其他线程的后续 AtomicBoolean.get()AtomicBoolean.compareAndSet() 可见。

但是,我一直看到标记为 thread-safe 的代码是这样的,

// default false so that first-thread that execute() can enter the logic block
private static final  AtomicBoolean executing = new AtomicBoolean(false);


public void execute() {
    if (executing.compareAndSet(false, true)) {  // check if the executing is previously false and if so update it to true
        try {
            // thead-safe code, i.e only one thread guaranteed to execute at any point of time time
        } finally {
            executing.set(false); // executing thread now re-sets the test value
        }
    }
}

变量 executing 不应该像 private static volatile AtomicBoolean executing = new AtomicBoolean(false); 一样声明为 volatile 吗?那么AtomicBoolean需要的可见性保证就实现了吗?

我们不能使用下面的代码

private static volatile final AtomicBoolean executing = new AtomicBoolean(false);

volatile 和 final 一起使用是无效的。正如@RealSkeptic 所述,永远不会改变(最终)的 var 不需要具有 volatile。 Volatile 用于那些其值在运行时被一个或多个线程更改的变量。

//快乐学习

Is it necessary to make AtomicBoolean also volatile?

没有

在示例中,executing 被声明为 static final,因此它将在 class 初始化时被初始化一次,并安全地发布到任何其他需要它的代码。

这种行为是有保证的,因为在 classes 初始化完成(通常)和随后使用由class。该变量也是 final 的事实排除了对静态变量的任何后续赋值,这些赋值会否定 happens-before.

如果某些东西可以在初始化后为其分配新值,则只需将 executing 声明为 volatile。如果不做一些令人讨厌的反思,这是不可能的。 (并且 JLS 指出,如果您做那种事情来更改 final,则内存模型保证不适用。)


如果 executingfinal 但实例字段而不是 static 字段,您会得到类似的效果。推理略有不同,但在 JLS 中也明确提到。


最后,Java 语法不允许您组合使用 volatilefinal 修饰符。这种组合没有意义。