JAVA多线程之扩展ThreadPoolExecutor
歡迎跳轉(zhuǎn)到本文的原文鏈接:https://honeypps.com/java/java-multi-thread-of-thread-pool-executor/
ThreadPoolExecutor是可擴展的,通過查看源碼可以發(fā)現(xiàn),它提供了幾個可以在子類化中改寫的方法:beforeExecute,afterExecute,terminated.
源碼片段如下所示:
?
protected void beforeExecute(Thread t, Runnable r) { } protected void afterExecute(Runnable r, Throwable t) { } protected void terminated() { }可以注意到,這三個方法都是protected的空方法,擺明了是讓子類擴展的嘛。
?
在執(zhí)行任務的線程中將調(diào)用beforeExecute和afterExecute等方法,在這些方法中還可以添加日志、計時、監(jiān)視或者統(tǒng)計信息收集的功能。無論任務是從run中正常返回,還是拋出一個異常而返回,afterExecute都會被調(diào)用。如果任務在完成后帶有一個Error,那么就不會調(diào)用afterExecute。如果beforeExecute拋出一個RuntimeException,那么任務將不被執(zhí)行,并且afterExecute也不會被調(diào)用。
在線程池完成關(guān)閉時調(diào)用terminated,也就是在所有任務都已經(jīng)完成并且所有工作者線程也已經(jīng)關(guān)閉后,terminated可以用來釋放Executor在其生命周期里分配的各種資源,此外還可以執(zhí)行發(fā)送通知、記錄日志或者手機finalize統(tǒng)計等操作。
下面就以給線程池添加統(tǒng)計信息為例(添加日志和及時等功能):
?
package com.threadPool;import java.util.concurrent.BlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicLong; import java.util.logging.Logger;public class TimingThreadPool extends ThreadPoolExecutor {private final ThreadLocal<Long> startTime = new ThreadLocal<Long>();private final Logger log = Logger.getAnonymousLogger();private final AtomicLong numTasks = new AtomicLong();private final AtomicLong totalTime = new AtomicLong();public TimingThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,BlockingQueue<Runnable> workQueue){super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);}protected void beforeExecute(Thread t, Runnable r){super.beforeExecute(t, r);log.info(String.format("Thread %s: start %s", t,r));startTime.set(System.nanoTime());}protected void afterExecute(Runnable r, Throwable t){try{long endTime = System.nanoTime();long taskTime = endTime-startTime.get();numTasks.incrementAndGet();totalTime.addAndGet(taskTime);log.info(String.format("Thread %s: end %s, time=%dns", t,r,taskTime));}finally{super.afterExecute(r, t);}}protected void terminated(){try{log.info(String.format("Terminated: avg time=%dns",totalTime.get()/numTasks.get()));}finally{super.terminated();}} }可以看到TimingThreadPool重寫了父類的三個方法。
?
下面寫一個測試類,參考運行效果:
?
package com.threadPool;import java.util.concurrent.SynchronousQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit;public class CheckTimingThreadPool {public static void main(String[] args){ThreadPoolExecutor exec = new TimingThreadPool(0, Integer.MAX_VALUE,60L, TimeUnit.SECONDS,new SynchronousQueue<Runnable>());exec.execute(new DoSomething(5));exec.execute(new DoSomething(4));exec.execute(new DoSomething(3));exec.execute(new DoSomething(2));exec.execute(new DoSomething(1));exec.shutdown();}}class DoSomething implements Runnable{private int sleepTime;public DoSomething(int sleepTime){this.sleepTime = sleepTime;}@Overridepublic void run(){System.out.println(Thread.currentThread().getName()+" is running.");try{TimeUnit.SECONDS.sleep(sleepTime);}catch (InterruptedException e){e.printStackTrace();}}}運行結(jié)果:
?
?
十二月 25, 2015 4:18:42 下午 com.threadPool.TimingThreadPool beforeExecute 信息: Thread Thread[pool-1-thread-1,5,main]: start com.threadPool.DoSomething@43f459c2 十二月 25, 2015 4:18:42 下午 com.threadPool.TimingThreadPool beforeExecute 信息: Thread Thread[pool-1-thread-3,5,main]: start com.threadPool.DoSomething@33891d5d pool-1-thread-3 is running. 十二月 25, 2015 4:18:42 下午 com.threadPool.TimingThreadPool beforeExecute 信息: Thread Thread[pool-1-thread-4,5,main]: start com.threadPool.DoSomething@33891d5d pool-1-thread-4 is running. 十二月 25, 2015 4:18:42 下午 com.threadPool.TimingThreadPool beforeExecute 信息: Thread Thread[pool-1-thread-5,5,main]: start com.threadPool.DoSomething@10747b4 pool-1-thread-5 is running. 十二月 25, 2015 4:18:42 下午 com.threadPool.TimingThreadPool beforeExecute 信息: Thread Thread[pool-1-thread-2,5,main]: start com.threadPool.DoSomething@7d4af469 pool-1-thread-2 is running. pool-1-thread-1 is running. 十二月 25, 2015 4:18:43 下午 com.threadPool.TimingThreadPool afterExecute 信息: Thread null: end com.threadPool.DoSomething@10747b4, time=999589906ns 十二月 25, 2015 4:18:44 下午 com.threadPool.TimingThreadPool afterExecute 信息: Thread null: end com.threadPool.DoSomething@33891d5d, time=1999461618ns 十二月 25, 2015 4:18:45 下午 com.threadPool.TimingThreadPool afterExecute 信息: Thread null: end com.threadPool.DoSomething@33891d5d, time=3000507593ns 十二月 25, 2015 4:18:46 下午 com.threadPool.TimingThreadPool afterExecute 信息: Thread null: end com.threadPool.DoSomething@7d4af469, time=3999691253ns 十二月 25, 2015 4:18:47 下午 com.threadPool.TimingThreadPool afterExecute 信息: Thread null: end com.threadPool.DoSomething@43f459c2, time=4999778490ns 十二月 25, 2015 4:18:47 下午 com.threadPool.TimingThreadPool terminated 信息: Terminated: avg time=2999805772ns可以看到,在測試類CheckTimingThreadPool中通過execute了五個線程,然后分別對這五個線程進行統(tǒng)計,最后統(tǒng)計出各個線程的耗時平均時間。
?
這里說明下TimingThreadPool的構(gòu)造函數(shù),它直接調(diào)用了父類的構(gòu)造方法,在ThreadPoolExecutor中有許多構(gòu)造方法,有興趣的朋友可以查看jdk api或者源碼進行查看。
簡要說明下構(gòu)造函數(shù)的參數(shù)的含義:
corePoolSize:線程池維護線程的最少數(shù)量
maximumPoolSize:線程池維護線程的最大數(shù)量
keepAliveTime:線程池維護線程所允許的空閑時間
unit:線程池維護所允許的空閑時間的單位
workQueue:線程池所使用的緩存隊列
歡迎跳轉(zhuǎn)到本文的原文鏈接:https://honeypps.com/java/java-multi-thread-of-thread-pool-executor/
總結(jié)
以上是生活随笔為你收集整理的JAVA多线程之扩展ThreadPoolExecutor的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java守护线程概述
- 下一篇: JAVA多线程之UncaughtExce