J'ai remarqué quelque chose de très étrange hier. Il semble que deux threads entrent deux blocs synchronisés bloquant sur le même objet en même temps.section synchronisée ne bloque pas!
La classe (MyClass
) contenant le code correspondant ressemble à ceci:
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);
}
}
J'ai créé une décharge de fil de mon application en cours d'exécution de la classe au-dessus et a été très surpris que j'ai vu ceci:
"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)
...
(j'ai changé les noms de classe et de méthode pour le cas de la simplicité, donc ne pas confondre les noms stupides.)
Il semble que Thr ead http-8080-136 et http-8080-111 ont tous deux acquis le verrou myLock
. C'est le même objet car l'adresse de l'objet est la même: 0x00007fd8a6b8c790
. Java Runtime Specification dit ceci au sujet du mot-clé synchronized
:
Une déclaration synchronisée acquiert un verrou d'exclusion mutuelle (§17.1) au nom du fil d'exécution, exécute un bloc, puis libère le verrou. Alors que le thread en cours d'exécution possède le verrou, aucun autre thread ne peut acquérir le verrou. [The Java Language Specification, 14.19]
Alors, comment est-ce encore possible?
Il y a 44 autres threads dans le vidage de thread "en attente" pour le verrou. Voici à quoi cela ressemble si un thread est en attente:
"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)
En envoyant le signal QUIT au processus. Je ne sais pas comment la machine virtuelle Sun agit pendant le vidage de thread. Mais je suppose que le processus est arrêté. Sinon, vous obtiendrez un vidage de thread incohérent. –
Je sais que pour IBM JVM, ce n'est pas nécessairement vrai, mais je ne suis pas sûr de Sun, cependant, certainement quelque chose à garder à l'esprit. –
Ce site affirme que tous les threads sont en pause: http://expertodev.wordpress.com/2009/05/30/how-to-take-java-thread-dump/ –