如果多个线程可以访问一个字段,是否应该将其标记为 易失性?
阅读一些线程(常见并发问题、易失性关键字、 内存模型)我对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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
好吧,您已经阅读了其他问题,我想您已经阅读了答案,所以我将强调一些关键点:
补充:
如果该字段引用一个对象,那么它将拥有自己的字段,并且所有这些考虑因素也适用于这些字段。
Well, you've read those other questions and I presume you've read the answers already, so I'll just highlight some key points:
Added:
If the field reference an Object, then it will have fields of its own and all those consideration also applies to these fields.
如果一个字段被多个线程访问,它应该是
易失性
或final
,或者仅使用同步块访问。否则,分配的值可能对其他线程不可见。一个类必须专门设计用于多个线程的并发访问。简单地将字段标记为 volatile 或 Final 不足以保证线程安全。存在一致性问题(多个字段更改的原子性)、线程间信号传递的问题(例如使用
wait
和notify
)等。因此,最安全的是假设一个对象应该只对单个线程可见,除非另有说明。使所有对象都线程安全是没有必要的,而且成本高昂——就软件速度而言,但更重要的是,就开发费用而言。
相反,软件的设计应使并发线程之间的交互尽可能少,最好根本不交互。需要清楚地识别它们交互的点,以便设计适当的并发控制。
If a field is accessed by multiple threads, it should be
volatile
orfinal
, 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
andnotify
), 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.
如果您必须询问,请使用锁。
易失性
在某些情况下可能很有用,但要正确使用却非常非常困难。例如:如果两个线程同时运行
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:If two threads run
Increment()
at the same time, it's possible for the result to becounter = 1
. This is because the computer will first retrievecounter
, 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 forvolatile
- 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 tosynchronized
unless you have hard evidence that it's too slow already, and have done detailed analysis on the algorithm you plan to implement.简短的回答是否定的。线程问题需要比这更多的思考和规划。请参阅此内容,了解 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.