Volatile应该在我们只对变量做读操作时使用,因为一个线程更新的值对另一个线程是可见的,即使前一个线程失去CPU并退出同步块。对吗?当需要使用原子行为时,将使用原子原语。例如-
if (volatileBoolean) {
volatileBoolean = !volatileBoolean;
}
假设volatileBoolean值为true。一个线程检查volatileBoolean为true并进入if块,第二个线程看到volatileBoolean的值为true,也进入if块。现在,让我们假设第一个线程将false值(!volatileBoolean)赋给volatileBoolean变量并丢失CPU,因此退出if块。第二个线程看到挥发布尔值为false,将其赋值回true。
这是AtomicBoolean应该使用的情况吗?如果是,为什么不能使用synchronized来处理?
synchronized(this){
if (volatileBoolean) {
volatileBoolean = !volatileBoolean;
}
}
这是AtomicBoolean应该使用的情况吗?
是的。
如果是,为什么不能使用synchronized来处理?
在功能上是等价的,但是AtomicBoolean不使用锁,这样在适度的争用下效率会更高。看另一个问题——它看的是AtomicInteger,但结论也直接适用于AromicBoolean。
是的,这就是您想要使用AtomicBoolean的情况。这是实现你提到的那种同步的一种非常好的和安全的方式(而不是自己做),而且它要快得多。
Volatile应该在我们只对变量做读操作时使用,因为一个线程更新的值对另一个线程是可见的,即使前一个线程失去CPU并退出同步块。对吗?
- volatile与synchronized块没有任何依赖关系。Volatile变量不是由线程缓存的。因此,一个线程的更改将对其他线程可见。
- 所以volatile变量可以在单线程写/更新变量时使用,并且更新需要对访问该变量的所有其他线程立即可见。volatile只保证可见性而不是原子性。
这是AtomicBoolean应该使用的情况吗?如果是,为什么不能使用synchronized来处理?
- 如果你使用同步块,我们不需要在内部使用volatile变量,因为同步块将确保共享数据的可见性和原子性。在大多数当前的处理器架构中,易失性读取比非易失性读取稍微昂贵一些。
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变量的正确性时,需要对可见性进行微妙的推理。挥发物的良好用途变量包括确保它们自己的状态、它们所引用的对象的状态的可见性,或者指示一个变量已发生重要的生命周期事件(如初始化或关机)。
AtomicBoolean和任何AtomicSomething只是使用volatile实现的。唯一的区别是,那些AtomicSomething包含一些方法来做同步没有synchronized关键字,如compareAndSet或lazySet。在这种情况下,你应该使用AtomicBoolean。