可以使用" AtomicInteger"保证线程安全吗?

时间:2018-02-15 19:21:20

标签: java multithreading atomic volatile

假设我有

private volatile AtomicInteger atomInt = new AtomicInteger(3);

在方法中我的用法是atomInt.incrementAndGet()

由于我使用AtomicInteger,因此会避免"线程干扰"。然后我使用volatile,因此它将保证所有线程中变量的一致视图。这是否意味着我有完整的线程安全性,或者仍然存在内存一致性问题"?

我因使用"减少"而感到困惑。在tutorial,所以它告诉我仍有机会,但我无法想到它:

  

使用volatile变量可降低内存一致性的风险   错误,因为对volatile变量的任何写入都会建立一个   在与之后的相关读取之前发生   变量

2 个答案:

答案 0 :(得分:2)

  

然后我使用volatile,因此它将保证所有线程中变量的一致视图。

原子变量已经保证了线程安全性。如果您不重新分配变量,则volatile是多余的。您可以在此处将volatile替换为final

private final AtomicInteger atomInt = new AtomicInteger(3);
  

这是否意味着我有完整的线程安全性或仍然存在“内存一致性问题”的可能性?

此时,它绝对是线程安全的。使用变量时,可能不会出现“内存一致性问题”。但是使用正确的线程安全组件并不意味着整个类/程序是线程安全的。如果它们之间的交互不正确,可能会出现问题。

  

使用volatile变量可降低内存一致性错误的风险......

volatile个变量只能保证可见性。他们不保证atomicity

正如Brian Goetz所写(强调我的):

  

volatile变量很方便,但是它们有局限性。 volatile变量最常见的用途是完成,中断或状态标志。易失性变量可用于其他类型的状态信息,但尝试此操作时需要更加小心。例如, volatile的语义不足以使增量操作(count++)原子,除非您可以保证变量仅从单个线程写入

     

只有满足以下所有条件时才能使用volatile变量:

     
      
  • 写入变量不依赖于其当前值,或者您可以确保只有一个线程更新该值;
  •   
  • 变量不参与其他状态变量的不变量;
  •   
  • 访问变量时,出于任何其他原因不需要锁定。
  •   

来自java.util.concurrent.atomic包的文档:

  
      
  • get具有阅读volatile变量的记忆效应。
  •   
  • set具有编写(分配)volatile变量的记忆效应。
  •   

答案 1 :(得分:1)

易失性确实意味着变量的变化将是可见的。但在这种情况下,您不应该更改变量所持有的引用。

你想要引用一个原子对象volatile似乎很奇怪。 atomicinteger类的重点是提供一种安全访问和更改整数值的方法。使一些变量变为volatile的唯一原因是因为你打算覆盖它的值。为什么在可以使用其实例方法更新其值时覆盖对AtomicInteger的引用?

这就是为什么你得到建议让这个变量最终而不是volatile。使变量最终指向参考,以便它不会改变,同时确保该变量包含的引用是可见的。 atomicInteger以线程安全的方式管理自己的状态,因此您不必覆盖对它的引用。

所以说volatile在这里是多余的并不完全正确。但它正在做一些通常不应该做的事情。必须更改变量中包含的值时,请使用volatile。如果不应更改变量中包含的值,请使用final。