[英]Java concurrency issue about visibility
我读到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
,现在经过thread1
解除lock
。 现在可见性是所有其他线程都会读取对obj
的更改? 即, synchronized
块内的每个变化都可见? 或者我应该将C对象更改为volatile
以使其对其他人可见?
使obj
volatile
将使C对象的引用变为volatile
。 即在同步块外可见。 它不会影响该对象的成员。
即对另一个线程可以看到对obj的重新分配。 重新分配给其成员不会。
在synchronized块内部的每一个变化都是可见的吗?
是的,这是个主意。 JLS 17.45定义发生在关系之前。 尤其是:
监视器上的解锁发生在该监视器上的每个后续锁定之前。
因此,当thread2获取锁时,您可以保证在保持同一个锁时它将看到thread1所做的更改。
我应该将C对象更改为volatile以使其对其他人可见吗?
volatile保证如果你写: obj = new C();
在某个地方,随后读取obj
会看到它现在指的是一个新对象。 但是,它没有对obj的“内容”提供任何此类保证。 所以如果你写: obj.x = someValue;
,如果obj是易变的,那么您无法保证更改对另一个线程可见。 除非你让x
易变。
现在可见性是所有其他线程都会读取对obj的更改?
只有该锁定的同步块内的线程。
在synchronized块内部的每一个变化都是可见的吗?
只是可能。 对于保证可见性,线程必须位于同步块内。
或者我应该将C对象更改为volatile?
如果你没有同步并且在这里没有任何区别,那将无济于事。 volatile
只会改变obj
引用的行为,而不是它的字段。
不,访问obj
字段仍然不是线程安全的。 锁对象上的同步仅允许您通过线程安全操作将值写入此块中的obj
字段。
UPD :对obj
volatile
不会帮助你,因为你不会改变这个字段自己的参考值。
要回答你的问题,另一种方法可以简单地让你访问变量obj,也没有锁。 您必须确保的是,必须通过锁定小心地保护对obj的所有访问,以便obj不处于不一致状态(由程序员定义)。
在您的特定示例中,它看起来足够一致。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.