“同步(this)”与“synchronized((BaseClass)this)”在Java中?

时间:2012-01-05 14:01:19

标签: java multithreading synchronization

这是我之前提问Is this variable being safely accessed by using synchronization?

的继承者

对于以下程序,

Class SubClassB extends SuperClassA {
     protected int c;

     public void inc() {
          synchronized (this) {
               c++;
          }
     }

     public void dec() {
          synchronized ( (SuperClassA) this) {
               c--;
          }
     }
}

计数器“c”是否可以访问线程安全?我不确定在“dec()”方法中,SuperClassA是否将“this”引用为synchronized块的有效对象?如果是,两个同步块是否会锁定相同的“this”对象? (在我看来,“(SuperClassA)这个”不等于“这个”)

这个奇怪的模拟代码来自以下现实生活中的例子,其中SuperClassA是一个不应被修改的基类,

Class SuperClassA {
     protected int c;

     public void dec() {
          synchronized (this) {
               c--;
          }
     }
}

Class SubClassB extends SuperClassA {

     public void inc() {
          synchronized (this) {
               c++;
          }
     }

     public void dec() {
          super.dec();
     }
}

在这个例子中,SubClassB中的“dec()”方法调用它的超类的“dec()”方法,该方法执行对“this”对象的锁定,我认为该对象是“SuperClassA.this”。如果SubClassB的“inc()”方法中的锁定对象与SubClassB的“dec()”方法中的锁定对象不完全相同,那么我想知道SubClassB中的继承计数器“c”可能不会被不同的线程安全地访问。我觉得在同步块中使用“this”引用有一些含糊之处。

在现实生活中的例子中,如果我希望SubClassB的计数器“c”是线程安全的,我是否需要在其“dec()”方法中再添加一个synchronized块,如下所示,

Class SubClassB extends SuperClassA {

     public void inc() {
          synchronized (this) {
               c++;
          }
     }

     public void dec() {
          synchronized (this) {
               super.dec();
          }
     }
}

但似乎这样的附加区块并不优雅,可能是多余的!

有没有人对这些问题有一些想法。提前谢谢。

劳伦斯

4 个答案:

答案 0 :(得分:6)

代码是线程安全的,因为(SomeObject) this adn this是同一个对象。强制转换不会将对象转换为另一个对象。

但是,代码缺少封装,因为它允许任何子类以不同步的方式访问受保护的c字段。因此,任何子类都可以使用c++c--而无需任何同步。该字段应该是私有的。

答案 1 :(得分:5)

  

计数器“c”是否可以访问线程安全?

是的,它使用相同的锁定对象。

  

我不确定在“dec()”方法中,SuperClassA是否将“this”引用为同步块的有效对象?

  

如果是,两个同步块是否会锁定相同的“this”对象? (在我看来,“(SuperClassA)这个”不等于“这个”)

是。即使你将实例转换为可以转换为(甚至是Object)的东西,它仍然会引用同一个对象。

  

[...]但似乎这样的附加区块并不优雅,可能是多余的!

这是多余的。仅当您调用多个同步方法并且组合效果必须是原子时才需要额外同步。

答案 2 :(得分:3)

  在我看来,“(SuperClassA)这个”不等于“这个”

错误;同步是在对象上完成的,而转换只会改变编译时类型,对对象标识没有影响。

因此,您不必在子类中添加额外的同步。

答案 3 :(得分:2)

就同步而言,所有三个例子都是正确的。

  1. 只有一台显示器与任何物体相关联。
  2. this投射到synchronized内的基类没有任何区别。
  3. 对于同一个对象,在派生类或基类的上下文中是否调用synchronized(this)并不重要:在两种情况下都使用相同的锁。