синхронизируемый раздел не блокируется!

Вчера я заметил что-то очень странное. Кажется, что два потока вводят два синхронизируемых блока, соединяющие тот же объект одновременно.

Класс (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 говорит это о 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)

7
задан Esko 14 July 2010 в 12:29
поделиться

4 ответа

Я задал тот же вопрос в списке рассылки hotspot-dev и получил очень интересный ответ от Кристофера Филлипса:


Привет Эдуард

Я думаю, что дамп потока вводит в заблуждение.

Если вы действительно думаете, что эти 2 потока находятся в блокировке одновременно, вам, вероятно, следует получить gcore (который является внешне последовательным).

Состояние, которое вы видите "ожидание входа в монитор", на самом деле MONITOR_WAIT, которое может представлять следующий код перед фактическим получением горячей блокировки: (также см. OSThreadContendState в osThread.hpp), вызываемый из: 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.

Chris

4
ответ дан 7 December 2019 в 12:14
поделиться

Как был сделан дамп потока? Если бы потоки не были приостановлены, владение блокировкой могло измениться между сбросом одного потока на другой.

1
ответ дан 7 December 2019 в 12:14
поделиться

Я думаю, что важная информация такова: «ожидание записи монитора», что одинаково для обоих потоков. Поскольку оба потока (в дампе потока) помечены как потоки deamon, я предполагаю, что одновременно должен быть запущен основной поток. Возможно ли, что основной поток является текущим владельцем монитора, который блокирует два других потока?

0
ответ дан 7 December 2019 в 12:14
поделиться

Они не получили блокировку, иначе вы увидите xsMethodA или xsMethodB в трассировке стека.

0
ответ дан 7 December 2019 в 12:14
поделиться