Java线程设置对象引用的安全性
我想知道以下类是否是线程安全的:Java线程设置对象引用的安全性,java,multithreading,Java,Multithreading,我想知道以下类是否是线程安全的: class Example { private Thing thing; public setThing(Thing thing) { this.thing = thing; } public use() { thing.function(); } } 具体来说,如果一个线程通过Example::use调用setThing,而另一个线程在Thing::function中,会发生什么情况 例如: Example exampl
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
具体地说,我想知道,当use()执行时调用setThing时,它会成功地继续使用旧对象,还是会以某种方式更新对该对象的引用导致问题。如果该方法正在共享资源而线程未同步,然后,它们会发生冲突,可能会出现几种情况,包括覆盖由另一个线程计算并存储在共享变量中的数据
如果该方法只有局部变量,那么您可以通过多线程使用该方法,而无需担心竞速。但是,通常非助手类在其方法中操纵成员变量,因此建议使方法同步,或者如果您确切知道问题可能发生的位置,则使用
final
lock/object锁定(也称为同步)方法的子范围 对SpecificUCAR类的螺纹安全性进行推理时,有两点:
示例
类的共享状态仅由一个对象组成
从可见性的角度来看,该类不是线程安全的。一个线程的设置结果
不会被其他线程看到,因此它们可以处理过时的数据。NPE也是可以接受的,因为类初始化期间thing
的初始值为null
通过use
方法访问Thing
类而不使用其源代码是不可能的。但是,Example
调用use
方法而不进行任何同步,否则Example
就不是线程安全的
因此,示例
不是线程安全的。要修复点1,如果您确实需要setter,您可以将volatile
添加到thing
字段,或者将其标记为final并在构造函数中初始化。确保满足2的最简单方法是将use
标记为synchronized
。如果将setThing
标记为synchronized
,则不再需要volatile
。然而,还有许多其他复杂的技术可以满足第2点的要求。这本好书更详细地描述了这里写的所有内容。第二个线程可能会看到新的值,也可能看不到。如果它确实看到了它,它可能还没有完全构建好。取决于Thing
的线程安全性。Thing
在您的示例中永远不会为空,因为变量赋值在Java中是原子的(除了long和double)。但是,在thread2将旧对象设置为新值后,thread1仍可能使用旧对象。将事物声明为volatile以避免这种情况。thread1将始终使用相同的方法完成函数()
方法的执行-Object@rollback,你明确回答了我的问题,请随意回答。我会更新我的问题,因为你用好话表达了我无法表达的东西。任何文件都将不胜感激。
//Thread1
while(1) {
example.use();
}
//Thread2
while(1) {
sleep(3600000); //yes, i know to use a scheduled thread executor
setThing(new Thing());
}