我想知道以下类是否是线程安全的:
class Example {
private Thing thing;
public setThing(Thing thing) {
this.thing = thing;
}
public use() {
thing.function();
}
}
具体来说,如果一个线程通过Example :: use来调用setThing而另一个线程在Thing :: function中会发生什么?
例如:
Example example = new Example();
example.setThing(new Thing());
createThread(example); // create first thread
createThread(example); // create second thread
//Thread1
while(1) {
example.use();
}
//Thread2
while(1) {
sleep(3600000); //yes, i know to use a scheduled thread executor
setThing(new Thing());
}
具体来说,我想知道,当use()执行时调用setThing时,它是否会成功继续旧对象,或者更新对象的引用会以某种方式导致问题。
答案 0 :(得分:1)
如果方法是共享资源并且线程未同步,则它们将发生冲突并且可能发生多种情况,包括覆盖由另一个线程计算并存储在共享变量中的数据。
如果该方法只有局部变量,那么你可以使用mutliple线程的方法,而不必担心赛车。但是,通常非辅助类操作其方法中的成员变量,因此建议使方法同步,或者如果您确切知道问题可能发生的位置,则使用{{1}锁定(也称为同步)方法的子范围。锁/对象。
答案 1 :(得分:1)
关于特定级别的线程安全性的推理有两点:
Example
类的共享状态仅包含一个Thing
对象。
setThing
的结果,因此它们可以处理陈旧数据。 NPE也是可以接受的,因为在类初始化期间thing
的初始值为null
。Thing
方法访问use
类是否安全是不可能的。但是Example
调用use
方法而没有任何同步,所以它应该是,否则Example
不是线程安全的。因此Example
不是线程安全的。要修复第1点,您可以将volatile
添加到thing
字段,如果您确实需要setter或将其标记为final并在构造函数中初始化。确保满足2的最简单方法是将use
标记为synchronized
。如果您使用setThing
标记synchronized
,则不再需要volatile
。然而,还有许多其他复杂的技术可以满足第2点。This伟大的书籍更详细地描述了这里所写的所有内容。