這些多線程的問題贪绘,有些來源于各大網(wǎng)站、有些來源于自己的思考央碟∷肮啵可能有些問題網(wǎng)上有、可能有些問題對應(yīng)的答案也有亿虽、也可能有些各位網(wǎng)友也都看過菱涤,但是本文寫作的重心就是所有的問題都會按照自己的理解回答一遍,不會去看網(wǎng)上的答案洛勉,因此可能有些問題講的不對粘秆,能指正的希望大家不吝指教。
1坯认、ReadWriteLock是什么
首先明確一下翻擒,不是說ReentrantLock不好,只是ReentrantLock某些時候有局限牛哺。如果使用ReentrantLock陋气,可能本身是為了防止線程A在寫數(shù)據(jù)、線程B在讀數(shù)據(jù)造成的數(shù)據(jù)不一致引润,但這樣巩趁,如果線程C在讀數(shù)據(jù)、線程D也在讀數(shù)據(jù)淳附,讀數(shù)據(jù)是不會改變數(shù)據(jù)的议慰,沒有必要加鎖,但是還是加鎖了奴曙,降低了程序的性能别凹。
因為這個,才誕生了讀寫鎖ReadWriteLock洽糟。ReadWriteLock是一個讀寫鎖接口炉菲,ReentrantReadWriteLock是ReadWriteLock接口的一個具體實現(xiàn),實現(xiàn)了讀寫的分離坤溃,讀鎖是共享的拍霜,寫鎖是獨占的,讀和讀之間不會互斥薪介,讀和寫祠饺、寫和讀、寫和寫之間才會互斥汁政,提升了讀寫的性能道偷。
2缀旁、FutureTask是什么
這個其實前面有提到過,F(xiàn)utureTask表示一個異步運算的任務(wù)试疙。FutureTask里面可以傳入一個Callable的具體實現(xiàn)類诵棵,可以對這個異步運算的任務(wù)的結(jié)果進行等待獲取、判斷是否已經(jīng)完成祝旷、取消任務(wù)等操作履澳。當(dāng)然,由于FutureTask也是Runnable接口的實現(xiàn)類怀跛,所以FutureTask也可以放入線程池中距贷。
3、Linux環(huán)境下如何查找哪個線程使用CPU最長
這是一個比較偏實踐的問題吻谋,這種問題我覺得挺有意義的忠蝗。可以這么做:
(1)獲取項目的pid漓拾,jps或者ps -ef | grep java阁最,這個前面有講過
(2)top -H -p pid,順序不能改變
這樣就可以打印出當(dāng)前的項目骇两,每條線程占用CPU時間的百分比速种。注意這里打出的是LWP,也就是操作系統(tǒng)原生線程的線程號低千,我筆記本山?jīng)]有部署Linux環(huán)境下的Java工程配阵,因此沒有辦法截圖演示,網(wǎng)友朋友們?nèi)绻臼鞘褂肔inux環(huán)境部署項目的話示血,可以嘗試一下棋傍。
使用"top -H -p pid"+"jps pid"可以很容易地找到某條占用CPU高的線程的線程堆棧,從而定位占用CPU高的原因难审,一般是因為不當(dāng)?shù)拇a操作導(dǎo)致了死循環(huán)瘫拣。
最后提一點,"top -H -p pid"打出來的LWP是十進制的告喊,"jps pid"打出來的本地線程號是十六進制的拂铡,轉(zhuǎn)換一下,就能定位到占用CPU高的線程的當(dāng)前線程堆棧了葱绒。
4、Java編程寫一個會導(dǎo)致死鎖的程序
第一次看到這個題目斗锭,覺得這是一個非常好的問題地淀。很多人都知道死鎖是怎么一回事兒:線程A和線程B相互等待對方持有的鎖導(dǎo)致程序無限死循環(huán)下去。當(dāng)然也僅限于此了岖是,問一下怎么寫一個死鎖的程序就不知道了帮毁,這種情況說白了就是不懂什么是死鎖实苞,懂一個理論就完事兒了,實踐中碰到死鎖的問題基本上是看不出來的烈疚。
真正理解什么是死鎖黔牵,這個問題其實不難,幾個步驟:
1)兩個線程里面分別持有兩個Object對象:lock1和lock2爷肝。這兩個lock作為同步代碼塊的鎖猾浦;
2)線程1的run()方法中同步代碼塊先獲取lock1的對象鎖,Thread.sleep(xxx)灯抛,時間不需要太多金赦,50毫秒差不多了,然后接著獲取lock2的對象鎖对嚼。這么做主要是為了防止線程1啟動一下子就連續(xù)獲得了lock1和lock2兩個對象的對象鎖
3)線程2的run)(方法中同步代碼塊先獲取lock2的對象鎖夹抗,接著獲取lock1的對象鎖,當(dāng)然這時lock1的對象鎖已經(jīng)被線程1鎖持有纵竖,線程2肯定是要等待線程1釋放lock1的對象鎖的
這樣漠烧,線程1"睡覺"睡完,線程2已經(jīng)獲取了lock2的對象鎖了靡砌,線程1此時嘗試獲取lock2的對象鎖已脓,便被阻塞,此時一個死鎖就形成了乏奥。代碼就不寫了摆舟,占的篇幅有點多,Java多線程7:死鎖這篇文章里面有邓了,就是上面步驟的代碼實現(xiàn)恨诱。
點擊提供了一個死鎖的案例。
5骗炉、怎么喚醒一個阻塞的線程
如果線程是因為調(diào)用了wait()照宝、sleep()或者join()方法而導(dǎo)致的阻塞,可以中斷線程句葵,并且通過拋出InterruptedException來喚醒它厕鹃;如果線程遇到了IO阻塞,無能為力乍丈,因為IO是操作系統(tǒng)實現(xiàn)的剂碴,Java代碼并沒有辦法直接接觸到操作系統(tǒng)。
小編分類整理了許多java進階學(xué)習(xí)材料和BAT面試題轻专,需要資料的請加QQ群:731611386就能領(lǐng)取2019年java進階學(xué)習(xí)資料和BAT面試題以及《EffectiveJava》(第3版)電子版書籍忆矛。