List<ThreadState> (String threadDump) { List<ThreadState> result = new ArrayList<>(); StringBuilder lastThreadStack = new StringBuilder(); ThreadState lastThreadState = null; boolean expectingThreadState = false; boolean haveNonEmptyStackTrace = false; StringBuilder coroutineDump = null; for(@NonNls String line: StringUtil.tokenize(threadDump, "\r\n")) { if (EventCountDumper.EVENT_COUNTS_HEADER.equals(line)) { break; } if (isCoroutineDumpHeader(line)) { coroutineDump = new StringBuilder(); } if (coroutineDump != null) { coroutineDump.append(line).append("\n"); continue; } if (line.startsWith("============") || line.contains("Java-level deadlock")) { break; } ThreadState state = tryParseThreadStart(line.trim()); if (state != null) { if (lastThreadState != null) { lastThreadState.setStackTrace(lastThreadStack.toString(), !haveNonEmptyStackTrace); } lastThreadState = state; result.add(lastThreadState); lastThreadStack.setLength(0); haveNonEmptyStackTrace = false; lastThreadStack.append(line).append("\n"); expectingThreadState = true; } else { boolean parsedThreadState = false; if (expectingThreadState) { expectingThreadState = false; parsedThreadState = tryParseThreadState(line, lastThreadState); } lastThreadStack.append(line).append("\n"); if (!parsedThreadState && line.trim().startsWith("at")) { haveNonEmptyStackTrace = true; } } } if (lastThreadState != null) { lastThreadState.setStackTrace(lastThreadStack.toString(), !haveNonEmptyStackTrace); } for(ThreadState threadState: result) { inferThreadStateDetail(threadState); String lockId = findWaitingForLock(threadState.getStackTrace()); ThreadState lockOwner = findLockOwner(result, lockId, true); if (lockOwner == null) { lockOwner = findLockOwner(result, lockId, false); } if (lockOwner != null) { if (threadState.isAwaitedBy(lockOwner)) { threadState.addDeadlockedThread(lockOwner); lockOwner.addDeadlockedThread(threadState); } lockOwner.addWaitingThread(threadState); } } sortThreads(result); if (coroutineDump != null) { ThreadState coroutineState = new ThreadState("Coroutine dump", "undefined"); coroutineState.setStackTrace(coroutineDump.toString(), false); result.add(coroutineState); } return result; }