Ho notato qualcosa di molto strano ieri. Sembra che due thread inseriscano contemporaneamente due blocchi sincronizzati che si bloccano sullo stesso oggetto.La sezione sincronizzata non blocca!
La classe (MyClass
) contenente il codice in questione è simile a questo:
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);
}
}
ho creato una discarica filo della mia applicazione in esecuzione la classe superiore e sono rimasto molto sorpreso come ho visto questo:
"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)
...
(i cambiato i nomi delle classi e il metodo per il caso di semplicità, in modo da non confondersi con i nomi stupidi.)
sembra che thr ead http-8080-136 e http-8080-111 hanno entrambi acquisito il blocco su myLock
. È lo stesso oggetto in cui l'indirizzo dell'oggetto è lo stesso: 0x00007fd8a6b8c790
. Il Java Runtime Specification dice questo circa la parola synchronized
:
Una dichiarazione sincronizzato acquisisce un blocco mutua esclusione (§17.1) per conto del thread in esecuzione, esegue un blocco, quindi rilascia il blocco. Mentre il thread in esecuzione possiede il blocco, nessun altro thread può acquisire il blocco. [The Java Language Specification, 14.19]
Così come è questo possibile?
Ci sono altri 44 thread nel dump di thread "in attesa" per il blocco. Ecco come appare se un thread è in attesa:
"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)
Inviando il segnale QUIT al processo. Non so come agisce Sun VM durante il dump del thread. Ma suppongo che il processo sia fermato. Altrimenti si otterrebbe un dump discontinuo del thread. –
So per IBM JVM questo non è necessariamente vero, non sono sicuro di SUN, tuttavia, sicuramente qualcosa da tenere a mente. –
Questo sito dichiara che tutti i thread sono in pausa: http://expertodev.wordpress.com/2009/05/30/how-to-take-java-thread-dump/ –