我已经在SO中查看了其他volatile和Atomicxxxx问题(包括this one)并阅读了the description of java.util.current.atomic,我对细微差别不太满意。
如果我在尝试使用volatile boolean
和AtomicBoolean
之间做出决定,除了AtomicBoolean提供的原子读取 - 修改 - 写入操作之外,是否存在实际差异? (例如compareAndSet()
和getAndSet()
)
假设我有
volatile boolean flag;
然后一个或多个线程设置标志(但不清除它)。如果我有一个读取标志的线程,如果设置,执行操作,然后清除该标志,volatile
是否足够?
就
而言,AtomicBoolean的成本是否高于volatile布尔值volatile boolean
似乎需要内存防护,AtomicBoolean
似乎需要内存防护+根据java.util.current.atomic说明对CAS操作进行一些小锁定)我的直觉调用是使用AtomicBoolean并且是安全的,但我想了解是否有使用volatile boolean
的情况(例如,如果我有数千个实例并且性能是一个问题)
答案 0 :(得分:70)
从实际角度来看,AtomicBoolean
和volatile
之间的主要区别在于比较和设置操作与volatile
变量不是原子操作。
volatile boolean b;
void foo() {
if( b ) {
//Here another thread might have already changed the value of b to false
b = false;
}
}
但是看到所有并发写入都是幂等的并且您只从一个线程读取,这应该不是问题。
答案 1 :(得分:19)
我不确定我是否完全赞同其他答案; biziclop的回答是正确的,但我不确定除非我们知道更多细节,否则我们可以断定你是安全的。
在简单的情况下,交错可能如下所示:
Thread 1 (writer) Thread 2 (Writer) Thread 3 (Reader)
----------------- ----------------- -----------------
flag = true;
if (flag) {
flag = true;
flag = false;
doStuff();
这可能没什么问题(flag
到true
的第二组无关紧要,因为doStuff()
仍然可能会看到线程2需要做的事情。
但是,如果你逆转线程3的顺序:
Thread 1 (writer) Thread 2 (Writer) Thread 3 (Reader)
----------------- ----------------- -----------------
flag = true;
if (flag) {
doStuff();
flag = true;
flag = false;
然后线程2的更新可能会丢失。
当然,你需要同样小心线程2做的其他事情,以确保它对线程3是可见的。如果线程2需要设置其他状态,那么命令也很重要。
在简单的情况下,是的,你很好,但如果它变得比简单的标志轻弹更复杂,那么这就更难以推理。
答案 2 :(得分:17)
基本上所有AtomicBoolean
都是对象中的volatile boolean
。
每个对象的开销很小。可能无关紧要,但可能有更多内存进入缓存。
如果你需要使用AtomicBooleanFieldUpdater
,那么会有很多性能开销。如果你不经常这样做(如NIO中的attach
),那就没关系。
答案 3 :(得分:7)
这里有很多好消息。但是,我会添加另一个可能有用的差异。你可以有一个AtomicBooleans数组,但你不能(据我所知)有一系列挥发性布尔值。
答案 4 :(得分:2)
然后一个或多个线程设置标志 (但不清楚)。如果我有一个 读取标志的线程,如果 设置,执行操作,然后清除 国旗,是否充足?
是的,如果你不需要AtomicBoolean的特殊能力,那么使用volatile就可以了。实际上,这是volatile的少数合理用途之一。