如果多个线程可以访问一个字段,是否应该将其标记为 易失性?

发布于 2024-08-08 10:21:52 字数 590 浏览 1 评论 0原文

阅读一些线程(常见并发问题易失性关键字内存模型)我对Java中的并发问题感到困惑。

我有很多字段由多个线程访问。我应该检查它们并将它们全部标记为易失性吗?

在构建一个类时,我不知道多个线程是否会访问它,所以让任何字段是易失性的肯定是不安全的,所以根据我的理解,很少有情况你不会使用它。这是正确的吗?

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

Reading a few threads (common concurrency problems, volatile keyword, memory model) I'm confused about concurrency issues in Java.

I have a lot of fields that are accessed by more than one thread. Should I go through them and mark them all as volatile?

When building a class I'm not aware of whether multiple threads will access it, so surely it is unsafe to let any field not be volatile, so by my understanding there's very few cases you wouldn't use it. Is this correct?

For me this is specific to version 1.5 JVMs and later, but don't feel limited to answering about my specific setup.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

黯然 2024-08-15 10:21:52

好吧,您已经阅读了其他问题,我想您已经阅读了答案,所以我将强调一些关键点:

  1. 它们会改变吗?如果不是,则不需要 volatile
  2. 如果是,那么一个字段的值是否与另一个字段相关?如果是,转到第4点,
  3. 有多少线程会改变它?如果只有 1,那么您所需要的就是 volatile
  4. 如果数字 2 的答案是“否”或者多个线程要写入它,那么仅使用 volatile 就不够,您可能会需要同步访问

补充:
如果该字段引用一个对象,那么它将拥有自己的字段,并且所有这些考虑因素也适用于这些字段。

Well, you've read those other questions and I presume you've read the answers already, so I'll just highlight some key points:

  1. are they going to change? if not, you don't need volatile
  2. if yes, then is the value of a field related to another? if yes, go to point 4
  3. how many threads will change it? if only 1, then volatile is all you need
  4. if the answer to number 2 is "no" or more than one threads is going to write to it, then volatile alone is not enough, you'll probably need to synchronize the access

Added:
If the field reference an Object, then it will have fields of its own and all those consideration also applies to these fields.

醉南桥 2024-08-15 10:21:52

如果一个字段被多个线程访问,它应该是易失性final,或者仅使用同步块访问。否则,分配的值可能对其他线程不可见。

一个类必须专门设计用于多个线程的并发访问。简单地将字段标记为 volatile 或 Final 不足以保证线程安全。存在一致性问题(多个字段更改的原子性)、线程间信号传递的问题(例如使用 waitnotify)等。

因此,最安全的是假设一个对象应该只对单个线程可见,除非另有说明。使所有对象都线程安全是没有必要的,而且成本高昂——就软件速度而言,但更重要的是,就开发费用而言。

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

If a field is accessed by multiple threads, it should be volatile or final, or accessed only with synchronized blocks. Otherwise, assigned values may not be visible to other threads.

A class has to be specifically designed for concurrent access by multiple threads. Simply marking fields volatile or final is not sufficient for thread-safety. There are consistency issues (atomicity of changes to multiple fields), concerns about inter-thread signaling (for example using wait and notify), etc.

So, it is safest to assume that an object should be visible to only a single thread unless it is documented otherwise. Making all of your objects thread-safe isn't necessary, and is costly—in terms of software speed, but more importantly, in terms of development expense.

Instead, software should be designed so that concurrent threads interact with each other as little as possible, preferably not at all. The points where they do interact need to be clearly identified so that the proper concurrency controls can be designed.

风追烟花雨 2024-08-15 10:21:52

如果您必须询问,请使用锁。 易失性在某些情况下可能很有用,但要正确使用却非常非常困难。例如:

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

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

请注意,synchronized 通常不需要 易失性 - 如果对给定字段的所有访问都受同一监视器保护,则永远不需要 易失性

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

If you have to ask, use locks. volatile can be useful in some cases, but it's very, very difficult to get right. For example:

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

If two threads run Increment() at the same time, it's possible for the result to be counter = 1. This is because the computer will first retrieve counter, add one, then save it back. Volatile just forces the save and load to occur in a specific order relative to other statements.

Note that synchronized usually obviates the need for volatile - if all accesses to a given field are protected by the same monitor, volatile will never be needed.

Using volatile to make lockless algorithms is very, very difficult; stick to synchronized unless you have hard evidence that it's too slow already, and have done detailed analysis on the algorithm you plan to implement.

梦幻之岛 2024-08-15 10:21:52

简短的回答是否定的。线程问题需要比这更多的思考和规划。请参阅此内容,了解 volatile 何时提供帮助的一些限制线程和没有线程时。值的修改必须正确同步,但通常修改一次需要多个变量的状态。举例来说,您有一个变量,并且您希望在它满足条件时更改它。从数组读取和写入数组是不同的指令,需要一起同步。挥发性还不够。

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

The short answer is no. Threading issues require more thought and planning than this. See this for some limitations on when volatile helps for threading and when it does not. The modification of the values has to be properly synchronized, but very typically modification requires the state of more than one variable at a time. Say for example you have variable and you want to change it if it meets a criteria. The read from the array and the write to the array are different instructions, and need to be synchronized together. Volatile is not enough.

Consider also the case where the variable references a mutable object (say an array or a Collection), then interacting with that object will not be thread safe just because the reference is volatile.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文