易失性布尔与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”的。

因此,如果你使用AtomicIntegergetAndAdd(int delta) ,你可以确定结果是10 。 以同样的方式,如果两个线程都同时否定一个booleanvariables,并且使用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块有优势)

你不能做compareAndSetgetAndSet作为primefaces操作与易变的布尔值(除非你当然同步它)。

AtomicBoolean具有以primefaces方式执行复合操作而不必使用synchronized块的方法。 另一方面, volatile boolean只能在synchronized块内完成复合操作。

读/写volatile boolean的内存效果分别与AtomicBooleangetset方法相同。

例如, 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布尔值 (通常你这样做来定义一个stopvariables在线程的主循环中被检查)。

但是,如果您有多个线程修改布尔值,则应使用AtomicBoolean 。 否则,下面的代码是不安全的:

 boolean r = !myVolatileBoolean; 

该操作分两步进行:

  1. 读取布尔值。
  2. 布尔值被写入。

如果其他线程修改#12#之间的值,则可能得到错误的结果。 AtomicBoolean方法通过自动执行步骤#1#2来避免此问题。