테스트

aion-server 4.8

Gitteol
최고관리자 · 1 · 💬 0 클론/새로받기
 4.8 61f661d · 1 commits 새로받기(Pull)
commons/src/com/aionemu/commons/utils/concurrent/DeadLockDetector.java
package com.aionemu.commons.utils.concurrent;

import java.lang.management.*;
import java.time.Duration;
import java.util.Arrays;
import java.util.Set;
import java.util.stream.Collectors;

import org.slf4j.LoggerFactory;

/**
 * @author -Nemesiss-, ATracer
 */
public class DeadLockDetector implements Runnable {

	private final Duration checkInterval;
	private final Runnable actionOnDeadlock;
	private final ThreadMXBean tmx;

	private DeadLockDetector(Duration checkInterval, Runnable actionOnDeadlock) {
		this.checkInterval = checkInterval;
		this.actionOnDeadlock = actionOnDeadlock;
		this.tmx = ManagementFactory.getThreadMXBean();
	}

	@Override
	public final void run() {
		while (!detectDeadlock()) {
			try {
				Thread.sleep(checkInterval);
			} catch (InterruptedException ignored) {
				return;
			}
		}
		if (actionOnDeadlock != null)
			actionOnDeadlock.run();
	}

	private boolean detectDeadlock() {
		long[] ids = tmx.findDeadlockedThreads();
		if (ids == null)
			return false;
		ThreadInfo[] tis = tmx.getThreadInfo(ids, true, true);
		Long skippableThreadId = null;
		String info = "Deadlock found:\n";
		for (ThreadInfo ti : tis) {
			if (ti.getLockedSynchronizers().length == 0 && ti.getLockedMonitors().length == 0)
				continue; // this thread is deadlocked but its not guilty
			if (skippableThreadId != null && skippableThreadId == ti.getThreadId()) {
				skippableThreadId = null; // don't log the same relations twice
				continue;
			}

			info += createShortLockInfo(ti);
			ThreadInfo dl = ti;
			while ((dl = tmx.getThreadInfo(new long[]{dl.getLockOwnerId()}, true, true)[0]).getThreadId() != ti.getThreadId()) {
				info += createShortLockInfo(dl);
				if (skippableThreadId == null)
					skippableThreadId = dl.getThreadId();
			}
		}

		info += "\nDeadlocked threads:\n";
		for (ThreadInfo ti : tis)
			info += toStringUnlimited(ti);
		info += "\nRemaining threads:\n";
		Set<Long> ignoredIds = Arrays.stream(ids).boxed().collect(Collectors.toSet());
		for (ThreadInfo ti : tmx.dumpAllThreads(true, true)) {
			if (!ignoredIds.contains(ti.getThreadId()))
				info += toStringUnlimited(ti);
		}
		LoggerFactory.getLogger(DeadLockDetector.class).error(info);
		return true;
	}

	private String createShortLockInfo(ThreadInfo threadInfo) {
		return "\t\"" + threadInfo.getThreadName() + "\" is waiting to lock " + threadInfo.getLockInfo().toString() + " which is held by \""
			+ threadInfo.getLockOwnerName() + "\". " + "Locked synchronizers: " + threadInfo.getLockedSynchronizers().length + ", " + "monitors: "
			+ threadInfo.getLockedMonitors().length + '\n';
	}

	/**
	 * Same as threadInfo.toString() but with full stack trace instead of only the top 8 elements
	 */
	private String toStringUnlimited(ThreadInfo threadInfo) {
		StringBuilder sb = new StringBuilder("\"" + threadInfo.getThreadName() + "\"" + (threadInfo.isDaemon() ? " daemon" : "") + " prio="
			+ threadInfo.getPriority() + " Id=" + threadInfo.getThreadId() + " " + threadInfo.getThreadState());
		if (threadInfo.getLockName() != null)
			sb.append(" on " + threadInfo.getLockName());
		if (threadInfo.getLockOwnerName() != null)
			sb.append(" owned by \"" + threadInfo.getLockOwnerName() + "\" Id=" + threadInfo.getLockOwnerId());
		if (threadInfo.isSuspended())
			sb.append(" (suspended)");
		if (threadInfo.isInNative())
			sb.append(" (in native)");
		sb.append('\n');
		StackTraceElement[] stackTrace = threadInfo.getStackTrace();
		for (int i = 0; i < stackTrace.length; i++) {
			sb.append("\tat " + stackTrace[i].toString() + '\n');
			if (i == 0 && threadInfo.getLockInfo() != null) {
				switch (threadInfo.getThreadState()) {
					case BLOCKED -> sb.append("\t-  blocked on " + threadInfo.getLockInfo() + '\n');
					case WAITING, TIMED_WAITING -> sb.append("\t-  waiting on " + threadInfo.getLockInfo() + '\n');
				}
			}
			for (MonitorInfo mi : threadInfo.getLockedMonitors()) {
				if (mi.getLockedStackDepth() == i) {
					sb.append("\t-  locked " + mi + '\n');
				}
			}
		}
		LockInfo[] locks = threadInfo.getLockedSynchronizers();
		if (locks.length > 0) {
			sb.append("\n\tNumber of locked synchronizers = " + locks.length + '\n');
			for (LockInfo li : locks)
				sb.append("\t- " + li + '\n');
		}
		sb.append('\n');
		return sb.toString();
	}

	public static Thread start(Duration checkInterval, Runnable actionOnDeadlock) {
		return Thread.ofPlatform().name("DeadLockDetector").start(new DeadLockDetector(checkInterval, actionOnDeadlock));
	}
}

📎 첨부파일

댓글 작성 권한이 없습니다.
🏆 포인트 랭킹 TOP 10
순위 닉네임 포인트
1 no_profile 타키야겐지쪽지보내기 자기소개 아이디로 검색 전체게시물 102,949
2 no_profile 동가리쪽지보내기 자기소개 아이디로 검색 전체게시물 63,733
3 no_profile 라프텔쪽지보내기 자기소개 아이디로 검색 전체게시물 51,771
4 no_profile 불멸의행복쪽지보내기 자기소개 아이디로 검색 전체게시물 36,923
5 서번트쪽지보내기 자기소개 아이디로 검색 전체게시물 35,011
6 no_profile 닥터스쪽지보내기 자기소개 아이디로 검색 전체게시물 29,470
7 no_profile 검은고양이쪽지보내기 자기소개 아이디로 검색 전체게시물 29,077
8 no_profile Revolution쪽지보내기 자기소개 아이디로 검색 전체게시물 28,199
9 no_profile 보거스쪽지보내기 자기소개 아이디로 검색 전체게시물 26,731
10 no_profile 호롤롤로쪽지보내기 자기소개 아이디로 검색 전체게시물 17,020
알림 0