目的:有時候為了快速定位出現錯誤的位置,在采用線程池時我們需要自定義線程池的名稱。
1、創建ThreadFactory(ThreadPoolExecutor默認采用的是DefaultThreadFactory,可以參照代碼)。
public class NamedThreadFactory implements ThreadFactory{ private final AtomicInteger poolNumber = new AtomicInteger(1); private final ThreadGroup threadGroup; private final AtomicInteger threadNumber = new AtomicInteger(1); public final String namePrefix; NamedThreadFactory(String name){ SecurityManager s = System.getSecurityManager(); threadGroup = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup(); if (null==name || "".equals(name.trim())){ name = "pool"; } namePrefix = name +"-"+ poolNumber.getAndIncrement() + "-thread-"; } @Override public Thread newThread(Runnable r) { Thread t = new Thread(threadGroup, r, namePrefix + threadNumber.getAndIncrement(), 0); if (t.isDaemon()) t.setDaemon(false); if (t.getPriority() != Thread.NORM_PRIORITY) t.setPriority(Thread.NORM_PRIORITY); return t; } }
2、創建線程池
//核心線程滿了,則進入隊列,隊列滿了,則創建新線程,當線程數達到最大線程數,則進入拒絕策略
static ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5,5,1, TimeUnit.MINUTES,new LinkedBlockingDeque<>(),new NamedThreadFactory("測試"));
3、測試代碼
static ThreadLocal<SimpleDateFormat>threadLocal = new ThreadLocal<SimpleDateFormat>(){ @Override protected SimpleDateFormat initialValue() { return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); } }; public static void main(String[] args) { threadPoolExecutor.execute(new Runnable() { @Override public void run() { try { System.out.println(threadLocal.get().parse("2019-10-22 16:59:00")); throw new NullPointerException("sfa"); } catch (ParseException e) { e.printStackTrace(); } } }); }
4、結果
補充:
1、參數解析
2、拒絕策略
(1)、CallerRunsPolicy
該任務被線程池拒絕,由調用execute方法的線程(如main線程)執行該任務。一般並發比較小,性能要求不高,不允許失敗。但是,由於調用者自己運行任務,如果任務提交速度過快,可能導致程序阻塞,性能效率上必然的損失較大。
(2)、AbortPolicy
丟棄任務,並拋出 RejectedExecutionException 異常。線程池默認的拒絕策略。必須處理好拋出的異常,否則會打斷當前的執行流程,影響后續的任務執行。
(3)、DiscardOldestPolicy
丟棄任務,不過也不拋出異常。
(4)、DiscardOldestPolicy
當觸發拒絕策略,只要線程池沒有關閉的話,丟棄阻塞隊列 workQueue 中最老的一個任務,並將新任務加入。