11

少し助けてください、以下のコードを少し考えてみてください。

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のロックを取得しようとすることを読みました。

その理由を知りたいです。これは、doSomething()がsuper.doSomething()を呼び出すことをJVMが認識しているためか、サブクラスメソッドを呼び出すと常にスーパークラスのロックも取得されるためです。

乾杯

4

5 に答える 5

9

あなたは間違っています-ロックはインスタンスレベルで取得されます。次のように言うと作成されるインスタンスは1つだけなので、例にはロックが1つだけあります。

Widget w = new LoggingWidget

ロック(モニターミューテックス、またはセマフォとも呼ばれます)は、内のすべてのオブジェクトインスタンスに個別に「接続」されていると見なすことができますJVM

サブクラスに別のsynchronizedメソッドがある場合LoggingWidget、これが当てはまることがわかります。この(新しい)メソッドとdoSomethingメソッドを同時に呼び出すことはできません[同じオブジェクトの異なるスレッドで]。

synchronizedこれは、スーパークラスの別のメソッドにも当てはまります(つまり、オーバーライドされるメソッドの影響を受けません)。

于 2009-07-09T15:40:54.723 に答える
5
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() が呼び出されると、そのインスタンスはすでにロックされています。

于 2009-07-09T15:46:56.990 に答える
1

再入可能性は、最初にロックを取得することによって機能します。1 つのスレッドがロックを取得すると、それは jvm で認識されます。現在ロックを保持しているスレッドと同期しているコードのブロックに入ると、ロックを再取得することなく続行できます。次に、jvm は、再入可能なアクションごとにカウンターを増やし、そのブロックを終了すると、カウントがゼロになるまでさらに減少します。カウントがゼロになると、ロックが解除されます。

于 2009-07-09T22:33:49.367 に答える
1

ロックを取得するインスタンスは の 1 つだけでありLoggingWidget、 の実際のインスタンスはありませんWidget

呼び出し時にロックが取得され、そのメソッドLoggingWidget.doSomething()を呼び出したときに既にロックを取得しているためsuper.doSomething()、通常どおり実行されます。

于 2009-07-09T15:43:09.850 に答える
0

B.Goetz-「JJavaConcurrencyinPractice」固有のロックが再入可能でない場合、super.doSomethingの呼び出しは、すでに保持されていると見なされるため、ロックを取得できず、スレッドはロックを待機して永続的に停止します。取得することはできません。再入可能性は、このような状況でのデッドロックから私たちを救います。

于 2009-07-10T11:49:56.187 に答える