什么时候最好在Java中使用volatile布尔值而不是AtomicBoolean?
我已经看过SO中的其他volatile和Atomicxxxx问题(包括这个 ),并且已经阅读了java.util.current.atomic的描述,对这些细微之处我还不太满意。
如果我试图决定使用volatile boolean
和AtomicBoolean
,是否有除AtomicBoolean提供的primefaces读取 – 修改 – 写入操作之间的实际差异? (比如compareAndSet()
和getAndSet()
)
假设我有
volatile boolean flag;
然后一个或多个线程设置标志(但不清除它)。 如果我有一个线程读取标志,如果设置,做一个动作,然后清除标志,是不是足够的?
AtomicBoolean的成本比volatile boolean更高
- 内存空间
- 性能命中(
volatile boolean
似乎需要内存屏蔽,AtomicBoolean
似乎需要内存屏蔽+根据java.util.current.atomic描述对CAS操作进行一些次要locking)
我的直觉是和AtomicBoolean一起去,并且是安全的,但我想知道是否有使用volatile boolean
的情况(例如,如果我有成千上万的实例,性能是一个问题)。
基本上所有的AtomicBoolean
都是一个对象中的一个volatile boolean
。
每个对象会有一个小的开销。 可能微不足道,但可能更多的内存进入caching。
如果你需要使用AtomicBooleanFieldUpdater
那么会有相当多的性能开销。如果你不打算经常这样做(如NIO所附)。
从实际的angular度来看, AtomicBoolean
和volatile
之间的主要区别在于,比较和设置操作不是primefaces的,而且是volatile
variables。
volatile boolean b; void foo() { if( b ) { //Here another thread might have already changed the value of b to false b = false; } }
但是看到所有的并发写入都是幂等的,而且只能从一个线程读取,这不应该是一个问题。
我不确定我是否完全同意这里的其他答案。 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需要设置其他状态,则顺序也变得非常重要。
在简单的情况下,是的,你很好,但如果它变得比简单的标志轻弹更复杂,那么这变得更难以推理。
这里有很多很好的信息。 但是,我会添加另一个可能有用的区别。 你可以有一个AtomicBooleans数组,但你不能(据我所知)有一个可变的布尔值数组。
然后一个或多个线程设置标志(但不清除它)。 如果我有一个线程读取标志,如果设置,做一个动作,然后清除标志,是不是足够的?
是的,如果你不需要AtomicBoolean的特殊function,那么使用volatile就可以了。 事实上,这是挥发性的less数合理用途之一。