Jef*_*ffV 224 java concurrency boolean volatile atomicboolean
AtomicBoolean做什么,一个volatile布尔无法实现?
tet*_*eto 250
当所述字段仅由其所有者线程更新时,我使用volatile字段,并且该值仅由其他线程读取,您可以将其视为发布/订阅场景,其中有许多观察者但只有一个发布者.但是,如果这些观察者必须根据字段的值执行一些逻辑,然后推回一个新的值,那么我会使用Atomic*vars或锁或同步块,这些都适合我.在许多并发场景中,它归结为获取值,将其与另一个值进行比较并在必要时进行更新,因此在Atomic*类中存在compareAndSet和getAndSet方法.
检查java.util.concurrent.atomic包的JavaDocs以获取Atomic类的列表以及它们如何工作的优秀解释(只是了解到它们是无锁的,因此它们优于锁或同步块)
Cep*_*pod 86
它们完全不同.考虑这个volatile整数的例子:
volatile int i = 0;
void incIBy5() {
i += 5;
}
Run Code Online (Sandbox Code Playgroud)
如果两个线程同时调用该函数,i之后可能是5,因为编译后的代码将与此类似(除非您无法同步int):
void incIBy5() {
int temp;
synchronized(i) { temp = i }
synchronized(i) { i = temp + 5 }
}
Run Code Online (Sandbox Code Playgroud)
如果变量是易失性的,则对它的每个原子访问都是同步的,但实际上有资格作为原子访问并不总是很明显.使用Atomic*对象,可以保证每个方法都是"原子的".
因此,如果您使用AtomicInteger和getAndAdd(int delta),您可以确定结果将是10.以同样的方式,如果两个线程同时否定一个boolean变量,AtomicBoolean你可以确定它之后具有原始值,用a volatile boolean,你不能.
因此,每当您有多个线程修改字段时,您需要使其成为原子或使用显式同步.
目的volatile是不同的.考虑这个例子
volatile boolean stop = false;
void loop() {
while (!stop) { ... }
}
void stop() { stop = true; }
Run Code Online (Sandbox Code Playgroud)
如果你有一个线程正在运行loop()而另一个线程正在调用stop(),那么如果省略则可能会遇到无限循环volatile,因为第一个线程可能会缓存stop的值.这里,volatile作为编译器的提示,使用优化更加小心.
nan*_*nda 52
你不能这样做compareAndSet,getAndSet因为使用volatile布尔值进行原子操作(当然除非你同步它).
Nam*_*San 42
AtomicBoolean具有以原子方式执行其复合操作而无需使用synchronized块的方法.另一方面,volatile boolean只能在synchronized块内执行复合操作.
读/写的记忆效应分别与方法和方法volatile boolean相同.getsetAtomicBoolean
例如,该compareAndSet方法将原子地执行以下操作(没有synchronized块):
if (value == expectedValue) {
value = newValue;
return true;
} else {
return false;
}
Run Code Online (Sandbox Code Playgroud)
因此,该compareAndSet方法将允许您编写保证仅执行一次的代码,即使从多个线程调用也是如此.例如:
final AtomicBoolean isJobDone = new AtomicBoolean(false);
...
if (isJobDone.compareAndSet(false, true)) {
listener.notifyJobDone();
}
Run Code Online (Sandbox Code Playgroud)
保证只通知监听器一次(假设没有其他线程在设置AtomicBoolean后false再次将其设置为true).
dhb*_*lah 14
volatile关键字保证发生在共享该变量的线程之间的关系之前.它并不能保证在访问该布尔变量时,2个或更多线程不会互相中断.
这里的很多答案都过于复杂、令人困惑,或者根本就是错误的。例如:
\n\n\n\xe2\x80\xa6 如果有多个线程修改布尔值,则应该使用
\nAtomicBoolean.
作为一般性陈述,这是不正确的。
\n\n\n如果变量是易失性的,则对它的每个原子访问都是同步的 \xe2\x80\xa6
\n
这是不正确的;同步是完全不同的事情。
\n简单的答案是AtomicBoolean允许您防止某些操作中的竞争条件,这些操作需要读取值,然后根据您读取的内容写入一个值;它使此类操作原子化(即,它消除了变量在读取和写入之间可能发生变化的竞争条件)\xe2\x80\x94,因此得名。
如果您只是读取和写入变量,其中写入不依赖于您刚刚读取的值,volatile那么即使使用多个线程,也可以正常工作。
记住成语 -
读取 - 修改 - 写入这是您无法使用 volatile 实现的
小智 5
如果有多个线程访问类级别变量,则每个线程可以在其threadlocal缓存中保留该变量的副本.
使变量volatile将阻止线程在threadlocal缓存中保留变量的副本.
原子变量是不同的,它们允许对其值进行原子修改.
小智 5
布尔基元类型对于写和读操作是原子的,易失性保证了先发生原则。所以如果你需要一个简单的 get() 和 set() 那么你就不需要 AtomicBoolean。
另一方面,如果您需要在设置变量值之前进行一些检查,例如“如果为真则设置为假”,那么您也需要以原子方式执行此操作,在这种情况下使用 compareAndSet 和其他方法提供AtomicBoolean,因为如果您尝试使用 volatile boolean 实现此逻辑,您将需要一些同步以确保值在 get 和 set 之间没有更改。
如果你只有一个线程修改你的布尔值,你可以使用一个 volatile 布尔值(通常你这样做是为了定义一个stop在线程的主循环中检查的变量)。
但是,如果您有多个线程修改布尔值,则应使用AtomicBoolean. 否则,以下代码是不安全的:
boolean r = !myVolatileBoolean;
Run Code Online (Sandbox Code Playgroud)
此操作分两步完成:
如果其他线程修改了#1和之间的值2#,您可能会得到错误的结果。AtomicBoolean方法通过执行步骤#1和#2原子来避免这个问题。
挥发性布尔值与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;
}
Run Code Online (Sandbox Code Playgroud)
因此,如果您要做的只是获取并设置Atomic *,那么您也可能只拥有一个volatile字段。
可变布尔无法实现的AtomicBoolean有什么作用?
原子*类为您提供了更高级的功能,如方法incrementAndGet(),compareAndSet()以及其他无锁实现多个操作(GET /递增/集,测试/套)。这就是Atomic *类如此强大的原因。
例如,如果多个线程使用,则下面的代码++将存在竞争条件,因为++实际上是:get,increment和set。
private volatile value;
...
// race conditions here
value++;
Run Code Online (Sandbox Code Playgroud)
但是,以下代码将在没有锁的情况下安全地在多线程环境中运行:
private final AtomicLong value = new AtomicLong();
...
value.incrementAndGet();
Run Code Online (Sandbox Code Playgroud)
同样重要的是要注意,使用Atomic *类包装volatile字段是从对象的角度封装关键共享资源的好方法。这意味着开发人员不能仅仅假设未共享该字段就处理该字段,这可能会给field ++注入问题。或其他引入竞争条件的代码。
| 归档时间: |
|
| 查看次数: |
91641 次 |
| 最近记录: |