2008-10-19 3 views
60

Давным-давно я сохранил предложение из справочника Java: «Java не имеет механизма для обработки тупика, он даже не знает, что произошел тупик». (Head First Java 2nd Edition, p.516)Обнаружение тупика в Java

Итак, что это? Есть ли способ поймать тупик в Java? Я имею в виду, есть ли способ, которым наш код понимает, что произошло тупиковое дело?

+1

Является ли Java отличным от других языков в этом отношении? – 2008-10-19 22:58:05

+0

невозможно обнаружить тупик - это просто довольно сложно – 2008-10-19 23:00:49

+0

например - большинство баз данных обнаружит взаимоблокировки – 2008-10-19 23:01:21

ответ

17

JConsole способен обнаруживать взаимоблокировки в запущенном приложении.

3

Не совсем то, что вы просили, но когда возникает тупик , вы можете выполнить «kill -3» на идентификаторе процесса, и он выгружает дамп потока в стандартный вывод. Кроме того, у 1,6 jvm есть некоторые инструменты, чтобы сделать то же самое в gui-манере.

6

В целом, java не обеспечивает обнаружение тупиковой ситуации. Синхронизированное ключевое слово и встроенные мониторы затрудняют рассуждение о тупике, чем на языках с явной блокировкой.

Я предлагаю перейти на использование java.util.concurrent.Lock locks и т. Д., Чтобы упростить ваши схемы блокировки. На самом деле вы можете легко сделать свою собственную реализацию интерфейса блокировки с обнаружением тупиковой ситуации. Алгоритм состоит в том, чтобы в основном пройти график зависимости блокировки и искать цикл.

+3

Замки в java.util.concurrent.Lock имеют обнаружение блокировки, встроенное в JDK 1.6. См. Java.lang.management.ThreadMXBean. – staffan 2008-10-20 09:56:39

11

JDK 5 и 6 сбрасывают данные о блокировке в полном дампе потока (полученные с помощью kill -3, jstack, jconsole и т. Д.). JDK 6 содержит информацию о ReentrantLock и ReentrantReadWriteLock. Из этой информации можно диагностировать тупик, обнаружив цикл блокировки: Нить A удерживает блокировку 1, Thread B удерживает блокировку 2, и либо A запрашивает 2, либо B запрашивает 1. Из моего опыта это обычно довольно очевидно.

Другие инструменты анализа могут действительно находить потенциальные блокировки, даже если они не встречаются. Инструменты резьбы от таких поставщиков, как OptimizeIt, JProbe, Coverity и т. Д. - это хорошие места для просмотра.

3

Доктор Хайнц Кабуц из JavaSpecialists написал интересный и информативный newsletter issue on Java deadlocks и описывает что-то, называемое ThreadMXBean, в another newsletter issue. Между ними вы должны получить хорошее представление о проблемах и о некоторых указателях на выполнение собственных инструментов.

3

Если вы следуете простому правилу, избегайте тупиковых ситуаций: попросите все потоки запросить и отпустите свои блокировки в том же порядке. Таким образом, вы никогда не попадаете в ситуацию, когда может возникнуть взаимоблокировка.

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

На мой взгляд, профилактика лучше, чем лечение.

Это одно из двух рекомендаций, которые мне нравятся, чтобы обеспечить правильную работу нитей. Другой - обеспечить каждую нить только, которая несет ответственность за собственное исполнение, так как она полностью знает, что она делает в любой момент времени.

Таким образом, это означает, что нет вызовов Thread.stop, используйте глобальный флаг (или очередь сообщений или что-то в этом роде), чтобы указать другой поток, который вы хотите предпринять. Затем пусть этот поток выполняет фактическую работу.

+2

Хотя это канонический ответ, это не всегда возможно. Есть и другие способы избежать тупиковой ситуации. Например, вы можете использовать timed tryLocks (с ReentrantLock) для выполнения резервного копирования. – 2008-10-21 12:47:28

4

Если вы находитесь на Java 5, вы можете вызвать метод findMonitorDeadlockedThreads() на ThreadMXBean, который вы можете получить по телефону java.lang.management.ManagementFactory.getThreadMXBean(). Это обнаружит блокировки, вызванные только объектными мониторами. На Java 6 есть findDeadlockedThreads(), который также будет найти тупики, вызванные «ownable синхронизаторов (например ReentrandLock и ReentrantReadWriteLock).

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

75

с JDK 1.5 есть очень полезные методы в java.lang.management пакете, чтобы найти и инспектировать тупики, что происходит. См метод ThreadMXBean класса findMonitorDeadlockedThreads() и findDeadlockedThreads().

возможный способ использовать это, чтобы иметь отдельный сторожевая нить (o r периодическая задача), которая делает это.

Пример кода:

ThreadMXBean tmx = ManagementFactory.getThreadMXBean(); 
    long[] ids = tmx.findDeadlockedThreads(); 
    if (ids != null) { 
    ThreadInfo[] infos = tmx.getThreadInfo(ids, true, true); 
    System.out.println("The following threads are deadlocked:"); 
    for (ThreadInfo ti : infos) { 
     System.out.println(ti); 
    } 
    } 
2

