繁体   English   中英

关于可见性的Java并发问题

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM