AtomicBoolean做了哪些volatile boolean不能做到的事情?
当前回答
如果有多个线程访问类级别变量,则 每个线程都可以在其线程本地缓存中保留该变量的副本。
将变量设置为volatile将防止线程将变量的副本保存在线程本地缓存中。
原子变量是不同的,它们允许对其值进行原子修改。
其他回答
如果你只有一个线程修改你的布尔值,你可以使用一个volatile布尔值(通常你这样做是为了在线程的主循环中定义一个停止变量)。
但是,如果有多个线程修改布尔值,则应该使用AtomicBoolean。否则,以下代码是不安全的:
boolean r = !myVolatileBoolean;
该操作分两步完成:
读取布尔值。 写入布尔值。
如果其他线程修改了#1到2#之间的值,您可能会得到错误的结果。AtomicBoolean方法通过原子地执行步骤#1和#2来避免这个问题。
记住成语——
READ - MODIFY- WRITE这个你不能用volatile实现
I use volatile fields when said field is ONLY UPDATED by its owner thread and the value is only read by other threads, you can think of it as a publish/subscribe scenario where there are many observers but only one publisher. However if those observers must perform some logic based on the value of the field and then push back a new value then I go with Atomic* vars or locks or synchronized blocks, whatever suits me best. In many concurrent scenarios it boils down to get the value, compare it with another one and update if necessary, hence the compareAndSet and getAndSet methods present in the Atomic* classes.
检查java.util.concurrent.atomic包中的JavaDocs,以获得Atomic类的列表和它们如何工作的出色解释(刚刚了解到它们是无锁的,因此它们比锁或同步块更有优势)
它们完全不同。考虑下面这个易变整数的例子:
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提示编译器在优化时要更加小心。
这里的很多答案都过于复杂,令人困惑,或者是错误的。例如:
如果你有多个线程修改布尔值,你应该使用AtomicBoolean。
一般来说,这是不正确的。
如果一个变量是volatile,那么对它的每个原子访问都是同步的……
这是不正确的;同步完全是另一回事。
简单的答案是,AtomicBoolean允许您在某些操作中防止竞争条件,这些操作需要读取值,然后根据所读取的内容写入值;它使这些操作具有原子性(即它删除了变量可能在读和写之间发生变化的竞态条件)——因此得名。
如果你只是读写变量,写操作并不依赖于你刚刚读取的值,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