Java &引用;已同步(此)“;vs.“;已同步((基类)this)";在爪哇?

Java &引用;已同步(此)“;vs.“;已同步((基类)this)";在爪哇?,java,multithreading,synchronization,Java,Multithreading,Synchronization,这是我上一个问题的后续问题 对于以下节目 Class SubClassB extends SuperClassA { protected int c; public void inc() { synchronized (this) { c++; } } public void dec() { synchronized ( (SuperClassA) this) {

这是我上一个问题的后续问题

对于以下节目

Class SubClassB extends SuperClassA {
     protected int c;

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

     public void dec() {
          synchronized ( (SuperClassA) this) {
               c--;
          }
     }
}
计数器“c”是线程安全访问的吗?我不确定在“dec()”方法中,超类强制转换“this”引用是否是同步块的有效对象?如果是,两个同步块会锁定同一个“this”对象吗?(在我看来“(超类)this”不等于“this”)

这个奇怪的模拟代码来自下面的真实示例,其中超类是一个不应该修改的基类

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();
     }
}
在本例中,子类B中的“dec()”方法调用其超类的“dec()”方法,该方法执行对“this”对象的锁定,我假定该对象为“SuperClassA.this”。如果子类B的“inc()”方法中的锁定对象与子类B的“dec()”方法中的锁定对象不完全相同,那么我想知道子类B中继承的计数器“c”可能无法被不同的线程安全访问。我觉得在同步块中使用“this”引用存在一些歧义

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

Class SubClassB extends SuperClassA {

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

     public void dec() {
          synchronized (this) {
               super.dec();
          }
     }
}
但这样添加的块似乎并不优雅,可能是多余的

有人对这些问题有什么看法吗。提前谢谢


劳伦斯

就同步而言,这三个例子都是正确的

  • 只有一个监视器与任何对象关联
  • this
    强制转换为
    synchronized
    中的基类没有任何区别
  • 对于同一个对象,在派生类或基类的上下文中调用
    synchronized(this)
    并不重要:在这两种情况下使用相同的锁

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

    不过,该代码缺乏封装,因为它允许任何子类以非同步方式访问受保护的
    c
    字段。因此,任何子类都可以使用
    c++
    c--
    而不进行任何同步。这个领域应该是私有的

    在我看来“(超类)this”不等于“this”

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

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

    计数器“c”是线程安全访问的吗

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

    我不确定在“dec()”方法中,超类强制转换“this”引用是否是同步块的有效对象

    如果是,两个同步块会锁定同一个“this”对象吗?(在我看来“(超类)this”不等于“this”)

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

    […]但似乎这样添加的块并不优雅,可能是多余的


    这是多余的。只有在调用多个同步方法且组合效果必须是原子的情况下,才需要额外的同步。

    感谢您提醒我计数器“c”应声明为“私有”。现在我知道“(超级类)this”和“this”具有不同的编译时类型,但在同步块中持有相同的锁。感谢您的快速响应,并提醒我任何对象只有一个监视器。