AtomicInteger和volatile

我知道volatile允许可见性, AtomicInteger允许primefaces性。 因此,如果我使用易失性AtomicInteger ,是否意味着我不必再使用任何同步机制?

例如。

 class A { private volatile AtomicInteger count; void someMethod(){ // do something if(count.get() < 10) { count.incrementAndGet(); } } 

这线程安全吗?

我相信Atomic*实际上给出primefaces性和波动性。 因此,当您调用(比方说) AtomicInteger.get() ,您可以保证获得最新值。 这在java.util.concurrent.atomic 包文档中有记录 :

访问和更新primefaces的记忆效应通常遵循挥发性规则,如Java™语言规范第17.4节所述。

  • get具有读取volatile变量的记忆效应。
  • set具有写入(赋值)volatile变量的记忆效应。
  • lazySet具有写入(赋值)volatile变量的记忆效应,除了它允许对后续(但不是先前)的内存操作进行重新排序,这些内存操作本身不会对普通的非易失性写入施加重新排序约束。 在其他用法上下文中,> – lazySet可以在归零时为了垃圾收集而应用,这是一个永远不会再次访问的引用。
  • weakCompareAndSet以primefaces方式读取并有条件地写入变量,但不会创建任何先前发生的排序,因此不提供与weakCompareAndSet目标之外的任何变量的先前或后续读取和写入相关的保证。
  • compareAndSet和所有其他读取和更新操作(如getAndIncrement)都具有读取和写入volatile变量的内存效果。

现在,如果你有

 volatile AtomicInteger count; 

volatile部分意味着每个线程将使用最新的AtomicInteger引用,并且它是AtomicInteger的事实意味着您还将看到该对象的最新值。

需要这个并不常见(IME) – 因为通常你不会重新分配count以引用不同的对象。 相反,你有:

 private final AtomicInteger count = new AtomicInteger(); 

此时,它是一个final变量这一事实意味着所有线程都将处理同一个对象 – 事实上它是一个Atomic*对象意味着它们将在该对象中看到最新的值。

如果你将线程安全定义为在单线程模式和multithreading模式下具有相同的结果,那么我会说不,它不是线程安全的。 在单线程模式下,计数永远不会超过10,但在multithreading模式下它可以。

问题是getincrementAndGet是primefaces的,但if不是。 请记住,可以随时暂停非primefaces操作。 例如:

  1. 目前count = 9
  2. 线程A运行if(count.get() <10)并获得true并在那里停止。
  3. 线程B运行if(count.get() <10)并且也count.incrementAndGet() true因此它运行count.incrementAndGet()并完成。 现在count = 10
  4. 线程A恢复并运行count.incrementAndGet() ,现在count = 11 ,这在单线程模式下永远不会发生。

如果你想在不使用较慢的synchronized情况下使其成为线程安全的,那么试试这个实现:

 class A{ final AtomicInteger count; void someMethod(){ // do something if(count.getAndIncrement() <10){ // safe now } else count.getAndDecrement(); // rollback so this thread did nothing to count } 

这段代码中有答案

http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/util/concurrent/atomic/AtomicInteger.java

这是AtomicInteger的源代码。 值是挥发性的。 因此,AtomicInteger在内部使用Volatile。

要保持原始语义并支持多个线程,您可以执行以下操作:

 public class A { private AtomicInteger count = new AtomicInteger(0); public void someMethod() { int i = count.get(); while (i < 10 && !count.compareAndSet(i, i + 1)) { i = count.get(); } } } 

这可以避免任何线程看到计数达到10。