2010-07-13 3 views
7

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

Класс (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) 
    ... 

(я изменил имена классов и методов для случая простоты, так что не пугайтесь глупыми именами.)

кажется, что THR ead http-8080-136 и http-8080-111 оба приобрели замок на myLock. Это тот же объект, что и адрес объекта: 0x00007fd8a6b8c790. Время выполнения спецификация Java говорит, что это о synchronized ключевом слове:

Синхронного оператор получает блокировку взаимного исключения (§17.1) от имени выполняющегося потока, выполняет блок, затем освобождает замок. Пока исполняющий поток владеет блокировкой, никакая другая нить не может получить блокировку. [The Java Language Specification, 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

Я задал тот же самый вопрос в списке горячих точек-DEV рассылки и получил очень Goot ответ от Кристофера Филлипса:


Здравствуйте Эдуард

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

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

состояния вы видите «в ожидании входа монитора» на самом деле MONITOR_WAIT, который может представлять собой следующий код перед фактическим приобретением горячего замка: (также см OSThreadContendState в osThread.hpp) вызывается из: ЦСИ/доля/Vm/выполнения/синхронизатор.каст

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

1

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

+0

Посылая QUIT сигнал процессу. Я не знаю, как работает Sun VM во время дампа потока. Но я предполагаю, что процесс остановлен. В противном случае вы получите непоследовательный дамп потока. –

+0

Я знаю, что для IBM JVM это не обязательно так, но не уверен в SUN, однако, определенно, что-то нужно иметь в виду. –

+0

Этот сайт утверждает, что все потоки приостановлены: http://expertodev.wordpress.com/2009/05/30/how-to-take-java-thread-dump/ –

0

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

+0

Нет, основной поток ничего не делает. Даже если основной поток будет удерживать замок, в спецификации не проводится различие между основными и деамонными потоками. Только одному потоку разрешено владеть замком. –

+0

Согласен, только один поток может получить блокировку и войти в критический раздел (согласно спецификации). Оба деамоновых нити * ждут * для блокировки, как указано в дампе потока. Вы уверены, что в настоящее время нет другой ветки, удерживающей замок? – Javaguru

+0

Два потока http-8080-136 и http-8080-111 удерживают замок. Есть еще 44 потока в дампе потока «ожидание» для блокировки. –

0

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

+0

Так почему же существует разница между потоками http-8080-111 и http-8080-146? –

+0

И: ThreadDumpAnalyzer отображает оба потока (http-8080-136, http-8080-111) как «заблокированные». –

+0

Я имею в виду, что заголовок «synchronized not not block» неверен. Может быть, вы имеете в виду «синхронизированные блоки блоки, когда никто не держит блокировку»? –

Смежные вопросы