原子布尔能做什么,一个不稳定的布尔不能实现?
- 我在寻找一个更微妙的答案:"每种方法的局限性是什么?"例如,如果is是由一个线程设置并由一个或多个线程读取的标志,则不需要atomicboolean。但是,正如我从这些答案中看到的,如果线程在多个线程中共享一个变量,那么线程可以写入并根据其读取结果进行操作,那么AtomicBoolean将使用cas类型的非锁定操作。实际上,我在这里学到了不少东西。希望其他人也会受益。
- 可变布尔与原子布尔的可能重复
- volatile boolean需要显式同步来处理争用条件,换句话说,比如共享资源被多个线程更新(状态更改),例如递增/递减计数器或翻转boolean。
我使用易失性字段,当所述字段仅由其所有者线程更新并且值仅由其他线程读取时,您可以将其视为一个发布/订阅场景,其中有许多观察者,但只有一个发布者。但是,如果这些观察者必须根据字段的值执行一些逻辑,然后推回一个新的值,那么我将使用原子*变量、锁或同步块,无论什么最适合我。在许多并发场景中,它归结为获取值,将其与另一个值进行比较,并在必要时进行更新,因此原子*类中存在CompareAndSet和GetAndSet方法。
检查java.util.concurrent.atomic包的javadocs,以获取原子类的列表以及它们如何工作的极好解释(刚刚了解到它们是无锁的,因此它们比锁或同步块有优势)
- 如何决定哪个线程是所有者线程?
- @ksl我认为@teto想描述如果只有一个线程修改booleanvar,我们应该选择volatile boolean。
- 很好的总结。
它们完全不同。考虑一个volatile整数的例子:
1 2 3 4
| volatile int i = 0;
void incIBy5() {
i += 5;
} |
如果两个线程同时调用函数,那么i之后可能是5,因为编译后的代码与此类似(除非不能在int上同步):
1 2 3 4 5
| void incIBy5() {
int temp;
synchronized(i) { temp = i }
synchronized(i) { i = temp + 5 }
} |
如果一个变量是可变的,那么对它的每个原子访问都是同步的,但并不总是显而易见什么才是真正的原子访问。对于一个Atomic*对象,可以保证每个方法都是"原子的"。
因此,如果使用AtomicInteger和getAndAdd(int delta),您可以确定结果是10。同样地,如果两个线程同时对一个boolean变量求反,而对一个AtomicBoolean变量求反,则可以确定它在后面有原始值,而对一个volatile boolean变量则不能。
因此,每当有多个线程修改一个字段时,都需要使其成为原子的或使用显式同步。
volatile的目的不同。考虑这个例子
1 2 3 4 5
| volatile boolean stop = false;
void loop() {
while (!stop) { ... }
}
void stop() { stop = true; } |
如果有一个线程运行loop(),另一个线程调用stop(),那么如果省略volatile,可能会遇到无限循环,因为第一个线程可能缓存stop的值。在这里,volatile作为一个提示,提示编译器在优化时要更加小心。
- -1:你在举例,但不能真正解释volatile和atomicXXXX之间的区别。
- 请看一下原始问题。""允许原子修改"是一个有效的答案。
- 问题不是关于volatile的。问题是关于volatile boolean对AtomicBoolean。
- -1:关于布尔值的问题,与其他数据类型相比,这是一个独特的例子,应该直接解释。
- -1 volatile与同步无关。
- sgp15,volatile访问是同步操作(docs.oracle.com/javase/specs/jls/se7/html/…),因此,它们定义了并发事件的顺序,使它们等同于锁定在同一个监视器上。
- SGP15与Java 5的同步有关。
- 所以在volatile boolean示例中,使用atomicboolean有什么不同?这将是实际的问题,除了getandset()方法(假设您实际上需要这种能力),我不确定有什么不同。
- @罗宾,你总是可以用原子*替换一个volatile。但有时,这是不必要的,你可以安全一些开销。用挥发性物质代替原子会有伤害。
- 会有什么伤害?专门针对原子布尔,而不是一般的原子。我宁愿直接编码到布尔值,因为代码比使用原子布尔值的get/set方法更可读。
- 易失性布尔值上的flag = !flag不是线程安全的。如果只使用原子变量的get和set,那么应该可以进行切换。
- 如果布尔值由多个线程读取,但只由一个线程写入,那么volatile boolean就足够了。如果还有很多作家,你可能需要AtomicBoolean。
- 正确的答案应该是,它提供了一个比较和设置函数,这是不可能与volatile boolean(没有显式同步)一起使用的。这个答案不太清楚。越简单越好。我会要求OP考虑编辑答案,因为这是公认的答案。
- 我认为这个答案是错误的。AtomicBoolean只是一个原始布尔值的包装器,请参阅其他答案。例如,您希望使用对象(例如布尔值),但仍然希望将其标记为volatile——>使用atomicboolean
- "它们完全不同。"不,它们非常相似。DOCs明确地指出,CabaseDeSET是整个点:DOCS.Oracle .COM/JavaSe/ 7 /DOCS/API/Java/UTL/Orth/AfiMi‌
不能将compareAndSet,getAndSet作为原子操作与volatile boolean(当然,除非同步它)。
- 这是真的,但这难道不是布尔值的一个非常罕见的要求吗?
- @Robin考虑使用它来控制初始化方法的延迟调用。
AtomicBoolean具有自动执行复合操作的方法,而不必使用synchronized块。另一方面,如果在synchronized块内执行复合操作,则volatile boolean只能执行复合操作。
对volatile boolean的读写记忆效应分别与AtomicBoolean的get和set方法相同。
例如,compareAndSet方法将自动执行以下操作(不带synchronized块):
1 2 3 4 5 6
| if (value == expectedValue) {
value = newValue;
return true;
} else {
return false;
} |
因此,compareAndSet方法将允许您编写保证只执行一次的代码,即使是从多个线程调用的代码。例如:
1 2 3 4 5 6 7
| final AtomicBoolean isJobDone = new AtomicBoolean(false);
...
if (isJobDone.compareAndSet(false, true)) {
listener.notifyJobDone();
} |
保证只通知侦听器一次(假设没有其他线程在设置为true之后再次将AtomicBoolean设置回false)。
volatile关键字保证发生在共享该变量的线程之间的关系之前。它不能保证两个或多个线程在访问该布尔变量时不会互相中断。
- BooLin(如原始类型)在Java中访问是原子的。阅读和作业。所以没有其他线程会"中断"布尔操作。
- @欢迎参考JVM规范。
- 对不起,这个问题怎么回答?Atomic*类包装volatile字段。
- CPU缓存不是设置易失性的主要因素吗?确保读取的值实际上是最近设置的值
Volatile boolean vs AtomicBoolean
*《原子类包A型(波动的原始相同。从源。
1 2 3 4 5 6 7 8 9 10 11
| 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 ;
} |
所以如果你做的是把所有的原子和A *设置然后你不妨做一场好的波动。
What does AtomicBoolean do that a volatile boolean cannot achieve?
*给你这类原子方法提供更多先进的功能,如incrementAndGet(),compareAndSet(),和他人,实现多业务(增量/获得/设置/测试集)没有锁定。这就是为什么这是如此强大的类原子的*。
例如,如果使用的是多线程使用下面的代码++,会有竞争条件,实际上是因为++:get,增量和集。
1 2 3 4
| private volatile value;
...
// race conditions here
value++; |
然而,下面的代码将工作在一个多线程环境安全:没有锁
1 2 3
| private final AtomicLong value = new AtomicLong();
...
value.incrementAndGet(); |
它是重要的注意,使用的原子波动场*缠绕类是一个好的方式来encapsulate共享关键资源从一个对象采取的。这意味着,开发商不能及时处理场如果不是共享问题是一个8场+;或其他代码,引入竞争条件。
如果有多个线程访问类级变量,那么每个线程都可以将该变量的副本保存在其线程本地缓存中。
使变量变为易失性将阻止线程在线程本地缓存中保留变量的副本。
原子变量是不同的,它们允许原子修改它们的值。
布尔型是原始原子的读操作和写在前,发生动荡的商业原则。所以如果你需要一个简单的get()和()的集合,然后你不需要的atomicboolean。
在其他的手,如果你需要一些设置的值之前,实施检查一变,例如"如果TRUE然后设置为false,那么你需要做这个手术atomically为好,本案例中使用的atomicboolean compareandset和其他方法提供的,因为如果你尝试实现这一动荡的布尔逻辑。我需要一些同步问题一些有价值的确信没有改变之间的get和set。
记住这个成语-
读-修改-写这个你不能用volatile实现的
- 又短又脆。volatile只在拥有线程能够更新字段值,其他线程只能读取的情况下工作。
如果你有一个线程的布尔只读修改,你可以使用A挥发性布尔(to define a,你本不stop变量在线程的主回路)。
然而,如果你有一个线程的多元性,在AtomicBoolean布尔,你应该使用。人是不安全的,下面的代码:
1
| boolean r = !myVolatileBoolean; |
这是在两个步骤:做手术
一个布尔值读取。
写的是布尔值。
如果在其他线程之间的数据值和2##1,你可能得到一个错误的结果。AtomicBoolean避免这个问题的方法和步骤#1#2atomically做中学。