今天剛下載上阿里的java規(guī)范插件,掃描完成之后發(fā)現(xiàn)之前創(chuàng)建線程池的方式有問(wèn)題.
舊的
service = Executors.newFixedThreadPool(poolSize);
發(fā)現(xiàn)會(huì)提示錯(cuò)誤,查看原因發(fā)現(xiàn)
線程池不允許使用Executors去創(chuàng)建挽放,而是通過(guò)ThreadPoolExecutor的方式绍赛,這樣的處理方式讓寫的同學(xué)更加明確線程池的運(yùn)行規(guī)則,規(guī)避資源耗盡的風(fēng)險(xiǎn)辑畦。 說(shuō)明:Executors各個(gè)方法的弊端:
- newFixedThreadPool和newSingleThreadExecutor:主要問(wèn)題是堆積的請(qǐng)求處理隊(duì)列可能會(huì)耗費(fèi)非常大的內(nèi)存惹资,甚至OOM。
- newCachedThreadPool和newScheduledThreadPool:主要問(wèn)題是線程數(shù)最大數(shù)是Integer.MAX_VALUE航闺,可能會(huì)創(chuàng)建數(shù)量非常多的線程,甚至OOM猴誊。
線程池類為 java.util.concurrent.ThreadPoolExecutor潦刃,常用構(gòu)造方法為:
ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue,
RejectedExecutionHandler handler)
- corePoolSize: 線程池維護(hù)線程的最少數(shù)量
- maximumPoolSize:線程池維護(hù)線程的最大數(shù)量
- keepAliveTime: 線程池維護(hù)線程所允許的空閑時(shí)間
- unit: 線程池維護(hù)線程所允許的空閑時(shí)間的單位
- workQueue: 線程池所使用的緩沖隊(duì)列
- handler: 線程池對(duì)拒絕任務(wù)的處理策略
一個(gè)任務(wù)通過(guò) execute(Runnable)方法被添加到線程池,任務(wù)就是一個(gè) Runnable類型的對(duì)象懈叹,任務(wù)的執(zhí)行方法就是 Runnable類型對(duì)象的run()方法乖杠。
當(dāng)一個(gè)任務(wù)通過(guò)execute(Runnable)方法欲添加到線程池時(shí):
如果此時(shí)線程池中的數(shù)量小于corePoolSize,即使線程池中的線程都處于空閑狀態(tài)澄成,也要?jiǎng)?chuàng)建新的線程來(lái)處理被添加的任務(wù)胧洒。
如果此時(shí)線程池中的數(shù)量等于 corePoolSize,但是緩沖隊(duì)列 workQueue未滿墨状,那么任務(wù)被放入緩沖隊(duì)列卫漫。
如果此時(shí)線程池中的數(shù)量大于corePoolSize,緩沖隊(duì)列workQueue滿肾砂,并且線程池中的數(shù)量小于maximumPoolSize列赎,建新的線程來(lái)處理被添加的任務(wù)。
如果此時(shí)線程池中的數(shù)量大于corePoolSize镐确,緩沖隊(duì)列workQueue滿包吝,并且線程池中的數(shù)量等于maximumPoolSize,那么通過(guò) handler所指定的策略來(lái)處理此任務(wù)源葫。
也就是:處理任務(wù)的優(yōu)先級(jí)為:
核心線程corePoolSize诗越、任務(wù)隊(duì)列workQueue、最大線程maximumPoolSize息堂,如果三者都滿了嚷狞,使用handler處理被拒絕的任務(wù)。
當(dāng)線程池中的線程數(shù)量大于 corePoolSize時(shí)储矩,如果某線程空閑時(shí)間超過(guò)keepAliveTime感耙,線程將被終止。這樣持隧,線程池可以動(dòng)態(tài)的調(diào)整池中的線程數(shù)即硼。
unit可選的參數(shù)為java.util.concurrent.TimeUnit中的幾個(gè)靜態(tài)屬性:
NANOSECONDS、MICROSECONDS屡拨、MILLISECONDS只酥、SECONDS褥实。
workQueue我常用的是:java.util.concurrent.ArrayBlockingQueue
handler有四個(gè)選擇:
- ThreadPoolExecutor.AbortPolicy()
拋出java.util.concurrent.RejectedExecutionException異常 - ThreadPoolExecutor.CallerRunsPolicy()
重試添加當(dāng)前的任務(wù),他會(huì)自動(dòng)重復(fù)調(diào)用execute()方法 - ThreadPoolExecutor.DiscardOldestPolicy()
拋棄舊的任務(wù) - ThreadPoolExecutor.DiscardPolicy()
拋棄當(dāng)前的任務(wù)
推薦示例1
//org.apache.commons.lang3.concurrent.BasicThreadFactory
ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor(1,
new BasicThreadFactory.Builder().namingPattern("example-schedule-pool-%d").daemon(true).build());
推薦示例2
ThreadFactory namedThreadFactory = new ThreadFactoryBuilder()
.setNameFormat("demo-pool-%d").build();
//Common Thread Pool
ExecutorService pool = new ThreadPoolExecutor(5, 200,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(1024), namedThreadFactory, new ThreadPoolExecutor.AbortPolicy());
pool.execute(()-> System.out.println(Thread.currentThread().getName()));
pool.shutdown();//gracefully shutdown
推薦示例3
<bean id="userThreadPool"
class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<property name="corePoolSize" value="10" />
<property name="maxPoolSize" value="100" />
<property name="queueCapacity" value="2000" />
<property name="threadFactory" value= threadFactory />
<property name="rejectedExecutionHandler">
<ref local="rejectedExecutionHandler" />
</property>
</bean>
//in code
userThreadPool.execute(thread);