是否有必要让 `AtomicBoolean` 也成为 `volatile`?
Is it necessary to make `AtomicBoolean` also `volatile`?
我的理解:声明一个变量 volatile
可以保证 可见性 其他线程对该变量的写入。本质上,每个 write
到 volatile 变量 发生在 之后的 reads
.
我理解 AtomicBoolean.compareAndSet()
的原子性,以及它如何提供 read+write
操作的原子性,而 volatile
没有。但是我没有看到任何文档通过 AtomicBoolean
提供 visibility 保证,如下所示:
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
,则内存模型保证不适用。)
如果 executing
是 final
但实例字段而不是 static
字段,您会得到类似的效果。推理略有不同,但在 JLS 中也明确提到。
最后,Java 语法不允许您组合使用 volatile
和 final
修饰符。这种组合没有意义。
我的理解:声明一个变量 volatile
可以保证 可见性 其他线程对该变量的写入。本质上,每个 write
到 volatile 变量 发生在 之后的 reads
.
我理解 AtomicBoolean.compareAndSet()
的原子性,以及它如何提供 read+write
操作的原子性,而 volatile
没有。但是我没有看到任何文档通过 AtomicBoolean
提供 visibility 保证,如下所示:
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
alsovolatile
?
没有
在示例中,executing
被声明为 static final
,因此它将在 class 初始化时被初始化一次,并安全地发布到任何其他需要它的代码。
这种行为是有保证的,因为在 classes 初始化完成(通常)和随后使用由class。该变量也是 final
的事实排除了对静态变量的任何后续赋值,这些赋值会否定 happens-before.
如果某些东西可以在初始化后为其分配新值,则只需将 executing
声明为 volatile
。如果不做一些令人讨厌的反思,这是不可能的。 (并且 JLS 指出,如果您做那种事情来更改 final
,则内存模型保证不适用。)
如果 executing
是 final
但实例字段而不是 static
字段,您会得到类似的效果。推理略有不同,但在 JLS 中也明确提到。
最后,Java 语法不允许您组合使用 volatile
和 final
修饰符。这种组合没有意义。