2010-11-07 32 views
1

J'ai un blocage très étrange dans une application Java qui utilise deux threads. Les deux threads lisent et écrivent des données sur un hashmap partagé. Pour éviter les problèmes de synchronisation j'ai fait les fonctions synchronisées lecture et d'écriture des données du hashmap:Strange Deadlock (?)

private synchronized boolean identifiedLinksHasKey(String linkKey){ 
     return Parser.identifiedLinks.containsKey(linkKey); 
} 


private synchronized void putToIdentifiedLinks(String key, TreeSet<String> aset){  
     Parser.identifiedLinks.put(key,aset); 
} 

Cependant, le programme se bloque à un moment donné (ce qui ne se produit pas quand je le lance avec un seul fil). Pour déboguer mon application je jstack après qu'il se bloque, ce qui m'a donné la décharge de fil suivant:

"Discussion-2" prio = 6 tid = 0x0000000006b09800 JNV = 0x78fc runnable [0x00000000083ef000]
java .lang.Thread.State: RUNNABLE à java.util.HashMap.put (source inconnue) à bgp.parser.Entry. putToIdentifiedLinks (Entry.java:297) - verrouillés < 0x00000000853f2020> (a bgp.parser.Entry) à bgp.parser.Entry.parseTxtFile (Entry.java:141) à bgp.parser.Entry.run (Entry.java:31)

"Thread-1" prio = 6 tid = 0x0000000006b52800 nid = 0x9390 runnable [0x00000000082ef000]
java.lang.Thread.State: rUNNABLE à java.util.HashMap.getEntry (Inconnu Source) at java.util.HashMap.containsKey (Inconnu Source) at bgp.parse r.Entry. identifiedLinksHasKey (Entry.java:281) - verrouillé < 0x00000000853f00e0> (a bgp.parser.Entry) à bgp.parser.Entry.parseTxtFile (Entry.java:134) à bgp.parser.Entry.run (Entry.java:31)

Il semble que les deux threads accèdent simultanément aux deux fonctions synchronisées ce qui contredit la signification de la synchronisation. La même situation se produit même si j'utilise des verrous d'objet. Bien que l'état des threads ne soit pas BLOQUÉ mais RUNNABLE, ils se comportent comme bloqués, probablement parce qu'ils accèdent à la même hashmap en même temps.

J'apprécierais vraiment si quelqu'un pourrait m'expliquer pourquoi cette situation étrange se produit.

+3

ce n'est pas un interblocage. S'il apparaît bloqué, vous avez un problème différent à portée de main. –

+0

c'est vrai, je ne savais pas comment le mettre. – Vasilis

Répondre

3

Le mot clé 'synchronized' se verrouille au niveau de l'objet. C'est-à-dire: Aucune méthode synchronisée ne peut être exécutée en même temps dans un objet.

Est-il possible que deux objets distincts soient appelés à partir des deux threads distincts?

modifier: en visitant la trace de la pile, je suis de plus en plus confiant que c'est effectivement le cas. Changez le code comme suit.

private boolean identifiedLinksHasKey(String linkKey){ 
     synchronized(Parser) { 
      return Parser.identifiedLinks.containsKey(linkKey); 
     } 
} 

private void putToIdentifiedLinks(String key, TreeSet<String> aset){  
    synchronized(Parser) {  
     Parser.identifiedLinks.put(key,aset); 
    } 
} 

Je n'ai pas essayé ce code moi-même, et je ne suis pas sûr à 100% que ce soit possible d'utiliser une classe (Parser) plutôt que d'un objet à verrouiller. Si cela ne fonctionne pas, choisissez simplement un objet (unique) accessible à partir des deux threads/instances.

+2

Utilisez 'Parser.class' (niveau de classe) ou' Parser.identifiedLinks' (niveau d'objet) pour synchroniser, ce dernier étant le meilleur dans le contexte donné imho. – rsp

+0

Merci pour la réponse. rsp l'a raffiné et en effet le Parser.identifiedLinks a fait le travail. Il semble que je n'avais pas une compréhension correcte des serrures jusqu'à maintenant. – Vasilis

0

Si Parser est une classe singleton ou un membre statique de la classe Entry, la synchronisation des méthodes ne fonctionnera pas car elle protège uniquement les variables membres de l'objet Entry. Les membres statiques ne seront pas protégés par ce système. Votre meilleur pari est probablement de faire du membre identifié de la classe Parser un ConcurrentHashMap.

7

comparer ces deux:

bgp.parser.Entry.putToIdentifiedLinks(Entry.java:297) - locked <0x00000000853f2020>
bgp.parser.Entry.identifiedLinksHasKey(Entry.java:281) - locked <0x00000000853f00e0>

Ils sont différents verrouillage de portefeuille. Le verrou de mot-clé synchronized sur l'objet instance. (Par exemple, si vous créez deux objets Object a=new Object();Object b=new Object();, le verrouillage du a en n'affectera pas b)

+0

+1, c'était mon bug en effet. Je viens d'accepter la solution de TumbleCow parce qu'elle était un peu plus détaillée. – Vasilis

1

Je soupçonne que le identifiedLinksHasKey() et les méthodes putToIdentifiedLinks() sont en cours d'exécution par deux instances différentes de la classe bgp.parser.Entry, auquel cas le synchronized ne fonctionnera pas.

0

Se pourrait-il que vous ayez impliqué des fichiers en tant qu'objets avec une identité unique garantie? Si vous comptez sur, par exemple, vous vous attendez à ce que l'objet, représentant le fichier est garanti globalement unique en mémoire. Cela fonctionnera jusqu'à ce que l'uniqness soit violée.

La violation dans uniqness peut provenir de l'API du système d'exploitation. Il est connu pour Windows (mais est rarement compris par les gens venant d'Unix par exemple), ce handle de fichier créé n'est pas le même handle de fichier que celui trouvé et ouvert par findFirst/findnext.

Considérer l'API de fichier dans le système d'exploitation comme une simple API de communication vers un système très distant sans garantie de cause et de conséquence. Si vous créez un fichier, cela ne signifie pas que vous pouvez le trouver immédiatement, si vous supprimez un fichier, cela peut signifier que vous le retrouverez peut-être par la suite.