繁体   English   中英

如果多个线程可以访问某个字段,那么它应该标记为volatile吗?

[英]If more than one thread can access a field should it be marked as volatile?

阅读几个线程( 常见的并发问题volatile关键字内存模型 )我对Java中的并发问题感到困惑。

我有很多字段可以被多个线程访问。 我是否应该通过它们并将它们标记为易变?

在构建一个类时,我不知道多个线程是否会访问它,所以让任何字段都不易变化是不安全的,所以根据我的理解,你很少会使用它。 这个对吗?

对我来说,这是特定于版本1.5 JVM及更高版本,但不仅限于回答我的具体设置。

好吧,你已经阅读了其他问题,我认为你已经阅读了答案,所以我只想强调一些要点:

  1. 他们会改变吗? 如果没有,你不需要挥发性
  2. 如果是,则是与另一个相关的字段的值? 如果是,请转到第4点
  3. 有多少线程会改变它? 如果只有1,那么你只需要挥发性物质
  4. 如果数字2的答案是“否”或多个线程要写入它,那么单独的volatile是不够的 ,你可能需要同步访问

添加:
如果该字段引用一个Object,那么它将具有自己的字段,所有这些考虑也适用于这些字段。

如果一个字段由多个线程访问,则它应该是volatilefinal ,或者仅使用synchronized块访问。 否则,其他线程可能看不到指定的值。

必须专门为多线程的并发访问设计类。 简单地标记易失性或最终的字段对于线程安全是不够的。 存在一致性问题(多个字段的更改的原子性),关于线程间信令的关注(例如,使用waitnotify )等。

因此,最安全的做法是假设一个对象应该只对单个线程可见,除非另有说明。 使所有对象都是线程安全的并不是必需的,并且在软件速度方面成本很高,但更重要的是,在开发费用方面。

相反,软件的设计应使并发线程尽可能少地相互交互,最好不要。 需要清楚地识别它们进行交互的点,以便可以设计适当的并发控制。

如果你不得不问,请使用锁。 volatile在某些情况下可能很有用,但是很难做到正确。 例如:

class Foo {
  private volatile int counter = 0;
  int Increment() {
    counter++;
    return counter;
  }
}

如果两个线程同时运行Increment() ,则结果可能是counter = 1 这是因为计算机将首先检索counter ,添加一个,然后将其保存。 Volatile仅强制保存和加载以相对于其他语句的特定顺序发生。

请注意, synchronized通常不需要volatile - 如果对同一个监视器的所有访问都受到同一监视器的保护,则永远不需要volatile

使用volatile来制作无锁算法非常非常困难; 坚持synchronized除非你已经有足够的证据表明它已经太慢,并且已经对你计划实施的算法进行了详细的分析。

最简洁的答案是不。 线程问题需要更多的思考和计划。 请参阅此内容,了解volatile何时有助于线程化以及何时不进行线程化。 必须正确地同步值的修改,但通常修改一次需要多个变量的状态。 比如说你有变量,如果它符合标准你想要改变它。 从数组读取和写入数组是不同的指令,需要同步。 挥发性不够。

还要考虑变量引用可变对象(比如数组或集合)的情况,然后与该对象进行交互将不是线程安全的,因为引用是易失性的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM