AtomicBoolean做了哪些volatile boolean不能做到的事情?
当前回答
两者都是相同的概念,但在原子布尔中,它将为操作提供原子性,以防cpu切换发生在两者之间。
其他回答
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)。
这里的很多答案都过于复杂,令人困惑,或者是错误的。例如:
如果你有多个线程修改布尔值,你应该使用AtomicBoolean。
一般来说,这是不正确的。
如果一个变量是volatile,那么对它的每个原子访问都是同步的……
这是不正确的;同步完全是另一回事。
简单的答案是,AtomicBoolean允许您在某些操作中防止竞争条件,这些操作需要读取值,然后根据所读取的内容写入值;它使这些操作具有原子性(即它删除了变量可能在读和写之间发生变化的竞态条件)——因此得名。
如果你只是读写变量,写操作并不依赖于你刚刚读取的值,volatile就可以很好地工作,即使是多线程。
两者都是相同的概念,但在原子布尔中,它将为操作提供原子性,以防cpu切换发生在两者之间。
它们完全不同。考虑下面这个易变整数的例子:
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提示编译器在优化时要更加小心。
记住成语——
READ - MODIFY- WRITE这个你不能用volatile实现
推荐文章
- 在流中使用Java 8 foreach循环移动到下一项
- 访问限制:'Application'类型不是API(必需库rt.jar的限制)
- 用Java计算两个日期之间的天数
- 如何配置slf4j-simple
- 在Jar文件中运行类
- 带参数的可运行?
- 我如何得到一个字符串的前n个字符而不检查大小或出界?
- 我可以在Java中设置enum起始值吗?
- Java中的回调函数
- c#和Java中的泛型有什么不同?和模板在c++ ?
- 在Java中,流相对于循环的优势是什么?
- Jersey在未找到InjectionManagerFactory时停止工作
- 在Java流是peek真的只是调试?
- Recyclerview不调用onCreateViewHolder
- 将JSON字符串转换为HashMap