关于可见性的Java并发问题

时间:2012-12-17 09:16:58

标签: java multithreading

我读到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,而lockthread1获取,现在在{{{ 1}}释放thread1。现在可见性是所有其他线程都会读取对lock的更改?即将obj块内的每个更改都可见吗?或者我应该将C对象更改为synchronized以使其对其他人可见?

5 个答案:

答案 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不处于不一致状态(由程序员定义)。

在您的特定示例中,它看起来足够一致。