2010-07-13 11 views
7

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) 

Répondre

4

J'ai posé la même question sur la liste de diffusion hotspot-dev et reçu une réponse très Goot de Christopher Phillips:


Salut Eduard

Je pense que la décharge de fil qui est trompeur .

Si vous pensez vraiment que les 2 sont dans le verrou simultanément, vous devriez probablement obtenir un gcore (qui est cohérent à l'extérieur).

L'état que vous voyez « en attente pour l'entrée du moniteur » est en fait MONITOR_WAIT qui peut représenter le code suivant avant l'acquisition effective d'un verrouillage à chaud: (voir aussi OSThreadContendState dans osThread.hpp) appelé à partir de: src/share/vm/runtime/synchroniseur.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

1

Comment le vidage a-t-il été effectué? Si les threads n'ont pas été suspendus, la propriété du verrou pourrait avoir changé entre le vidage d'un thread et le suivant.

+0

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. –

+0

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. –

+0

Ce site affirme que tous les threads sont en pause: http://expertodev.wordpress.com/2009/05/30/how-to-take-java-thread-dump/ –

0

Je pense que l'information pertinente est: "en attente de l'entrée du moniteur", qui est la même pour les deux threads. Étant donné que les deux threads (dans le vidage de thread) sont marqués deamon threads, je suppose qu'il doit également y avoir un thread principal en cours d'exécution en même temps. Est-il possible que le thread principal soit le propriétaire actuel du moniteur qui bloque les deux autres threads?

+0

Non, le thread principal ne fait rien. Même si le thread principal maintient le verrou, la spécification ne fait pas la distinction entre les threads principal et deamon. Un seul thread est autorisé à posséder un verrou. –

+0

Je suis d'accord, un seul thread est autorisé à obtenir le verrou et à entrer dans la section critique (selon les spécifications). Les deux threads deamon * attendent * le verrou, comme indiqué dans le vidage de thread. Etes-vous sûr, il n'y a pas d'autre thread tenant actuellement le verrou? – Javaguru

+0

Les deux threads http-8080-136 et http-8080-111 maintiennent le verrou. Il y a 44 autres threads dans le vidage de thread "en attente" pour le verrou. –

0

Ils n'ont pas acquis de verrou, sinon vous verriez xsMethodA ou xsMethodB dans une pile.

+0

Alors, pourquoi y a-t-il une différence entre les threads http-8080-111 et http-8080-146? –

+0

Et: ThreadDumpAnalyzer répertorie les deux threads (http-8080-136, http-8080-111) comme "locked by". –

+0

Je veux dire que le titre "synchronized ne bloque pas" est faux. Peut-être voulez-vous dire "blocs de blocs synchronisés lorsque personne ne détient le verrou"? –