Привет тебе хабражитель!
В данной статье, точнее примере я хочу показать как можно получить информацию о залоченных потоках Вашего многопоточного java приложения. Под катом будет представлен пример простейшей ситтуации DeadLock'а, а также способы получения информации о нем.
Простейшая ситтуация получения DeadLoack'а — когда один поток пытается залочить уже залоченный другим потоком ресурс.
В данном примере оба потока будут залочены намертво между собой по ресурсам lock1 и lock2.
Выхода из программы не произойдет никогда. Начиная с версии java 1.5 очень просто можно отлавливать такие ситтуации, для этого существует специализированный бин для взамодействия с подсистемой потоков ThreadMXBean. Javadoc достаточно подробный так что читайте.
Давайте напишем простейший метод для получения отчета о наших проблемах с локировками.
В переменной threadMXBean лежит инстанс бина ThreadMXBean. На второй строчке кода мы получаем список идентификаторов тредов у которых есть проблемы с локировками. После чего используем вспомогательный класс ThreadDump(есть в исходниках) для вывода информации о наших проблемных потоках. Теперь нам необходим отдельный поток для сбора информации о проблемах в нашем приложении. Код его очень простой:
Он проверяет наличие отчета о проблемах каждые 6 секунд, и если такой присутствует то выводит его в System.out.
Теперь добавим пару строчек кода в нашу первую программу, для проверки что эта куча кода работает:
Запускаем и, в консоле нашей программы мы увидим примерно следующие строки:
Исходники
Спасибо за внимание.
В данной статье, точнее примере я хочу показать как можно получить информацию о залоченных потоках Вашего многопоточного java приложения. Под катом будет представлен пример простейшей ситтуации DeadLock'а, а также способы получения информации о нем.
Простейшая ситтуация получения DeadLoack'а — когда один поток пытается залочить уже залоченный другим потоком ресурс.
- public class TestDeadLockTracker {
- public static void main(String[] args) {
- final Object lock1 = new Object();
- final Object lock2 = new Object();
- Thread t1 = new Thread("Deadlock Test T1") {
- public void run() {
- synchronized (lock1) {
- try {
- Thread.sleep(150L);
- } catch (Throwable ignored) {
- }
- synchronized (lock2) {
- try {
- Thread.sleep(30L);
- } catch (Throwable ignored) {
- }
- lock2.notify();
- }
- lock1.notify();
- }
- }
- };
- Thread t2 = new Thread("Deadlock Test T2") {
- public void run() {
- synchronized (lock2) {
- try {
- Thread.sleep(150L);
- } catch (Throwable ignored) {
- }
- synchronized (lock1) {
- try {
- Thread.sleep(300L);
- } catch (Throwable ignored) {
- }
- lock1.notify();
- }
- lock2.notify();
- }
- }
- };
- t1.start();
- t2.start();
- }
- }
* This source code was highlighted with Source Code Highlighter.
В данном примере оба потока будут залочены намертво между собой по ресурсам lock1 и lock2.
Выхода из программы не произойдет никогда. Начиная с версии java 1.5 очень просто можно отлавливать такие ситтуации, для этого существует специализированный бин для взамодействия с подсистемой потоков ThreadMXBean. Javadoc достаточно подробный так что читайте.
Давайте напишем простейший метод для получения отчета о наших проблемах с локировками.
- public static String reportDeadlocks(ArrayList<Long> knownDeadlocks) {
- long[] threads = threadMXBean.findDeadlockedThreads();
-
- if ((threads == null) || (threads.length == 0)) {
- return null;
- }
-
- final ArrayList<Long> dumpIDs = new ArrayList<Long>(threads.length);
- for (long thread : threads) {
- boolean found = false;
-
- if (knownDeadlocks != null) {
- Iterator itr = knownDeadlocks.iterator();
- while ((!found) && (itr.hasNext())) {
- found = thread == ((Number) itr.next()).longValue();
- }
- }
-
- if (found) continue;
- dumpIDs.add(thread);
- }
-
- if (dumpIDs.size() == 0) return null;
-
- if (knownDeadlocks != null) knownDeadlocks.addAll(dumpIDs);
-
- ThreadDumpFilter filter = new ThreadDumpFilter() {
- public boolean include(Thread t) {
- long id = t.getId();
- for (Long dumpID : dumpIDs) {
- if (dumpID == id) return true;
- }
- return false;
- }
-
- public String toString() {
- return String.format("Deadlocked threads: %s", dumpIDs);
- }
- };
- StringWriter writer = new StringWriter();
- ThreadDump.print(new PrintWriter(writer), filter);
- writer.flush();
-
- return String.format("Found %d new deadlocked threads (%d total deadlocked):\n%s",
- dumpIDs.size(), threads.length, writer.toString());
- }
* This source code was highlighted with Source Code Highlighter.
В переменной threadMXBean лежит инстанс бина ThreadMXBean. На второй строчке кода мы получаем список идентификаторов тредов у которых есть проблемы с локировками. После чего используем вспомогательный класс ThreadDump(есть в исходниках) для вывода информации о наших проблемных потоках. Теперь нам необходим отдельный поток для сбора информации о проблемах в нашем приложении. Код его очень простой:
- private static class DeadlockTrackerThread extends Thread {
- private volatile boolean checking = true;
-
- DeadlockTrackerThread() {
- super("Deadlock Tracking Thread");
- setPriority(1);
- setDaemon(true);
- }
-
- public void setChecking(boolean b) {
- this.checking = b;
- if (this.checking) return;
- interrupt();
- }
-
- public void run() {
- ArrayList<Long> knownDeadlocks = new ArrayList<Long>();
- try {
- while (this.checking) {
- String report = ThreadUtils.reportDeadlocks(knownDeadlocks);
- if (report != null) {
- System.out.print("Dedlock detected " + report);
- }
- try {
- Thread.sleep(6000L);
- } catch (InterruptedException intx) {}
- }
- } catch (Exception e) {
- System.err.print("Error: " + e.getMessage());
- }
- }
- }
* This source code was highlighted with Source Code Highlighter.
Он проверяет наличие отчета о проблемах каждые 6 секунд, и если такой присутствует то выводит его в System.out.
Теперь добавим пару строчек кода в нашу первую программу, для проверки что эта куча кода работает:
- public class TestDeadLockTracker {
- public static void main(String[] args) {
- if (!ThreadUtils.isDeadlockDetectionSupported()) {
- System.out.println("DeadlockDetection not supported");
- return;
- }
- ThreadUtils.setDeadlockDetectionEnabled(true);
- ThreadUtils.setTrackingDeadlocksEnabled(true);
- final Object lock1 = new Object();
- ....
- }
- }
* This source code was highlighted with Source Code Highlighter.
Запускаем и, в консоле нашей программы мы увидим примерно следующие строки:
Dedlock detected Found 2 new deadlocked threads (2 total deadlocked):
— Thread Dump Deadlocked threads: [11, 10]
Thread[Deadlock Test T1,5,main] «Deadlock Test T1» Id=10 BLOCKED on java.lang.Object@272d7a10 owned by «Deadlock Test T2» Id=11
TestDeadLockTracker$1.run(TestDeadLockTracker.java:27)
Thread[Deadlock Test T2,5,main] «Deadlock Test T2» Id=11 BLOCKED on java.lang.Object@1aa8c488 owned by «Deadlock Test T1» Id=10
TestDeadLockTracker$2.run(TestDeadLockTracker.java:45)
— End Thread Dump
Исходники
Спасибо за внимание.