的AtomicInteger震荡(AtomicInteger and volatile)

2019-07-18 05:59发布

我知道volatile允许知名度, AtomicInteger允许原子。 所以,如果我使用挥发性AtomicInteger ,这是否意味着我没有使用任何更多的同步机制?

例如。

class A {

    private volatile AtomicInteger count;

    void someMethod(){
        // do something
        if(count.get() < 10) {
            count.incrementAndGet();
        }
}

这是线程安全的?

Answer 1:

我相信, Atomic*实际上给两个原子性和波动性。 所以,当你调用(比方说) AtomicInteger.get()保证能让你获得最新的值。 这是记录在在java.util.concurrent.atomic 包文档 :

用于访问和原子能的更新记忆效应一般遵循规则挥发物,如Java™语言规范的第17.4陈述。

  • GET具有读取volatile变量的内存效果。
  • 组具有写入(分配)挥发性变量的记忆效应。
  • lazySet具有写入(分配)volatile变量除了它允许使用本身不征收重排的约束与普通的非易失性写入后续的(而不是以前的)内存的动作重新排序的记忆效应。 在其他使用上下文,> - lazySet可能归零出来的时候,垃圾收集,是永远不会再次访问参考的缘故适用。
  • weakCompareAndSet自动读取和写入有条件的变量,但不会产生任何的之前发生的排序,所以不提供任何担保相对于以前或以后的读取和比weakCompareAndSet的目标以外的任何变量写道。
  • compareAndSet和如getAndIncrement所有其他的读取和更新操作同时具有读取和写入volatile变量的内存效果。

现在,如果你有

volatile AtomicInteger count;

volatile部分意味着每个线程将使用最新AtomicInteger参考,而事实上,它是一个AtomicInteger意味着,你可以看到该对象的最新值。

这是不常见(IME)需要这一点-因为通常你不会重新分配count是指不同的对象。 相反,你必须:

private final AtomicInteger count = new AtomicInteger();

在这一点上,事实证明这是一个final变量意味着所有的线程将被处理同样的对象-而事实上,它是一个Atomic*对象表示,他们将对该对象中看到最新的值。



Answer 2:

我说没有,它不是线程安全的,如果你定义线程安全的,有在单线程模式和多线程模式相同的结果。 在单线程模式,计数将永远不会大于10,但在多线程模式下就可以了。

问题是, getincrementAndGet是原子,但是一个if不。 请记住,非原子操作可以在任何时候暂停。 例如:

  1. count = 9目前。
  2. 线程A运行if(count.get() <10)并得到true和停在那里。
  3. B线程运行if(count.get() <10)并得到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
}


Answer 3:

答案是有这个代码

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

这是的AtomicInteger的源代码。 该值是挥发性。 所以,里面的AtomicInteger使用挥发性。



Answer 4:

为了保持原有的语义,并且支持多线程,你可以这样做:

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。



文章来源: AtomicInteger and volatile