代码之家  ›  专栏  ›  技术社区  ›  CaptainHastings

重入式锁定

  •  11
  • CaptainHastings  · 技术社区  · 16 年前

    有点帮助,请考虑下面的代码。

    public class Widget {
        public synchronized void doSomething() {
            ...
        }
    }
    
    public class LoggingWidget extends Widget {
        public synchronized void doSomething() {
            System.out.println(toString() + ": calling doSomething");
            super.doSomething();
        }
    }
    

    我读到当调用loggingwidget中的dosomething()时,JVM将首先尝试获取loggingwidget上的锁,然后再获取widget上的锁。

    我很想知道原因。是因为jvm知道dosomething()调用了super.dosomething(),还是因为调用子类方法总是会获取超类上的锁。

    干杯

    5 回复  |  直到 16 年前
        1
  •  9
  •   Hrishikesh Mishra    10 年前

    你错了-锁是在 实例 水平。示例中只有一个锁,因为当您说:

    Widget w = new LoggingWidget
    

    您可以查看锁(也称为 监测器 , 互斥器 信号量 )单独“附加”到 JVM .

    如果你有另一个 synchronized 方法在 LoggingWidget 子类,您会看到这是真的。无法调用此(新)方法和 doSomething 同时使用方法[在同一对象上使用不同的线程]。

    这也适用于另一个 同步的 超类上的方法(即被重写的方法不会以任何方式影响它)。

        2
  •  5
  •   bajafresh4life    16 年前
    public synchronized void doSomething() {
        System.out.println(toString() + ": calling doSomething");
        super.doSomething();
    }
    

    相同:

    public void doSomething() {
        synchronized (this) {
            System.out.println(toString() + ": calling doSomething");
            super.doSomething();
        }
    }
    

    您锁定的是实例,而不是类。所以当调用super.dosomething()时,您已经锁定了该实例。

        3
  •  1
  •   Nick Holt    16 年前

    只有一个实例可以获取锁,即 LoggingWidget ,从来没有实际的 Widget .

    当你呼叫时获得锁 LoggingWidget.doSomething() 当你打电话的时候你已经有锁了 super.doSomething() 该方法正常执行。

        4
  •  0
  •   John    16 年前

    重入是通过首先获取锁来工作的。当一个线程获得锁时,它在JVM中是已知的。当输入与当前持有锁的线程同步的代码块时,允许它们继续执行而不重新获取锁。然后,JVM会增加每个可重入操作的计数器,当退出该块时,计数器会进一步减少,直到计数为零。当计数为零时,锁被释放。

        5
  •  0
  •   Ovidiu Lupas    16 年前

    B.Goetz-“JJava实践中的并发性”如果内部锁不可重入,则对super.dosomething的调用将永远无法获取锁,因为它将被视为已被持有,并且线程将永久停止,等待它永远无法获取的锁。在这种情况下,重入可以避免死锁。