读取一些线程(common concurrency problems,volatile keyword,memory model)我对Java中的并发问题感到困惑。
我有很多字段可以被多个线程访问。我是否应该通过它们并将它们标记为易变?
在构建一个类时,我不知道多个线程是否会访问它,所以肯定让任何字段不变得不稳定是不安全的,所以根据我的理解,你很少会遇到这种情况。不要用它。这是对的吗?
对我而言,这是针对1.5版JVM及更高版本的,但不仅限于回答我的具体设置。
答案 0 :(得分:4)
嗯,你已经阅读了其他问题,我认为你已经阅读了答案,所以我只想强调一些要点:
添加了:
如果该字段引用一个Object,那么它将具有自己的字段,所有这些考虑也适用于这些字段。
答案 1 :(得分:3)
如果多个线程访问某个字段,则该字段应为volatile
或final
,或仅使用synchronized块访问。否则,指定的值可能对其他线程不可见。
必须专门为多个线程的并发访问设计类。简单地标记易失性或最终的字段对于线程安全是不够的。存在一致性问题(多个字段的更改的原子性),对线程间信令的关注(例如,使用wait
和notify
)等。
因此,最安全的做法是假设一个对象应该只对一个线程可见,除非另有说明。使所有对象都是线程安全的并不是必需的,并且在软件速度方面成本很高,但更重要的是,在开发费用方面。
相反,应该设计软件,以便并发线程尽可能少地相互交互,最好不要。需要明确识别它们进行交互的点,以便设计适当的并发控制。
答案 2 :(得分:2)
如果你不得不问,请使用锁。 volatile
在某些情况下可能很有用,但要做到这一点非常非常困难。例如:
class Foo {
private volatile int counter = 0;
int Increment() {
counter++;
return counter;
}
}
如果两个线程同时运行Increment()
,则结果可能为counter = 1
。这是因为计算机将首先检索counter
,添加一个,然后将其保存。 Volatile只是强制保存和加载以相对于其他语句的特定顺序发生。
请注意,synchronized
通常不需要volatile
- 如果对同一字段的所有访问都受同一监视器的保护,则永远不需要volatile
。
使用volatile
制作无锁算法非常非常困难;坚持synchronized
,除非你有确凿的证据证明它已经太慢了,并且已经对你计划实施的算法进行了详细的分析。
答案 3 :(得分:1)
简短的回答是否定的。线程问题需要更多的思考和计划。有关volatile何时有助于线程化以及何时不进行线程化的限制,请参阅this。必须正确地同步值的修改,但通常修改一次需要多个变量的状态。比如说你有变量,如果它符合标准你想要改变它。从数组读取和写入数组是不同的指令,需要同步。挥发性不够。
还要考虑变量引用可变对象(比如数组或集合)的情况,然后与该对象进行交互将不会是线程安全的,因为引用是易失性的。