En analysant les billes de l'un des environnements de production, je vis un fil en « ATTENTE » état sur un CountDownLatch attendent()Fil bloqué sur CountDownLatch attendre() lorsque le nombre est 0
...sun.misc.Unsafe.park(Native Method)
...java.util.concurrent.locks.LockSupport.park(Unknown Source)
...java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(Unknown Source)
...java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireSharedInterruptibly(Unknown Source)
...java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireSharedInterruptibly(Unknown Source)
...java.util.concurrent.CountDownLatch.await(Unknown Source)
Le verrou était initialisé à 1 et un autre thread a appelé la méthode countDown() sur la même instance du verrou, mais le thread principal reste bloqué sur le verrou. Cela a conduit à JVM être suspendu indéfiniment. Se bloquer même si le compte du verrou atteint zéro semble déraisonnable et je cherche des suggestions pour résoudre ce problème.
Des idées?
Remarque - La version utilisée est jvm comme ci-dessous
java version "1.5.0_15" Java (TM) 2 Runtime Environment, Standard Edition (build 1.5.0_15-b04) Java HotSpot (TM) Client VM (build 1.5.0_15-b04, mode mixte, partage)
Mise à jour - est ci-dessous l'extrait de code du fil dont je parle ci-dessus
private class MyRunnable implements Runnable, Thread.UncaughtExceptionHandler {
private AtomicBoolean shouldStop = new AtomicBoolean(false);
private CountDownLatch stopLatch = new CountDownLatch(1);
private Thread currentThread;
public void run() {
Thread.currentThread().setName("My Thread");
Thread.currentThread().setUncaughtExceptionHandler(this);
currentThread = Thread.currentThread();
if (currentThread.isInterrupted()) {
logger.debug("The pool thread had its interrupted stattus set. Clearing...");
Thread.interrupted();
logger.debug("The pool thread had its interrupted stattus set. Clearing...DONE");
}
try {
doBusinessLogic(shouldStop);
} catch (Exception e) {
logger.error("An exception was encountered in the thread", e);
} finally {
if (currentThread.isInterrupted()) {
logger.debug("Clearing interupted status for the thread and returning to pool...");
Thread.interrupted();
}
stopLatch.countDown();
logger.debug("Stopped task after counting down on the latch");
}
}
public void stopThread() {
shouldStop.set(true);
logger.debug("Stop flag was set to true.. waiting for thread method to return...");
try {
stopLatch.await();
logger.debug("Stop flag was set to true... task has finished. Returning.");
} catch (InterruptedException e) {
logger.error("Interrupted while awaiting thread stop event...", e);
}
}
public void uncaughtException(Thread t, Throwable e) {
logger.error("An uncaught exception occurred in the task thread ", e);
}
private void doBusinessLogic(AtomicBoolean shouldStop) {
long sleepPeriod = 11;
while (!shouldStop.get()) {
try {
Thread.sleep(sleepPeriod);
} catch (InterruptedException e) {
logger.debug("Thread was interrupted.Clearing interrupted status and proceeding", e);
if (Thread.currentThread().isInterrupted())
Thread.interrupted();
}
if (shouldStop.get()) {
logger.debug("Stop flag was set. Returning.");
return;
}
try {
logger.debug("Performing business logic...");
//.....
logger.debug("Performing business logic...DONE");
} catch (Throwable e) {
logger.error("An exception occurred", e);
}
if (shouldStop.get()) {
logger.debug("Stop flag was set. Returning.");
return;
}
}
}
}
Voici ce que je vois dans les journaux
DEBUG [main Thread] - Stop flag was set to true.. waiting for thread method to return...
DEBUG [My Thread] - Stop flag was set. Returning.
DEBUG [My Thread] - Stopped task after counting down on the latch
L'instruction enregistreur après latch.await() est jamais imprimé et la décharge de fil indique que le thread principal est bloqué sur le loquet.
Vous * dites * que 'countDown()' a été appelé sur la même instance - mais je serais plus enclin à croire qu'il y a un bug dans votre code et votre diagnostic que dans les bibliothèques JRE. Pouvez-vous produire un programme court mais complet qui démontre le problème? –
Si je pouvais le démontrer, j'aurais pu connaître probablement la cause première :). La raison pour laquelle je dis que countDown() a été appelée est parce que les instructions du logger l'indiquent. Des instructions de journal sont ajoutées après l'appel de countDown() et celles-ci sont visibles dans les journaux. Le vidage de thread indique cependant que le thread principal attend toujours sur le compte de verrou à zéro. –
J'ose dire que 'countDown' est appelé - mais votre journalisation * aussi * indique indiscutablement qu'elle est appelée sur la même instance? –