recursos - Detección programática de interbloqueo en java
programacion concurrente java ejemplos (9)
¿Cómo puedo detectar mediante programación que se ha producido un interbloqueo en un programa Java?
Aquí hay un código: http://www.java2s.com/Code/Java/Development-Class/PerformingdeadlockdetectionprogrammaticallywithintheapplicationusingthejavalangmanagementAPI.htm
La magia sucede en 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;
}
Esto llama a una API de ThreadMXBean
que tiene un nombre diferente en Java 5 y 6 (por lo tanto, el externo if()
).
El ejemplo de código también permite interrumpir los bloqueos, por lo que incluso puede romper el punto muerto.
En caso de que quiera que se haga en tiempo de ejecución, puede usar el watchdog para eso.
Es posible que desee considerar MTRAT de IBM . La prevención es mejor que curar después de todo. El kit de desarrollo de software multinúcleo también viene con una herramienta de detección de interbloqueo.
Puede detectar las hebras bloqueadas mediante programación utilizando la clase ThreadMXBean. Aquí está el código,
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 string 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");
}
Haga clic here para obtener más información sobre cómo detectar los subprocesos bloqueados.
Si no necesita detección programática, puede hacerlo a través de JConsole ; En la pestaña de hilo hay un botón "detectar interbloqueo". En JDK6, esto detecta bloqueos tanto para monitores intrínsecos como para bloqueos juc
Ejecute el JConsole mediante el comando $JAVA_HOM/bin/jconsole
Una sugerencia útil para la investigación:
Si puede detectar la aplicación con la mano roja y sospecha que se ha producido un bloqueo, vaya y presione "Ctrl-Break" en la ventana de la consola java.exe (o "Ctrl- /" en Solaris / Linux). El jvm volcará el estado actual y el seguimiento de la pila de todos los subprocesos, descubrirá los bloqueos muertos y los describirá con precisión.
Se verá algo como esto:
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)
...
tempus-fugit también lo implementa junto con una clase de volcado de hilos programática. Se implementa utilizando el mecanismo mbean mencionado anteriormente y ofrece una solución súper duper lista para usar y para usar.
JArmus es una biblioteca para la detección y evitación de puntos muertos. Incluye soporte para: Thread.join
, CyclicBarrier
, CyclicBarrier
, Phaser
y ReentrantLock
.
Para usar JArmus necesitas instrumentar tu código. Ya sea a través de una de sus clases instrumentadas o automáticamente con JArmus instrumentar jarmusc
.
java -jar jarmusc.jar yourprogram.jar checkedprogram.jar
La entrada yourprogram.jar
es el programa que desea verificar. La salida es el mismo programa con verificaciones para encontrar automáticamente cualquier punto muerto.
Las barreras necesitan ayuda.
La verificación de puntos muertos con las clases CyclicBarrier
, CyclicBarrier
, Phaser
es un poco difícil --- por ejemplo, JConsole no puede detectar estos tipos de puntos muertos. JArmus necesita una pequeña ayuda de usted: debe especificar qué subprocesos influyen en la sincronización, llamamos a estos subprocesos registrados .
Tan pronto como sea posible, el hilo debe marcarse como registrado. Un buen lugar para marcar los hilos registrados es el método Runnable.run
. JArmus.register(latch);
Ejemplo
El siguiente programa que los puntos muertos está correctamente identificado por JArmus:
final CountDownLatch latch = new CountDownLatch(2);
final CyclicBarrier barrier = new CyclicBarrier(2);
final Queue<Exception> 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();
Puede hacer esto mediante programación utilizando el ThreadMXBean
que se envía con el 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.
}
}
Obviamente, debe intentar aislar el hilo que realiza esta comprobación de interbloqueo. De lo contrario, si ese subproceso no se bloquea, no podrá ejecutar la comprobación.
Por cierto, esto es lo que JConsole está usando debajo de las cubiertas.