Программное обнаружение взаимоблокировок в Java - PullRequest
55 голосов
/ 09 июля 2009

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

Ответы [ 9 ]

60 голосов
/ 09 июля 2009

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

11 голосов
/ 09 июля 2009

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

Если вы можете поймать приложение с поличным и подозревать, что произошла тупиковая ситуация, перейдите и нажмите «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)
    ...
4 голосов
/ 09 марта 2015

Вы можете обнаружить заблокированные потоки программно, используя класс 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");
    }

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

3 голосов
/ 05 мая 2014

JArmus - библиотека для обнаружения и устранения тупиков. Включает поддержку: Thread.join, CyclicBarrier, CountDownLatch, Phaser и ReentrantLock.

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

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

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

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

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

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

Пример * * 1 032 Следующая программа, которая блокируется правильно, определяется 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();

2 голосов
/ 09 июля 2009

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

Запустите JConsole с помощью команды $JAVA_HOM/bin/jconsole

2 голосов
/ 09 июля 2009

Возможно, вы захотите рассмотреть MTRAT IBM . Профилактика лучше, чем лечение в конце концов. Multicore Software Development Kit также поставляется с инструментом обнаружения тупиковых ситуаций.

1 голос
/ 16 ноября 2011

Здесь есть код: http://www.java2s.com/Code/Java/Development-Class/PerformingdeadlockdetectionprogrammaticallywithintheapplicationusingthejavalangmanagementAPI.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()).

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

1 голос
/ 02 января 2010

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

0 голосов
/ 09 июля 2009

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

...