易失性布尔与AtomicBoolean
AtomicBoolean做了什么,一个易变的布尔无法实现?
他们完全不同。 考虑这个volatile
整数的例子:
volatile int i = 0; void incIBy5() { i += 5; }
如果两个线程同时调用该函数,那么之后i
可能是5,因为编译后的代码会有点类似于这个(除非你不能在int
同步):
void incIBy5() { int temp; synchronized(i) { temp = i } synchronized(i) { i = temp + 5 } }
如果一个variables是易失性的,那么每个对它的primefaces访问都是同步的,但是实际上作为primefaces访问的资格并不总是显而易见的。 使用Atomic*
对象,可以保证每个方法都是“primefaces”的。
因此,如果你使用AtomicInteger
和getAndAdd(int delta)
,你可以确定结果是10
。 以同样的方式,如果两个线程都同时否定一个boolean
variables,并且使用AtomicBoolean
那么可以确定它具有原始值,而使用volatile boolean
则不能。
所以,只要你有多个线程修改一个字段,你就需要使它成为primefaces或者使用显式的同步。
volatile
的目的是不同的。 考虑这个例子
volatile boolean stop = false; void loop() { while (!stop) { ... } } void stop() { stop = true; }
如果你有一个运行loop()
线程和另一个调用stop()
线程,如果你忽略volatile
,你可能会遇到无限循环,因为第一个线程可能会cachingstop的值。 在这里, volatile
用于提示编译器在优化时要多加小心。
当所有字段仅由其拥有者线程更新时,我使用volatile字段,并且该值只能被其他线程读取,您可以将其视为发布/订阅场景,其中有许多观察者,但只有一个发布者。 但是,如果这些观察者必须根据字段的值执行一些逻辑,然后推回一个新的值,那么我会selectAtomic * vars或者locks或者synchronized块,这些都适合我。 在许多并发场景中,它归结为获取值,将其与另一个进行比较,并在必要时进行更新,因此存在于Atomic *类中的compareAndSet和getAndSet方法。
检查java.util.concurrent.atomic包中的JavaDocs以获取Atomic类的列表以及它们如何工作的一个很好的解释(只知道它们是无锁的,所以它们比锁或synchronized块有优势)
你不能做compareAndSet
, getAndSet
作为primefaces操作与易变的布尔值(除非你当然同步它)。
AtomicBoolean
具有以primefaces方式执行复合操作而不必使用synchronized
块的方法。 另一方面, volatile boolean
只能在synchronized
块内完成复合操作。
读/写volatile boolean
的内存效果分别与AtomicBoolean
的get
和set
方法相同。
例如, compareAndSet
方法将自动执行以下操作(不带synchronized
块):
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
后再次设置为true
)。
volatile
关键字保证发生在共享该variables的线程之间的关系之前。 它并不保证2个或更multithreading在访问该布尔variables时不会中断对方。
如果有多个线程访问类级variables,则每个线程都可以将该variables的副本保留在其threadlocalcaching中。
使volatilevariables可以防止线程在threadlocalcaching中保留variables的副本。
primefacesvariables是不同的,它们允许对其值进行primefaces修改。
记住IDIOM –
读 – 修改 – 写这个你不能实现与易失性
布尔原语types对于写入和读取操作是primefaces的,volatile保证发生原则。 所以,如果你需要一个简单的get()和set(),那么你不需要AtomicBoolean。
另一方面,如果你需要在设置一个variables的值之前执行一些检查,例如“如果为true然后设置为false”,那么你还需要以primefaces方式执行这个操作,在这种情况下,使用compareAndSet和其他方法AtomicBoolean,因为如果你试图用volatile布尔实现这个逻辑,你需要一些同步来确保get和set之间的值没有变化。
Atomic *类包装相同types的易失性基元。 来源:
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; }
所以,如果你正在做的是获得和设置一个primefaces*,那么你可能只是有一个易变的领域,而不是。
AtomicBoolean做了什么,一个易变的布尔无法实现?
然而,Atomic *类给你提供的方法是提供更多高级function的方法,如incrementAndGet()
, compareAndSet()
和其他实现多个操作(get / increment / set,test / set)而不locking的function。 这就是为什么Atomic *类非常强大。
例如,以下代码将安全地在multithreading环境中工作:
private final AtomicLong value = new AtomicLong(); ... value.incrementAndGet();
但是,如果多个线程正在使用以下内容,将会出现竞争条件,因为++
实际上是:get,increment和set。
private volatile value; ... // race conditions here value++;
同样重要的是要注意,使用Atomic *类包装易失性字段是从对象angular度封装关键共享资源的好方法。 这意味着开发人员不能只处理这个领域,假设它不共享可能注入问题的字段++; 或引入竞争条件的其他代码。
如果你只有一个线程修改你的布尔值,你可以使用一个volatile布尔值 (通常你这样做来定义一个stop
variables在线程的主循环中被检查)。
但是,如果您有多个线程修改布尔值,则应使用AtomicBoolean
。 否则,下面的代码是不安全的:
boolean r = !myVolatileBoolean;
该操作分两步进行:
- 读取布尔值。
- 布尔值被写入。
如果其他线程修改#1
和2#
之间的值,则可能得到错误的结果。 AtomicBoolean
方法通过自动执行步骤#1
和#2
来避免此问题。