\n * 1.監控線程池狀態及異常關閉等情況
\n * 2.監控線程池運行時的各項指標, 比如:任務等待數、已完成任務數、任務異常信息、核心線程數、最大線程數等
\n * author: 老K\n */\npublic class ThreadPoolExt extends ThreadPoolExecutor{\n\n private static final Logger log = LoggerFactory.getLogger(ThreadPoolExt.class);\n\n private TimeUnit timeUnit;\n\n public ThreadPoolExt(int corePoolSize,\n int maximumPoolSize,\n long keepAliveTime,\n TimeUnit unit,\n BlockingQueue \n */\n private void monitor(String title){\n try {\n // 線程池監控信息記錄, 這裏需要注意寫ES的時機,尤其是多個子線程的日誌合併到主流程的記錄方式\n String threadPoolMonitor = MessageFormat.format(\n \"{0}{1}core pool size:{2}, current pool size:{3}, queue wait size:{4}, active count:{5}, completed task count:{6}, \" +\n \"task count:{7}, largest pool size:{8}, max pool size:{9}, keep alive time:{10}, is shutdown:{11}, is terminated:{12}, \" +\n \"thread name:{13}{14}\",\n System.lineSeparator(), title, this.getCorePoolSize(), this.getPoolSize(),\n this.getQueue().size(), this.getActiveCount(), this.getCompletedTaskCount(), this.getTaskCount(), this.getLargestPoolSize(),\n this.getMaximumPoolSize(), this.getKeepAliveTime(timeUnit != null ? timeUnit : TimeUnit.SECONDS), this.isShutdown(),\n this.isTerminated(), Thread.currentThread().getName(), System.lineSeparator());\n log.info(threadPoolMonitor);\n } catch (Exception e) {\n log.error(\"ThreadPool monitor error\", e);\n }\n }\n}","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"自定義拒絕策略代碼:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"package com.javakk;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.lang.management.*;\nimport java.text.MessageFormat;\nimport java.util.concurrent.RejectedExecutionException;\nimport java.util.concurrent.RejectedExecutionHandler;\nimport java.util.concurrent.ThreadPoolExecutor;\nimport java.util.concurrent.TimeUnit;\n\n/**\n * 自定義線程池拒絕策略: \n * 1.記錄線程池的核心線程數,活躍數,已完成數等信息,以及調用線程的堆棧信息,便於排查 \n * 2.拋出異常中斷執行 \n * author: 老K\n */\npublic class RejectedPolicyWithReport implements RejectedExecutionHandler {\n\n private static final Logger log = LoggerFactory.getLogger(RejectedPolicyWithReport.class);\n\n private static volatile long lastPrintTime = 0;\n\n private static final long TEN_MINUTES_MILLS = 10 * 60 * 1000;\n\n private static Semaphore guard = new Semaphore(1);\n @Override\n public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {\n try {\n String title = \"thread pool execute reject policy!!\";\n String msg = MessageFormat.format(\n \"{0}{1}core pool size:{2}, current pool size:{3}, queue wait size:{4}, active count:{5}, completed task count:{6}, \" +\n \"task count:{7}, largest pool size:{8}, max pool size:{9}, keep alive time:{10}, is shutdown:{11}, is terminated:{12}, \" +\n \"thread name:{13}{14}\",\n System.lineSeparator(), title, e.getCorePoolSize(), e.getPoolSize(), e.getQueue().size(), e.getActiveCount(),\n e.getCompletedTaskCount(), e.getTaskCount(), e.getLargestPoolSize(), e.getMaximumPoolSize(), e.getKeepAliveTime(TimeUnit.SECONDS),\n e.isShutdown(), e.isTerminated(), Thread.currentThread().getName(), System.lineSeparator());\n log.info(msg);\n threadDump(); // 記錄線程堆棧信息包括鎖爭用信息\n } catch (Exception ex) {\n log.error(\"RejectedPolicyWithReport rejectedExecution error\", ex);\n }\n throw new RejectedExecutionException(\"thread pool execute reject policy!!\");\n }\n\n /**\n * 獲取線程dump信息 \n * 注意: 該方法默認會記錄所有線程和鎖信息雖然方便debug, 使用時最好加開關和間隔調用, 否則可能會增加latency \n * 1.當前線程的基本信息:id,name,state \n * 2.堆棧信息 \n * 3.鎖相關信息(可以設置不記錄) \n * 默認在log記錄 \n * @return\n */\n private void threadDump() {\n long now = System.currentTimeMillis();\n // 每隔10分鐘dump一次\n if (now - lastPrintTime < TEN_MINUTES_MILLS) { \n return; \n } \n if (!guard.tryAcquire()) { \n return; \n } \n // 異步dump線程池信息 \n ExecutorService pool = Executors.newSingleThreadExecutor(); \n pool.execute(() -> {\n try {\n ThreadMXBean threadMxBean = ManagementFactory.getThreadMXBean();\n StringBuilder sb = new StringBuilder();\n for (ThreadInfo threadInfo : threadMxBean.dumpAllThreads(true, true)) {\n sb.append(getThreadDumpString(threadInfo));\n }\n log.error(\"thread dump info:\", sb.toString());\n } catch (Exception e) {\n log.error(\"thread dump error\", e);\n } finally {\n guard.release();\n }\n lastPrintTime = System.currentTimeMillis();\n });\n pool.shutdown();\n }\n\n @SuppressWarnings(\"all\")\n private String getThreadDumpString(ThreadInfo threadInfo) {\n StringBuilder sb = new StringBuilder(\"\"\" + threadInfo.getThreadName() + \"\"\" +\n \" Id=\" + threadInfo.getThreadId() + \" \" +\n threadInfo.getThreadState());\n if (threadInfo.getLockName() != null) {\n sb.append(\" on \" + threadInfo.getLockName());\n }\n if (threadInfo.getLockOwnerName() != null) {\n sb.append(\" owned by \"\" + threadInfo.getLockOwnerName() +\n \"\" Id=\" + threadInfo.getLockOwnerId());\n }\n if (threadInfo.isSuspended()) {\n sb.append(\" (suspended)\");\n }\n if (threadInfo.isInNative()) {\n sb.append(\" (in native)\");\n }\n sb.append('n');\n int i = 0;\n\n StackTraceElement[] stackTrace = threadInfo.getStackTrace();\n MonitorInfo[] lockedMonitors = threadInfo.getLockedMonitors();\n for (; i < stackTrace.length && i < 32; i++) {\n StackTraceElement ste = stackTrace[i];\n sb.append(\"tat \" + ste.toString());\n sb.append('n');\n if (i == 0 && threadInfo.getLockInfo() != null) {\n Thread.State ts = threadInfo.getThreadState();\n switch (ts) {\n case BLOCKED:\n sb.append(\"t- blocked on \" + threadInfo.getLockInfo());\n sb.append('n');\n break;\n case WAITING:\n sb.append(\"t- waiting on \" + threadInfo.getLockInfo());\n sb.append('n');\n break;\n case TIMED_WAITING:\n sb.append(\"t- waiting on \" + threadInfo.getLockInfo());\n sb.append('n');\n break;\n default:\n }\n }\n\n for (MonitorInfo mi : lockedMonitors) {\n if (mi.getLockedStackDepth() == i) {\n sb.append(\"t- locked \" + mi);\n sb.append('n');\n }\n }\n }\n if (i < stackTrace.length) {\n sb.append(\"t...\");\n sb.append('n');\n }\n\n LockInfo[] locks = threadInfo.getLockedSynchronizers();\n if (locks.length > 0) {\n sb.append(\"ntNumber of locked synchronizers = \" + locks.length);\n sb.append('n');\n for (LockInfo li : locks) {\n sb.append(\"t- \" + li);\n sb.append('n');\n }\n }\n sb.append('n');\n return sb.toString();\n }\n}","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"文章來源:","attrs":{}},{"type":"link","attrs":{"href":"http://javakk.com/188.html","title":null},"content":[{"type":"text","text":"http://javakk.com/188.html","attrs":{}}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}}]}