我读到synchronized
方法或块提供了两个功能:“互斥”和“可见性”。我想知道两件事。
public class A{
private final Object lock = new Object();
private C obj = new C();
public void methodA(){
synchronized(lock){
obj.x = 1;
obj.y=3;
}
}
public void methodB(C obj2){
synchronized(lock){
obj2.x = obj.x;
}
}
}
假设我们有2个线程在methodA
类型的全局共享对象上调用A
,而lock
由thread1
获取,现在在{{{ 1}}释放thread1
。现在可见性是所有其他线程都会读取对lock
的更改?即将obj
块内的每个更改都可见吗?或者我应该将C对象更改为synchronized
以使其对其他人可见?
答案 0 :(得分:2)
制作obj
volatile
会将引用设为C对象volatile
。即在同步块外可见。它不会影响该对象的成员。
即。对另一个线程可以看到对obj的重新分配。重新分配给其成员不会。
答案 1 :(得分:1)
同步块内部的每个变化都是可见的吗?
是的,这个想法。 JLS 17.45定义发生在关系之前。特别是:
监视器上的解锁发生在该监视器上的每次后续锁定之前。
因此,当thread2获得锁定时,您可以保证在持有相同锁定时它将看到thread1所做的更改。
我应该将C对象更改为volatile以使其对其他人可见吗?
volatile保证如果你在某处写{:1}},随后读obj = new C();
会看到它现在引用一个新对象。但是,对于内容和#34;它没有提供任何此类保证。对象因此,如果你写道:obj
,obj是易变的,你就不能保证更改对其他线程可见。除非你使obj.x = someValue;
变得不稳定。
答案 2 :(得分:1)
现在可见性是所有其他线程都会读取对obj的更改?
仅锁定同步块内的线程。
同步块内部的每个变化都是可见的吗?
只有可能。对于保证可见性,线程必须位于同步块内。
或者我应该将C对象更改为volatile?
如果您没有同步,这将无济于事,并且不会在此处产生任何影响。 volatile
只会更改obj
引用的行为,而不会改变其字段。
答案 3 :(得分:0)
不,访问obj
字段仍然不是线程安全的。锁对象上的同步只允许您通过线程安全操作将值写入此块中的obj
字段。
UPD :volatile
的{{1}}对您没有帮助,因为您不会更改此字段自己的参考值。
答案 4 :(得分:0)
要回答你的问题,另一种方法可以简单地让你访问变量obj,而不需要锁定。您必须确保的是,必须通过锁定小心地保护对obj的所有访问,以便obj不处于不一致状态(由程序员定义)。
在您的特定示例中,它看起来足够一致。