首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >AtomicInteger和易失性

AtomicInteger和易失性
EN

Stack Overflow用户
提问于 2013-01-15 21:12:21
回答 5查看 20.3K关注 0票数 31

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

例如:

代码语言:javascript
复制
class A {

    private volatile AtomicInteger count;

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

这是threadsafe吗?

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2013-01-15 21:19:08

我相信Atomic*实际上同时提供了原子性和易失性。因此,当您调用(比方说) AtomicInteger.get()时,您肯定会得到最新的值。java.util.concurrent.atomic package documentation中记录了这一点

原子的访问和更新的内存效应通常遵循挥发的规则,如

™语言规范的第17.4节所述。

  • get具有读取易失性变量的内存效果。
  • set具有写入(赋值)易失性变量的内存效果。
  • set具有写入(赋值)易失性变量的内存效果,但它允许对后续(而不是先前)内存操作进行重新排序,这些操作本身不会对普通的非易失性写入施加重新排序约束条件。在其他使用上下文中,出于垃圾收集的目的,当将从不访问的引用设为空时,可以应用>- lazySet,以原子方式读取和有条件地写入变量,但不会创建任何发生之前的排序,因此不提供对除weakCompareAndSet.
  • compareAndSet的目标之外的任何变量的先前或后续读取和写入的保证,并且所有其他读取和更新操作(如getAndIncrement )都具有读取和写入易失性变量的内存效应。

现在,如果你有

代码语言:javascript
复制
volatile AtomicInteger count;

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

这是不常见的(输入法)需要它-因为通常你不会重新分配count来引用不同的对象。取而代之的是,你需要:

代码语言:javascript
复制
private final AtomicInteger count = new AtomicInteger();

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

票数 62
EN

Stack Overflow用户

发布于 2014-08-30 14:45:17

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

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

  1. count = 9 currently.
  2. Thread A运行if(count.get() <10)并获取true,停止there.
  3. Thread B运行true并获取true,因此它运行count.incrementAndGet()并结束。现在count = 10.
  4. Thread A恢复并运行count.incrementAndGet(),现在运行count = 11,这在单线程模式下永远不会发生。

如果你想在不使用更慢的synchronized的情况下让它成为线程安全的,可以尝试这个实现:

代码语言:javascript
复制
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
}
票数 6
EN

Stack Overflow用户

发布于 2014-12-02 21:03:35

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

代码语言:javascript
复制
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();
        }

    }

}

这避免了任何线程看到count达到10。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/14338533

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档