Détection programmatique des interblocages en Java

Comment puis-je détecter par programme qu’un blocage s’est produit dans un programme Java?

Vous pouvez le faire par programmation en utilisant le ThreadMXBean avec le JDK:

 ThreadMXBean bean = ManagementFactory.getThreadMXBean(); long[] threadIds = bean.findDeadlockedThreads(); // Returns null if no threads are deadlocked. if (threadIds != null) { ThreadInfo[] infos = bean.getThreadInfo(threadIds); for (ThreadInfo info : infos) { StackTraceElement[] stack = info.getStackTrace(); // Log or store stack trace information. } } 

Évidemment, vous devriez essayer d’isoler le thread qui effectue cette vérification d’interblocage – Sinon, si ce thread est bloqué, il ne pourra pas exécuter la vérification!

C’est d’ailleurs ce que JConsole utilise sous les couvertures.

Un indice utile pour l’enquête:

Si vous pouvez attraper l’application rouge et soupçonner un blocage, appuyez sur “Ctrl-Break” dans la fenêtre de la console java.exe (ou “Ctrl-\” sur Solaris / Linux). Le JVM videra le statut actuel et la trace de la stack de tous les threads, découvrira les verrous morts et les décrira avec précision.

Cela ressemblera à ceci:

 Full thread dump Java HotSpot(TM) Client VM (1.5.0_09-b03 mixed mode): "[Test Timer] Request Queue" prio=6 tid=0x13d708d0 nid=0x1ec in Object. wait() [0x1b00f000..0x1b00fb68] at java.lang.Object.wait(Native Method) at java.lang.Object.wait(Unknown Source) at library.util.AsyncQueue.run(AsyncQueue.java:138) - locked <0x02e70000> (a test.server.scheduler.SchedulerRequestQueue) ... Found one Java-level deadlock: ============================= "Corba service": waiting to lock monitor 0x13c06684 (object 0x04697d90, a java.lang.Object), which is held by "[Server Connection] Heartbeat Timer" "[Server Connection] Heartbeat Timer": waiting to lock monitor 0x13c065c4 (object 0x0467e728, a test.proxy.ServerProxy), which is held by "Corba service" Java stack information for the threads listed above: =================================================== "Corba service": at test.proxy.ServerProxy.stopHBWatchDog(ServerProxy:695) - waiting to lock <0x04697d90> (a java.lang.Object) ... 

JArmus est une bibliothèque pour la détection et l’évitement des interblocages. Il inclut la prise en charge de: Thread.join , CyclicBarrier , CountDownLatch , Phaser et ReentrantLock .

Pour utiliser JArmus, vous devez instrumenter votre code. Soit par l’une de ses classes instrumentées ou automatiquement avec le Jarmmus instrumentar jarmusc .

java -jar jarmusc.jar yourprogram.jar checkedprogram.jar

L’entrée yourprogram.jar est le programme que vous voulez vérifier. La sortie est le même programme avec des contrôles pour trouver automatiquement tout blocage.

Les obstacles ont besoin d’aide

Vérification des blocages avec les classes CyclicBarrier , CountDownLatch , Phaser est un peu difficile — par exemple, JConsole ne peut pas détecter ces types de blocages. JArmus a besoin d’un peu d’aide de votre part: vous devez spécifier quels threads influencent la synchronisation, nous appelons ces threads enregistrés .

Dès que possible, le thread doit se marquer comme enregistré. Un bon endroit pour marquer les threads enregistrés est la méthode de départ Runnable.run . JArmus.register(latch);

Exemple

Le programme suivant que Deadlocks est correctement identifié par JArmus:

 final CountDownLatch latch = new CountDownLatch(2); final CyclicBarrier barrier = new CyclicBarrier(2); final Queue exceptions = new ArrayDeque<>(); Thread t1 = new Thread(new Runnable() { @Override public void run() { try { JArmus.register(barrier); // do not forget to register! JArmus.register(latch); // do not forget to register! latch.countDown(); latch.await(); barrier.await(); } catch (Exception e) { exceptions.add(e); } } }); Thread t2 = new Thread(new Runnable() { @Override public void run() { try { JArmus.register(barrier); // do not forget to register! JArmus.register(latch); // do not forget to register! barrier.await(); latch.countDown(); latch.await(); } catch (Exception e) { exceptions.add(e); } } }); t1.start(); t2.start(); 

Vous pourriez vouloir considérer le MTRAT d’IBM . Mieux vaut prévenir que guérir après tout. Le kit de développement logiciel Multicore est également fourni avec un outil de détection de blocage.

Si vous n’avez pas besoin de détection par programmation, vous pouvez le faire via le JConsole . sur l’onglet thread, il y a un bouton “détecter le blocage”. Dans JDK6, cela détecte les verrous pour les deux moniteurs insortingnsèques et juc Lock

Exécutez le JConsole via la commande $JAVA_HOM/bin/jconsole

Vous pouvez détecter les threads bloqués par programmation en utilisant la classe ThreadMXBean. Voici le code,

  ThreadMXBean bean = ManagementFactory.getThreadMXBean(); long ids[] = bean.findMonitorDeadlockedThreads(); if(ids != null) { ThreadInfo threadInfo[] = bean.getThreadInfo(ids); for (ThreadInfo threadInfo1 : threadInfo) { System.out.println(threadInfo1.getThreadId()); //Prints the ID of deadlocked thread System.out.println(threadInfo1.getThreadName()); //Prints the name of deadlocked thread System.out.println(threadInfo1.getLockName()); //Prints the ssortingng representation of an object for which thread has entered into deadlock. System.out.println(threadInfo1.getLockOwnerId()); //Prints the ID of thread which currently owns the object lock System.out.println(threadInfo1.getLockOwnerName()); //Prints name of the thread which currently owns the object lock. } } else { System.out.println("No Deadlocked Threads"); } 

Cliquez ici pour plus d’informations sur la façon de détecter les threads bloqués.

Il y a du code ici: http://www.java2s.com/Code/Java/Development-Class/PerformingdeadlockdetectionprogrammaticallywithintheapplicationusingthejavalangmanagementAPI.htm

La magie se produit dans ThreadMonitor.findDeadlock() :

  public boolean findDeadlock() { long[] tids; if (findDeadlocksMethodName.equals("findDeadlockedThreads") && tmbean.isSynchronizerUsageSupported()) { tids = tmbean.findDeadlockedThreads(); if (tids == null) { return false; } System.out.println("Deadlock found :-"); ThreadInfo[] infos = tmbean.getThreadInfo(tids, true, true); for (ThreadInfo ti : infos) { printThreadInfo(ti); printLockInfo(ti.getLockedSynchronizers()); System.out.println(); } } else { tids = tmbean.findMonitorDeadlockedThreads(); if (tids == null) { return false; } ThreadInfo[] infos = tmbean.getThreadInfo(tids, Integer.MAX_VALUE); for (ThreadInfo ti : infos) { // print thread information printThreadInfo(ti); } } return true; } 

Cela appelle une API de ThreadMXBean qui a un nom différent en Java 5 et 6 (d’où le nom externe if() ).

L’exemple de code permet également d’interrompre les verrous, vous permettant même de sortir de l’impasse.

tempus-fugit l’ implémente également avec une classe de suppression de threads programmatique. Il est implémenté en utilisant le mécanisme de mbean mentionné ci-dessus et offre une solution de super duper prête à l’emploi.

Si vous voulez que cela soit fait au moment de l’exécution, vous pouvez utiliser watchdog pour cela.