7

昨日、非常に奇妙なことに気づきました。2 つのスレッドが、同じオブジェクトをロックしている 2 つの同期ブロックに同時に入っているようです。

関連するコードを含むクラス ( MyClass) は次のようになります。

private static int[]    myLock  = new int[0];

protected static int methodA(final long handle, final byte[] sort) {
    synchronized (myLock) {
        return xsMethodA(handle, sort);
    }
}

protected static int methodB(final long handle) {
    synchronized (myLock) {
        return xsMethodB(handle);
    }
}

上記のクラスを実行しているアプリケーションのスレッド ダンプを作成しましたが、これを見て非常に驚きました。

"http-8080-136" daemon prio=10 tid=0x00000000447df000 nid=0x70ed waiting for monitor entry [0x00007fd862aea000]
   java.lang.Thread.State: BLOCKED (on object monitor)
    at com.MyClass.methodA(MyClass.java:750)
    - locked <0x00007fd8a6b8c790> (a [I)
    at com.SomeOtherClass.otherMethod(SomeOtherClass.java:226)
    ...

"http-8080-111" daemon prio=10 tid=0x00007fd87d1a0000 nid=0x70c8 waiting for monitor entry [0x00007fd86e15f000]
   java.lang.Thread.State: BLOCKED (on object monitor)
    at com.MyClass.methodB(MyClass.java:991)
    - locked <0x00007fd8a6b8c790> (a [I)
    at com.SomeOtherClass.yetAnotherMethod(SomeOtherClass.java:3231)
    ...

(単純にするためにクラスとメソッドの名前を変更したので、ばかげた名前に混乱しないでください。)

スレッド http-8080-136 と http-8080-111 の両方が のロックを取得したようmyLockです。これは、オブジェクト アドレスが同じであるため、同じオブジェクトです: 0x00007fd8a6b8c790. Java Runtime Specification は、synchronizedキーワードについて次のように述べています。

同期ステートメントは、実行中のスレッドに代わって相互排他ロック (§17.1) を取得し、ブロックを実行してからロックを解放します。実行中のスレッドがロックを所有している間、他のスレッドはロックを取得できません。[ Java 言語仕様、14.19 ]

では、これはどのようにして可能になるのでしょうか?

スレッド ダンプには、ロックを「待機中」の別の 44 のスレッドがあります。スレッドが待機中の場合は、次のようになります。

"http-8080-146" daemon prio=10 tid=0x00007fd786dab000 nid=0x184b waiting for monitor entry [0x00007fd8393b6000]
   java.lang.Thread.State: BLOCKED (on object monitor)
    at com.MyClass.methodC(MyClass.java:750)
    - waiting to lock <0x00007fd8a6b8c790> (a [I)
    at com.SomeOtherClass.yetAnoterMethod2(SomeOtherClass.java:226)
4

4 に答える 4

4

私はhotspot-devメーリングリストで同じ質問をし、クリストファーフィリップスから非常にばかげた答えを受け取りました:


こんにちはエドゥアルド

誤解を招くのはスレッドダンプだと思います。

2つが同時にロックされていると本当に思う場合は、おそらくgcore(外部的に整合性があります)を取得する必要があります。

「モニターエントリを待機中」と表示される状態は、実際にはMONITOR_WAITであり、ホットロックを実際に取得する前に次のコードを表すことができます:( osThread.hppのOSThreadContendStateも参照)から呼び出されます:src / share / vm / runtime / synchronizer.cpp

3413      OSThreadContendState osts(Self->osthread());
3414      ThreadBlockInVM tbivm(jt);
3415
3416      Self->set_current_pending_monitor(this);
3417
3418      // TODO-FIXME: change the following for(;;) loop to straight-line code.
3419      for (;;) {
3420        jt->set_suspend_equivalent();
3421        // cleared by handle_special_suspend_equivalent_condition()
3422        // or java_suspend_self()
3423
3424        EnterI (THREAD) ;
3425
3426        if (!ExitSuspendEquivalent(jt)) break ;
3427
3428        //
3429        // We have acquired the contended monitor, but while we were
3430        // waiting another thread suspended us. We don't want to enter
3431        // the monitor while suspended because that would surprise the
3432        // thread that suspended us.

クリス

于 2010-07-14T12:23:57.947 に答える
1

スレッド ダンプはどのように取得されましたか? スレッドが一時停止されていない場合、あるスレッドのダンプと次のスレッドのダンプの間にロックの所有権が変更された可能性があります。

于 2010-07-13T09:07:34.403 に答える
0

関連する情報は、「モニターのエントリを待機中」であると思います。これは、両方のスレッドで同じです。(スレッドダンプ内の)両方のスレッドがデーモンスレッドとしてマークされているので、同時に実行されているメインスレッドも存在する必要があると思います。メインスレッドが他の2つのスレッドをブロックする現在のモニター所有者である可能性はありますか?

于 2010-07-13T09:13:43.323 に答える
0

それらはロックを取得していません。それ以外の場合は、スタック トレースに xsMethodA または xsMethodB が表示されます。

于 2010-07-13T09:29:16.517 に答える