Вопрос

Как я могу программно обнаружить, что в программе Java возникла взаимоблокировка?

Нет правильного решения

Другие советы

Вы можете сделать это программно, используя команду ThreadMXBean который поставляется с 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.
    }
}

Очевидно, вам следует попытаться изолировать поток, выполняющий эту проверку взаимоблокировки. В противном случае, если этот поток заблокируется, он не сможет выполнить проверку!

Кстати, именно это и использует JConsole.

Один полезный совет для расследования:

Если вы можете поймать приложение с поличным и подозреваете, что произошла взаимоблокировка, нажмите «Ctrl-Break» в окне консоли java.exe (или «Ctrl-\" в Solaris/Linux).JVM будет выгружать текущий статус и трассировку стека всех потоков, обнаруживать мертвые блокировки и точно описывать их.

Это будет выглядеть примерно так:

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

Вы можете обнаружить тупиковые потоки программно, используя класс ThreadMXBean. Вот код:

    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");
    }

Нажмите здесь для получения дополнительной информации о том, как обнаружить тупиковые потоки.

Джармус — это библиотека для обнаружения и предотвращения взаимоблокировок.Он включает поддержку:Thread.join, CyclicBarrier, CountDownLatch, Phaser, иReentrantLock.

Чтобы использовать JArmus, вам необходимо инструментировать свой код.Либо через один из инструментальных классов, либо автоматически с помощью инструментария JArmus. jarmusc.

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

Вход yourprogram.jar это программа, которую вы хотите проверить.На выходе получается та же программа с проверками на автоматическое обнаружение любой тупиковой ситуации.

Барьерам нужна помощь

Проверка взаимоблокировок с помощью классов CyclicBarrier, CountDownLatch, Phaser это немного сложно - например, JConsole не может обнаружить эти типы взаимоблокировок.Джармасу нужна ваша небольшая помощь:вы должны указать, какие потоки влияют на синхронизацию, мы называем их зарегистрированный потоки.

Как можно скорее поток должен пометить себя как зарегистрированный.Хорошее место для пометки зарегистрированных тем — это метод «начало». Runnable.run. JArmus.register(latch);

Пример

Следующая программа, которую Jarmus правильно идентифицируется: 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();

Возможно, вы захотите рассмотреть MTRAT от IBM.В конце концов, профилактика лучше, чем лечение.А Комплект разработки многоядерного программного обеспечения также поставляется с инструментом обнаружения взаимоблокировок.

Если вам не требуется программное обнаружение, вы можете сделать это через JКонсоль;на вкладке темы есть кнопка "обнаружить взаимоблокировку".В JDK6 это обнаруживает блокировки как для встроенных мониторов, так и для j.u.c Lockс

Запустите JConsole через $JAVA_HOM/bin/jconsole команда

Здесь есть код: http://www.java2s.com/Code/Java/Development-Class/Performing deadlockdetection программно внутри приложения с использованием thejavalangmanagementAPI.htm

Волшебство происходит в 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;
  }

Это вызывает API ThreadMXBean который имеет другое имя в Java 5 и 6 (отсюда и внешний if()).

Пример кода также позволяет прерывать блокировки, так что вы даже можете выйти из тупика.

темпус-фугит также реализует его вместе с классом программного дампа потока.Он реализован с использованием механизма mbean, упомянутого выше, и предлагает готовое супер-пупер решение.

Если вы хотите, чтобы это было сделано во время выполнения, вы можете использовать сторожевая собака для этого.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top