1.不應(yīng)用線程池的缺點(diǎn)
- 有些開發(fā)者圖省事贮乳,遇到需要多線程處理的地方,直接new Thread(...).start()塘揣,對(duì)于一般場(chǎng)景是沒問題的宿崭,但如果是在并發(fā)請(qǐng)求很高的情況下,就會(huì)有些隱患:
- 新建線程的開銷奖蔓。線程雖然比進(jìn)程要輕量許多,但對(duì)于JVM來說厨疙,新建一個(gè)線程的代價(jià)還是挺大的疑务,決不同于新建一個(gè)對(duì)象
- 資源消耗量。沒有一個(gè)池來限制線程的數(shù)量知允,會(huì)導(dǎo)致線程的數(shù)量直接取決于應(yīng)用的并發(fā)量温鸽,這樣有潛在的線程數(shù)據(jù)巨大的可能,那么資源消耗量將是巨大的
- 穩(wěn)定性涤垫。當(dāng)線程數(shù)量超過系統(tǒng)資源所能承受的程度,穩(wěn)定性就會(huì)成問題
2.制定執(zhí)行策略
- 在每個(gè)需要多線程處理的地方切蟋,不管并發(fā)量有多大榆芦,需要考慮線程的執(zhí)行策略
- 任務(wù)以什么順序執(zhí)行
- 可以有多少個(gè)任務(wù)并發(fā)執(zhí)行
- 可以有多少個(gè)任務(wù)進(jìn)入等待執(zhí)行隊(duì)列
- 系統(tǒng)過載的時(shí)候,應(yīng)該放棄哪些任務(wù)镰惦?如何通知到應(yīng)用程序犬绒?
- 一個(gè)任務(wù)的執(zhí)行前后應(yīng)該做什么處理
3.線程池的類型
- 不管是通過Executors創(chuàng)建線程池,還是通過Spring來管理茵瘾,都得清楚知道有哪幾種線程池:
- FixedThreadPool:定長(zhǎng)線程池咐鹤,提交任務(wù)時(shí)創(chuàng)建線程,直到池的最大容量祈惶,如果有線程非預(yù)期結(jié)束,會(huì)補(bǔ)充新線程
- CachedThreadPool:可變線程池凡涩,它猶如一個(gè)彈簧,如果沒有任務(wù)需求時(shí)力麸,它回收空閑線程育韩,如果需求增加,則按需增加線程筋讨,不對(duì)池的大小做限制
- SingleThreadExecutor:?jiǎn)尉€程版仔。處理不過來的任務(wù)會(huì)進(jìn)入FIFO隊(duì)列等待執(zhí)行
- SecheduledThreadPool:周期性線程池。支持執(zhí)行周期性線程任務(wù)
-
其實(shí)蛮粮,這些不同類型的線程池都是通過構(gòu)建一個(gè)ThreadPoolExecutor來完成的然想,所不同的是
corePoolSize,maximumPoolSize,keepAliveTime,unit,workQueue,threadFactory
這么幾個(gè)參數(shù)。具體可以參見JDK DOC变泄。
4.線程池飽和策略
- 由以上線程池類型可知,除了CachedThreadPool其他線程池都有飽和的可能屏富,當(dāng)飽和以后就需要相應(yīng)的策略處理請(qǐng)求線程的任務(wù)蛙卤,比如,達(dá)到上限時(shí)通過ThreadPoolExecutor.setRejectedExecutionHandler方法設(shè)置一個(gè)拒絕任務(wù)的策略神年,JDK提供了AbortPolicy行嗤、CallerRunsPolicy、DiscardPolicy栅屏、DiscardOldestPolicy幾種策略,具體差異可見JDK DOC
5.線程無依賴性
- 多線程任務(wù)設(shè)計(jì)上盡量使得各任務(wù)是獨(dú)立無依賴的占婉,所謂依賴性可兩個(gè)方面:
- 線程之間的依賴性甫恩。如果線程有依賴可能會(huì)造成死鎖或饑餓
- 調(diào)用者與線程的依賴性。調(diào)用者得監(jiān)視線程的完成情況奖慌,影響可并發(fā)量
當(dāng)然松靡,在有些業(yè)務(wù)里確實(shí)需要一定的依賴性,比如調(diào)用者需要得到線程完成后結(jié)果岛马,傳統(tǒng)的Thread是不便完成的屠列,因?yàn)閞un方法無返回值,只能通過一些共享的變量來傳遞結(jié)果夏志,但在Executor框架里可以通過Future和Callable實(shí)現(xiàn)需要有返回值的任務(wù)苛让,當(dāng)然線程的異步性導(dǎo)致需要有相應(yīng)機(jī)制來保證調(diào)用者能等待任務(wù)完成。