Вчера я заметил что-то очень странное. Кажется, что два потока одновременно вставляют два синхронизированных блока на один и тот же объект.синхронизированный раздел не блокируется!
Класс (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)
Посылая QUIT сигнал процессу. Я не знаю, как работает Sun VM во время дампа потока. Но я предполагаю, что процесс остановлен. В противном случае вы получите непоследовательный дамп потока. –
Я знаю, что для IBM JVM это не обязательно так, но не уверен в SUN, однако, определенно, что-то нужно иметь в виду. –
Этот сайт утверждает, что все потоки приостановлены: http://expertodev.wordpress.com/2009/05/30/how-to-take-java-thread-dump/ –