Если вы отладки в Eclipse, вы можете приостановить приложение (выберите приложение в окне отладки и небольшой кнопки || на панели инструментов отладки), а затем он может сообщать о блокировках.

См., Например, http://runnerwhocodes.blogspot.com/2007/10/deadlock-detection-with-eclipse.html.

8

Обратите внимание, что существует тупиковая ситуация с использованием параллельного пакета, который очень трудно отлаживать. Вот где у вас есть ReentrantReadWriteLock, и один поток захватывает блокировку чтения, а затем (скажем) пытается войти в монитор, удерживаемый другим потоком, который также ждет захвата блокировки записи. Особенно сложно отладить, что нет записи о том, кто ввел блокировку чтения. Это просто счет. Поток мог даже выбросить исключение и умер, оставив отсчет чтения ненулевым.

Вот пример тупиковой, что метод findDeadlockedThreads упоминалось ранее не получит:

import java.util.concurrent.locks.*; 
import java.lang.management.*; 

public class LockTest { 

    static ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); 

    public static void main(String[] args) throws Exception { 
     Reader reader = new Reader(); 
     Writer writer = new Writer(); 
     sleep(10); 
     System.out.println("finding deadlocked threads"); 
     ThreadMXBean tmx = ManagementFactory.getThreadMXBean(); 
     long[] ids = tmx.findDeadlockedThreads(); 
     if (ids != null) { 
      ThreadInfo[] infos = tmx.getThreadInfo(ids, true, true); 
      System.out.println("the following threads are deadlocked:"); 
      for (ThreadInfo ti : infos) { 
       System.out.println(ti); 
      } 
     } 
     System.out.println("finished finding deadlocked threads"); 
    } 

    static void sleep(int seconds) { 
     try { 
      Thread.currentThread().sleep(seconds*1000); 
     } catch (InterruptedException e) {} 
    } 

    static class Reader implements Runnable { 
     Reader() { 
      new Thread(this).start(); 
     } 
     public void run() { 
      sleep(2); 
      System.out.println("reader thread getting lock"); 
      lock.readLock().lock(); 
      System.out.println("reader thread got lock"); 
      synchronized (lock) { 
       System.out.println("reader thread inside monitor!"); 
       lock.readLock().unlock(); 
      } 
     } 
    } 

    static class Writer implements Runnable { 
     Writer() { 
      new Thread(this).start(); 
     } 
     public void run() { 
      synchronized (lock) { 
       sleep(4); 
       System.out.println("writer thread getting lock"); 
       lock.writeLock().lock(); 
       System.out.println("writer thread got lock!"); 
      } 
     } 
    } 
} 
0

После так долго, я могу написать простейший пример взаимоблокировки. Комментарии приветствуются.

Class A 
{ 
    synchronized void methodA(B b) 
    { 
    b.last(); 
    } 

    synchronized void last() 
    { 
    SOP(“ Inside A.last()”); 
    } 
} 

Class B 
{ 
    synchronized void methodB(A a) 
    { 
    a.last(); 
    } 

    synchronized void last() 
    { 
    SOP(“ Inside B.last()”); 
    } 
} 


Class Deadlock implements Runnable 
{ 
    A a = new A(); 
    B b = new B(); 

    // Constructor 
    Deadlock() 
    { 
    Thread t = new Thread(); 
    t.start(); 
    a.methodA(b); 
    } 

    public void run() 
    { 
    b.methodB(a); 
    } 

    public static void main(String args[]) 
    { 
    new Deadlock(); 
    } 
} 
-3

вы должны изменить код немного в Тупик класса

 
    Deadlock() { 
    Therad t = new Thread(this); // modified 
    t.start(); 
    System.out.println(); //any instruction to delay 
    a.methodA(b); 
} 

Также приведенный выше код не всегда будет вызывать мертвую блокировку, только несколько раз, это может произойти.

3

Java может обнаруживать взаимоблокировки (хотя не во время выполнения, он все еще может диагностировать и сообщать об этом).

Например, при использовании слегка модифицированной версии кода «Saurabh M. Chande» (сменил его на Java и добавил некоторое время, чтобы гарантировать блокировку при каждом прогоне).После того, как вы запустите его и зависаний, если вы напечатаете:

kill -3 PID # where 'PID' is the Linux process ID 

Он будет генерировать дамп стека, который будет включать в себя следующую информацию:

Found one Java-level deadlock: 
============================= 
"Thread-0": 
    waiting to lock monitor 0x08081670 (object 0x7f61ddb8, a Deadlock$A), 
    which is held by "main" 
"main": 
     waiting to lock monitor 0x080809f0 (object 0x7f61f3b0, a Deadlock$B), 
     which is held by "Thread-0" 
0

Java 5 введен ThreadMXBean - интерфейс, который предоставляет различные методы мониторинга потоков. ... Разница заключается в том, что findDeadlockedThreads может также обнаружить тупики, вызванные владельцами замков (java.util.concurrent), в то время как findMonitorDeadlockedThreads может обнаружить только монитор блокировки (т.е. синхронизированные блоки)

Или вы можете обнаружить его программно, передать этот https://dzone.com/articles/how-detect-java-deadlocks

Смежные вопросы