項目中使用到了ThreadPoolExecutor,這個是挺好的東西,線程池的實現。但有一點不太爽的是,用Jprofiler調試由它創建的線程的時候,看到的都是pool-1-thread-1\2\3\4之類的。這是它自身的默認規則產生的,pool代表這是池,-1-代表是第幾個ThreadPoolExecutor產生的,-thread-1是遞增的。
所以每次我都要點 Thread Dumps 去查看線程執行的具體的代碼與堆棧信息,推測是哪個地方出的問題。雖然說也能看出來,但很不直觀嘛。於是有了一個想法,能不能不要用它的默認名稱,由我自己的設定線程的名字,這樣就一目瞭然了。把idea和master王說了,覺得也是個好主意。當然就只是在開發階段有幫助,系統穩定上線後就沒有用了。
Executors.defaultThreadFactory()是缺省的創建線程的實現。看下源碼,
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
之所以在工具中看到所有的線程都是以 pool- 開頭的,那是因爲人家就是寫死的。 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-prjname-具體thread-1這種形式,如果說項目中所有代碼共用一個pool,我可以直接把 poolNumber.getAndIncrement() 換成想要的名稱。沒錯。但是具體thread呢?再搞一個參數,從上層傳遞進來替換嗎?最開始發現貌似可以的。當然了,這意味着原生的Executors不能用了,把所有代碼都copy到一個新類裏,可能還會關聯到其他類,也一併copy,如果不是關聯到很多類的話,還是可以的。如果一層又一層,就比較沒意思了。
使用方式:pool.taskPressIn(msgThread, "發送tmp"); 發送tmp就是我想要的具體thread的名稱。但通過工具多次觀察後,發現thread名稱不是傳進去的那個。認真考慮了newCachedThreadPool這個池,它是線程可複用的。當我提交了一個帶名稱的任務實例後,池子裏其實是有空閒的線程的,這些線程可能就是之前命過名的,直接運行實例了,名稱也就不會變了。
我最開始想着從池子中使用的線程入手,用的哪個就改哪個的名稱,由於跟代碼,想發現任務execute時,怎麼獲取線程的,master王想了一個辦法。
我們說一個線程在start後纔會執行run方法,run方法的執行表示這個task真正被線程運行了,這時線程的名稱也就確定了。所以可以在run的第一句加上
Thread.currentThread().setName(ThreadPoolFairEx.renameThread(Thread.currentThread(), this.threadName));
Thread.currentThread()把當前的運行的線程傳進去,renameThread()是一個替換string的方法而已,把自定義的threadName替之。然後currentThread再setName。這樣就是這種效果