/* * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the * Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that * it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If * not, see <http://www.gnu.org/licenses/>. */ package silentium.commons.utils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.lang.management.*; /** * @author ATracer */ public class DeadLockDetector extends Thread { private static final Logger log = LoggerFactory.getLogger(DeadLockDetector.class.getName()); private final long checkInterval; private final boolean restartWhenDeadLock; private static final String INDENT = " "; private StringBuilder sb; public DeadLockDetector(final long checkInterval) { this.checkInterval = checkInterval * 1000L; restartWhenDeadLock = false; } public DeadLockDetector(final long checkInterval, final boolean restartWhenDeadLock) { this.checkInterval = checkInterval * 1000L; this.restartWhenDeadLock = restartWhenDeadLock; } @Override public void run() { boolean noDeadLocks = true; while (noDeadLocks) try { final ThreadMXBean bean = ManagementFactory.getThreadMXBean(); final long[] threadIds = bean.findDeadlockedThreads(); if (threadIds != null) { log.error("Deadlock detected !"); sb = new StringBuilder(); noDeadLocks = false; final ThreadInfo[] infos = bean.getThreadInfo(threadIds); sb.append("\nTHREAD LOCK INFO: \n"); for (final ThreadInfo threadInfo : infos) { printThreadInfo(threadInfo); final LockInfo[] lockInfos = threadInfo.getLockedSynchronizers(); final MonitorInfo[] monitorInfos = threadInfo.getLockedMonitors(); printLockInfo(lockInfos); printMonitorInfo(threadInfo, monitorInfos); } sb.append("\nTHREAD DUMPS: \n"); for (final ThreadInfo ti : bean.dumpAllThreads(true, true)) printThreadInfo(ti); log.error(sb.toString()); if (restartWhenDeadLock) System.exit(ExitCode.CODE_RESTART); } Thread.sleep(checkInterval); } catch (Exception ex) { log.error(ex.getLocalizedMessage(), ex); } } private void printThreadInfo(final ThreadInfo threadInfo) { printThread(threadInfo); sb.append(INDENT).append(threadInfo.toString()).append('\n'); final StackTraceElement[] stacktrace = threadInfo.getStackTrace(); final MonitorInfo[] monitors = threadInfo.getLockedMonitors(); for (int i = 0; i < stacktrace.length; i++) { final StackTraceElement ste = stacktrace[i]; sb.append(INDENT + "at ").append(ste.toString()).append('\n'); for (final MonitorInfo mi : monitors) { if (mi.getLockedStackDepth() == i) { sb.append(INDENT + " - locked ").append(mi).append('\n'); } } } } private void printThread(final ThreadInfo ti) { sb.append("\nPrintThread\n"); sb.append('"').append(ti.getThreadName()).append('"').append(" Id=").append(ti.getThreadId()).append(" in ").append(ti.getThreadState()).append('\n'); if (ti.getLockName() != null) { sb.append(" on lock=").append(ti.getLockName()).append('\n'); } if (ti.isSuspended()) { sb.append(" (suspended)" + '\n'); } if (ti.isInNative()) { sb.append(" (running in native)" + '\n'); } if (ti.getLockOwnerName() != null) { sb.append(INDENT + " owned by ").append(ti.getLockOwnerName()).append(" Id=").append(ti.getLockOwnerId()).append('\n'); } } private void printMonitorInfo(final ThreadInfo threadInfo, final MonitorInfo... monitorInfos) { sb.append(INDENT + "Locked monitors: count = ").append(monitorInfos.length).append('\n'); for (final MonitorInfo monitorInfo : monitorInfos) { sb.append(INDENT + " - ").append(monitorInfo).append(" locked at ").append('\n'); sb.append(INDENT + " ").append(monitorInfo.getLockedStackDepth()).append(' ').append(monitorInfo.getLockedStackFrame()).append('\n'); } } private void printLockInfo(final LockInfo... lockInfos) { sb.append(INDENT + "Locked synchronizers: count = ").append(lockInfos.length).append('\n'); for (final LockInfo lockInfo : lockInfos) sb.append(INDENT + " - ").append(lockInfo).append('\n'); } }