public static String createDumpMessage(ThreadDumpBo threadDump) {
        ThreadState threadState = getThreadState(threadDump.getThreadState());

        // set threadName
        StringBuilder message = new StringBuilder(64);
        message.append("\"").append(threadDump.getThreadName()).append("\"");

        // set threadId
        String hexStringThreadId = Long.toHexString(threadDump.getThreadId());
        message.append(" Id=0x").append(hexStringThreadId);

        // set threadState
        message.append(" ").append(threadState.name());

        if (!StringUtils.isBlank(threadDump.getLockName())) {
            message.append(" on ").append(threadDump.getLockName());
        }

        if (!StringUtils.isBlank(threadDump.getLockOwnerName())) {
            message.append(" owned by \"").append(threadDump.getLockOwnerName()).append("\" Id=").append(threadDump.getLockOwnerId());
        }

        if (threadDump.isSuspended()) {
            message.append(" (suspended)");
        }
        if (threadDump.isInNative()) {
            message.append(" (in native)");
        }
        message.append(LINE_SEPARATOR);

        // set StackTrace
        final List<String> stackTraceList = threadDump.getStackTraceList();
        for (int i = 0; i < stackTraceList.size(); i++) {
            String stackTrace = stackTraceList.get(i);
            message.append(TAB_SEPARATOR).append("at ").append(stackTrace);
            message.append(LINE_SEPARATOR);

            if (i == 0 && !StringUtils.isBlank(threadDump.getLockName())) {
                switch (threadState) {
                    case BLOCKED -> {
                        message.append(TAB_SEPARATOR).append("-  blocked on ").append(threadDump.getLockName());
                        message.append(LINE_SEPARATOR);
                    }
                    case WAITING, TIMED_WAITING -> {
                        message.append(TAB_SEPARATOR).append("-  waiting on ").append(threadDump.getLockName());
                        message.append(LINE_SEPARATOR);
                    }
                    default -> {
                    }
                }
            }

            for (MonitorInfoBo lockedMonitor : threadDump.getLockedMonitorInfoList()) {
                if (lockedMonitor.getStackDepth() == i) {
                    message.append(TAB_SEPARATOR).append("-  locked ").append(lockedMonitor.getStackFrame());
                    message.append(LINE_SEPARATOR);
                }
            }
        }

        // set Locks
        List<String> lockedSynchronizers = threadDump.getLockedSynchronizerList();
        if (CollectionUtils.hasLength(lockedSynchronizers)) {
            message.append(LINE_SEPARATOR).append(TAB_SEPARATOR).append("Number of locked synchronizers = ").append(lockedSynchronizers.size());
            message.append(LINE_SEPARATOR);
            for (String lockedSynchronizer : lockedSynchronizers) {
                message.append(TAB_SEPARATOR).append("- ").append(lockedSynchronizer);
                message.append(LINE_SEPARATOR);
            }
        }

        message.append(LINE_SEPARATOR);
        return message.toString();
    }
@author Taejin Koo
@author jaehong.kim - Add createDumpMessage() for ThreadDumpBo
web/src/main/java/com/navercorp/pinpoint/web/util/ThreadDumpUtils.java