以前我們知道創(chuàng)建線程的兩種方式:
本文再來講講另外兩種創(chuàng)建線程的方式:
callable接口 1、有什么特點? 2、為什么要用Callable接口?
3、怎么用?
思考:Thread類的構(gòu)造只能接受Runnable接口,并不能接口Callable接口,怎么辦? 接下來看看編碼實現(xiàn):
main方法:
計算出的結(jié)果為: ![]() 這個結(jié)果是正確的。那么問題來了:
大家注意看運行結(jié)果中的兩個 hello 是什么時候輸出的: ![]()
也就是說,輸出兩個 hello 并不需要用到 call 方法 的返回值,所以即使還沒算完,也應(yīng)該可以正常輸出,而不是被阻塞。所以,get方法的調(diào)用要放在最后并且等計算完了再get。那么如何保證計算完了呢?看如下代碼:
把get方法的調(diào)用放在最后面,并且用while進行自旋操作,如果沒計算完,就會一直在while循環(huán)中。看看這次的運行結(jié)果: ![]() 可以看到,這次main線程并沒被阻塞,運行后立即完成了自己該做的事。 注意上面的call方法里有一行注釋掉的輸出語句,以及main方法里有一個注釋掉的線程BB。如果把注釋放開,其實也還是只有AA線程會進去,BB線程根本就調(diào)不到call方法。也就說,多個線程共用一個 futureTask,只會進去一次。 線程池 1、為什么要用線程池? 2、如何使用線程池?
第一個是線程池中線程數(shù)固定的,第二個就是線程池中只有一個線程,第三個就是帶緩存的,線程數(shù)量可變。這三個底層用的都是ThreadPoolExecutor。
運行結(jié)果: ![]()
3、線程池的7大參數(shù):
`
可以發(fā)現(xiàn),最后兩個參數(shù)用的默認值,不需要我們傳,所以我們剛才只看到5個。下面來說說這7大參數(shù)都是干嘛的。
那么這些參數(shù)到底什么意思呢?舉個生活當(dāng)中的例子讓你秒懂: 今天星期天,你去銀行辦理業(yè)務(wù)。由于星期天,所以只開放了兩個窗口,所以corePoolSize就是2。如果剛好來了兩個人,那么能滿足需求。如果不止兩個人,那么其他人就得在等待區(qū)等著,這個等待區(qū)就是workQueue。如果等待區(qū)也坐滿了人,那么當(dāng)值人員就會打電話給經(jīng)理,讓經(jīng)理叫人加班多開窗口,假如這個銀行總共有5個窗口,那么這個5就是maximumPoolSize。如果開了5個窗口還是忙不過來,等待區(qū)還是爆滿,那么大堂經(jīng)理就會對辦理業(yè)務(wù)的人說:不好意思,我們這里忙不過來了,請您去別的網(wǎng)點吧。這就是拒絕策略。當(dāng)辦業(yè)務(wù)的人慢慢的少了,來加班的那幾個窗口如果超過了keepAliveTime時間都還沒有人來辦理業(yè)務(wù),那么他們就會下班。也就是說,兩個窗口忙得過來就不會勞煩別人加班。 4、線程池的拒絕策略:
5、上面說到三個最常見的線程池,生產(chǎn)中使用哪個? 因為FixedThreadPool和 SingleThreadExecutor 底層用的阻塞隊列是 LinkedBlockingQueue,這個隊列是有界,但是最大值是 int 的最大值,21億多,相當(dāng)于無界。也就是說可能會在這里堆積大量的任務(wù),造成OOM。CachedThreadPool本身線程數(shù)就可變,允許的最大線程數(shù)也是 int 的最大值,所以可能會創(chuàng)建大量的線程,最終造成OOM。 既然都不用, 那我們?nèi)绾蝿?chuàng)建線程池?答案是我們使用 ThreadPoolExecutor,手動配置那7個參數(shù)。如下:
既然我們說人家Executors創(chuàng)建的線程池不行,那么我們創(chuàng)建的怎么就行呢?那些參數(shù)怎么來的?corePoolSize設(shè)置為多少、maximumPoolSize又設(shè)置為多少才合適?請看下面的線程池參數(shù)配置。 6、線程池參數(shù)配置:
CPU密集型要盡可能的減少線程數(shù)量,一般公式:
IO密集型則應(yīng)盡可能多的配置線程,一般公式:
獲取CPU核心數(shù)的方式:
死鎖問題 1、什么是死鎖? 2、寫一個死鎖:
測試:
看運行結(jié)果: ![]()
3、死鎖定位分析:
這條命令可以查看進程號,Java也提供了類似的命令,那就是:
用這條命令查看到Java進程號后,找到可能出現(xiàn)異常的進程,再輸入:
這樣就可以查看到詳細信息了。以上面的代碼為例,先在cmd中進入項目路徑,輸入上面的命令。 ![]() 這樣就說明這是死鎖了。 |
|