AtomicBoolean做了哪些volatile boolean不能做到的事情?
当前回答
AtomicBoolean有一些方法可以原子地执行复合操作,而不必使用同步块。另一方面,volatile布尔值只能在同步块中执行复合操作。
读取/写入volatile boolean的内存效果分别与AtomicBoolean的get和set方法相同。
例如,compareAndSet方法将自动执行以下操作(没有同步块):
if (value == expectedValue) {
value = newValue;
return true;
} else {
return false;
}
因此,compareAndSet方法将允许您编写保证只执行一次的代码,即使是从多个线程调用时也是如此。例如:
final AtomicBoolean isJobDone = new AtomicBoolean(false);
...
if (isJobDone.compareAndSet(false, true)) {
listener.notifyJobDone();
}
保证只通知侦听器一次(假设没有其他线程将AtomicBoolean设置为true后再次设置为false)。
其他回答
记住成语——
READ - MODIFY- WRITE这个你不能用volatile实现
AtomicBoolean有一些方法可以原子地执行复合操作,而不必使用同步块。另一方面,volatile布尔值只能在同步块中执行复合操作。
读取/写入volatile boolean的内存效果分别与AtomicBoolean的get和set方法相同。
例如,compareAndSet方法将自动执行以下操作(没有同步块):
if (value == expectedValue) {
value = newValue;
return true;
} else {
return false;
}
因此,compareAndSet方法将允许您编写保证只执行一次的代码,即使是从多个线程调用时也是如此。例如:
final AtomicBoolean isJobDone = new AtomicBoolean(false);
...
if (isJobDone.compareAndSet(false, true)) {
listener.notifyJobDone();
}
保证只通知侦听器一次(假设没有其他线程将AtomicBoolean设置为true后再次设置为false)。
Volatile boolean vs AtomicBoolean
Atomic*类包装了相同类型的volatile原语。来源:
public class AtomicLong extends Number implements java.io.Serializable {
...
private volatile long value;
...
public final long get() {
return value;
}
...
public final void set(long newValue) {
value = newValue;
}
如果你所做的只是获取和设置一个Atomic*,那么你也可以用一个volatile字段来代替。
AtomicBoolean做了哪些volatile boolean不能做到的事情?
原子类为您提供了提供更高级功能的方法,例如用于数字的incrementAndGet(),用于布尔值的compareAndSet(),以及其他实现多重操作(get/increment/set, test/set)而无需锁定的方法。这就是为什么Atomic*类如此强大。
例如,如果多个线程使用++使用下面的代码,就会出现竞争条件,因为++实际上是:get、increment和set。
private volatile value;
...
// race conditions here
value++;
然而,下面的代码将在多线程环境中安全工作,没有锁:
private final AtomicLong value = new AtomicLong();
...
value.incrementAndGet();
同样重要的是要注意,从对象的角度来看,使用Atomic*类包装volatile字段是封装关键共享资源的好方法。这意味着开发人员不能假设字段不共享就处理它,可能会在字段++中注入问题;或其他引入竞态条件的代码。
Volatile关键字保证共享该变量的线程之间的happens-before关系。它不能保证2个或更多的线程在访问布尔变量时不会相互中断。
你不能将compareAndSet, getAndSet作为带有volatile boolean的原子操作(除非你同步它)。
推荐文章
- codestyle;把javadoc放在注释之前还是之后?
- 如何在Spring中定义List bean ?
- 将Set<T>转换为List<T>的最简洁的方法
- 在JavaScript中,什么相当于Java的Thread.sleep() ?
- 使用Java重命名文件
- URL从Java中的类路径加载资源
- .toArray(new MyClass[0]) or .toArray(new MyClass[myList.size()])?
- Hibernate中不同的保存方法之间有什么区别?
- Java 8流和数组操作
- Java Regex捕获组
- Openssl不被视为内部或外部命令
- 如何添加自定义方法到Spring Data JPA
- 如何在Ubuntu中设置Java环境路径
- 无法执行dex:在Eclipse中超过GC开销限制
- 有人能解释一下JPA和Hibernate中的mappedBy吗?