Java線程面試題
0. Java線程面試題
0.1 線程占用的內(nèi)存
JDK1.4默認(rèn)單個線程占用256K
JDK1.5默認(rèn)單個線程占用1M
可以通過-Xss參數(shù)設(shè)定
0.2 為什么要使用線程池
手動創(chuàng)建線程池的缺點
不受風(fēng)險控制:服務(wù)器CPU資源有限,如果每個人都顯示手動創(chuàng)建線程,不知道哪里的代碼出現(xiàn)了多線程,在運行的時候所有線程都在搶占資源,不好控制
頻繁創(chuàng)建,開銷大
不好管理:可能無限制新建線程,可能占用過多系統(tǒng)資源導(dǎo)致死機或OOM。而重用存在的線程,減少對象創(chuàng)建、消亡的開銷,性能佳
線程池優(yōu)點
降低系統(tǒng)資源消耗,通過重用已存在的線程,降低線程創(chuàng)建和銷毀造成的消耗
提高系統(tǒng)響應(yīng)速度,當(dāng)有任務(wù)到達時,通過復(fù)用已存在的線程,無需等待新線程的創(chuàng)建便能立即執(zhí)行
方便線程并發(fā)數(shù)的管控
1. 線程的狀態(tài)
1.1 線程狀態(tài)枚舉
NEW
線程被構(gòu)建,還未start
RUNNABLE
運行狀態(tài)
BLOCKED
阻塞狀態(tài),阻塞于鎖
WAITING
等待狀態(tài)
TIME_WAITING
超時等待狀態(tài),超過時間自行返回
TERMINATED
終止?fàn)顟B(tài),表示線程執(zhí)行完畢
1.2 線程狀態(tài)轉(zhuǎn)換圖

線程狀態(tài)轉(zhuǎn)換
2. 守護線程和線程優(yōu)先級
2.1 守護線程
JVM中不存在非守護線程時,JVM會退出
2.2 線程的優(yōu)先級
創(chuàng)建線程的時候可以給線程設(shè)置優(yōu)先級,優(yōu)先級高的線程有更高的概率分配到更多的時間片(不絕對)
3. 線程中斷
可以理解為Thread有個interrupted標(biāo)識符,默認(rèn)為false,表示一個線程是否被其他線程進行了中斷操作

復(fù)制
如果線程拋出InterruptedException,那么在拋出InterruptedException之前,JVM會先將標(biāo)識符設(shè)為false,然后再拋出
4. 線程間通信
4.1 通過volatile和synchronized
4.2 等待/通知機制
sleep()
當(dāng)前線程進入TIME_WAITING狀態(tài),不會釋放鎖,但會釋放CPU資源
一段時間后蘇醒,回到RUNNABLE狀態(tài)
yield()
當(dāng)前線程由RUNNING狀態(tài)變?yōu)镽EADY狀態(tài),不會釋放鎖,但會釋放CPU資源
wait(),notify(),nitifyAll()
使用wait(),notify(),nitofyAll()時需要對調(diào)用對象加鎖(必須在同步代碼塊內(nèi))
當(dāng)前線程調(diào)用某個加鎖對象的wait()后,會進入該對象的monitor對象的等待隊列中,釋放鎖,釋放CPU資源,狀態(tài)變?yōu)閃AITING
當(dāng)前線程調(diào)用某個加鎖對象的notify()或nitifyAll(),等待隊列中的線程從等待隊列中移動到同步隊列中,線程狀態(tài)由WAITING變?yōu)锽LOKING
等待隊列中的線程要想從wait()中返回,除了需要有其他線程調(diào)用notify()外,還需要等待線程釋放鎖,獲得對象的鎖后才能從wait()返回
復(fù)制

14
join()
注意,wait()是Object的,join()是Thread的
join()中底層調(diào)用的wait()
若調(diào)用了thread2.join()
就是讓當(dāng)前線程進入thread2的monitor對象的等待隊列中,知道thread2結(jié)束才會被喚醒
由于底層調(diào)用的是wait(),所以會釋放鎖,但注意釋放的是thread2的鎖
4.3 等待/通知規(guī)范
等待方偽代碼

復(fù)制
通知方偽代碼

復(fù)制
5. 創(chuàng)建線程的方式
1. 繼承Thread
2. 實現(xiàn)Runnable接口/利用匿名對象/lambda表達式
3. 實現(xiàn)Callable接口
4. FutureTask(可以由調(diào)用線程執(zhí)行其run(),也可以作為任務(wù)提交給線程池)
5. 定時器
6. Stream的parallelStream
7. 線程池隱性創(chuàng)建
