線程工廠ThreadFactory
我們在項目開發額過程中,如果有很多地方使用多線程,那么給線程命名是十分有必要的,這樣當出現問題的時候就比較容易排查
創建線程池,使用默認的線程工廠
/** * 創建線程池 */ public static final ThreadPoolExecutor pool = new ThreadPoolExecutor( 20, 100, 5, TimeUnit.SECONDS, new ArrayBlockingQueue<>(100) );
測試
public static void main(String[] args) { pool.execute(() -> { Integer integer = getOrderInfo(); System.out.println(integer); }); pool.shutdown(); } private static Integer getOrderInfo(){ try { List<Integer> list = new ArrayList<>(); for (int i = 0 ; i < 10 ; i++){ list.add(i); } return list.get(11); }catch (Exception e){ throw new IndexOutOfBoundsException("數組越界"); } }
上面程序發生異常,數組下標越界,我們發現線程的名稱是pool-1-thread-1,pool代表是哪一個線程池,如果再啟動一個線程池 就是pool-2,一直按照3,4,5,一直遞增,thread-1則是線程,也是遞增,thread-2,thread-2,但是當我們系統業務復雜,服務很多, 根據這個報錯很難找出是哪里的問題。 
為線程設定名字
我們首先看一下默認的ThreadFactory,
static class DefaultThreadFactory implements ThreadFactory { private static final AtomicInteger poolNumber = new AtomicInteger(1); private final ThreadGroup group; private final AtomicInteger threadNumber = new AtomicInteger(1); private final String namePrefix; DefaultThreadFactory() { SecurityManager s = System.getSecurityManager(); group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup(); namePrefix = "pool-" + poolNumber.getAndIncrement() + "-thread-"; } public Thread newThread(Runnable r) { Thread t = new Thread(group, r, namePrefix + threadNumber.getAndIncrement(), 0); if (t.isDaemon()) t.setDaemon(false); if (t.getPriority() != Thread.NORM_PRIORITY) t.setPriority(Thread.NORM_PRIORITY); return t; } }
不難看出在無參構造函數中使用了pool-作為前綴,那么這個我們可以自定義為自己的業務名稱,ThreadFactory是一個接口,我們 實現它,並根據自己的需求去改就行,如下:
我們在構造函數中傳了一個threadName,然后拼接成我們想要的
package thread.customthreadpool.threadFactory; import java.util.concurrent.Executors; import java.util.concurrent.ThreadFactory; import java.util.concurrent.atomic.AtomicInteger; /** * 自定義線程工廠 * * 線程工廠可以設置線程信息 */ public class MyThreadFactory implements ThreadFactory { private static final AtomicInteger poolNumber = new AtomicInteger(1); private final ThreadGroup group; private final AtomicInteger threadNumber = new AtomicInteger(1); private final String namePrefix; /** * 構造函數傳入我們想業務需要的線程名字threadName,方便發生異常是追溯 * @param threadName */ public MyThreadFactory(String threadName) { SecurityManager s = System.getSecurityManager(); group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup(); if (threadName == null || threadName.isEmpty()){ threadName = "pool"; } namePrefix = threadName + poolNumber.getAndIncrement() + "-thread-"; } public Thread newThread(Runnable r) { Thread t = new Thread(group, r, namePrefix + threadNumber.getAndIncrement(), 0); if (t.isDaemon()) t.setDaemon(false); if (t.getPriority() != Thread.NORM_PRIORITY) t.setPriority(Thread.NORM_PRIORITY); return t; } }
然后將其加入線程池
/** * 創建線程池 */ public static final ThreadPoolExecutor pool = new ThreadPoolExecutor( 20, 100, 5, TimeUnit.SECONDS, new ArrayBlockingQueue<>(100), new MyThreadFactory("business") );
當發生異常時,我們就能清晰的看到是哪一個模塊的問題,能夠快速的去排查 
