AtomicBoolean做了哪些volatile boolean不能做到的事情?
当前回答
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字段是封装关键共享资源的好方法。这意味着开发人员不能假设字段不共享就处理它,可能会在字段++中注入问题;或其他引入竞态条件的代码。
其他回答
记住成语——
READ - MODIFY- WRITE这个你不能用volatile实现
布尔基元类型是原子的,用于写和读操作,volatile保证happens before原则。因此,如果您需要一个简单的get()和set(),那么您不需要AtomicBoolean。
另一方面,如果你需要在设置一个变量的值之前执行一些检查,例如。"如果为真,则设置为假",那么您也需要原子地执行此操作,在这种情况下使用compareAndSet和AtomicBoolean提供的其他方法,因为如果您尝试使用volatile boolean实现此逻辑,则需要一些同步来确保get和set之间的值没有更改。
它们完全不同。考虑下面这个易变整数的例子:
volatile int i = 0;
void incIBy5() {
i += 5;
}
如果两个线程并发调用这个函数,i可能在后面是5,因为编译后的代码会有点类似于这个(除了你不能同步int):
void incIBy5() {
int temp;
synchronized(i) { temp = i }
synchronized(i) { i = temp + 5 }
}
如果一个变量是volatile的,那么对它的每个原子访问都是同步的,但是并不总是很明显什么才是原子访问。使用Atomic*对象,可以保证每个方法都是“原子的”。
因此,如果使用AtomicInteger和getAndAdd(int delta),可以确保结果为10。以同样的方式,如果两个线程同时对一个布尔变量求反,使用AtomicBoolean可以确保它之后具有原始值,而使用volatile布尔则不能。
因此,每当有多个线程修改一个字段时,您需要使其原子化或使用显式同步。
volatile的用途是不同的。考虑这个例子
volatile boolean stop = false;
void loop() {
while (!stop) { ... }
}
void stop() { stop = true; }
如果有一个线程运行loop(),另一个线程调用stop(),如果省略volatile,可能会陷入无限循环,因为第一个线程可能缓存stop的值。这里,volatile提示编译器在优化时要更加小心。
Volatile关键字保证共享该变量的线程之间的happens-before关系。它不能保证2个或更多的线程在访问布尔变量时不会相互中断。
两者都是相同的概念,但在原子布尔中,它将为操作提供原子性,以防cpu切换发生在两者之间。
推荐文章
- 在Selenium中等待页面加载
- Maven父pom vs模块pom
- 将JSON数据转换为Java对象
- Java的隐藏特性
- 使用Java 8的可选Stream::flatMap
- 使用管道字符("|")分割字符串
- 在IntelliJ中找不到Maven插件
- Java List.add() UnsupportedOperationException
- 连接两个字节数组的简单方法
- 为什么Mockito不模拟静态方法?
- Volatile boolean vs AtomicBoolean
- 在一个类中使用相同的方法实现两个接口。覆盖了哪个接口方法?
- 线程的上下文类装入器和普通类装入器之间的区别
- 如何在Java中正确地比较两个整数?
- 在Java中获取“unixtime”