一. JVM 對(duì) Java 的原生鎖做了哪些優(yōu)化?
1. 自旋鎖
在線程進(jìn)行阻塞的時(shí)候,先讓線程自旋等待一段時(shí)間,可能這段時(shí)間其它線程已經(jīng)解鎖,這時(shí)就無需讓線程再進(jìn)行阻塞操作了。 自旋默認(rèn)次數(shù)是10次。
2. 自適應(yīng)自旋鎖
自旋鎖的升級(jí),自旋的次數(shù)不再固定,由前一次自旋次數(shù)和鎖的擁有者的狀態(tài)決定。
3. 鎖消除
在動(dòng)態(tài)編譯同步代碼塊的時(shí)候,JIT編譯器借助逃逸分析技術(shù)來判斷鎖對(duì)象是否只被一個(gè)線程訪問,而沒有其他線程,這時(shí)就可以取消鎖了。
4. 鎖粗化
當(dāng)JIT編譯器發(fā)現(xiàn)一系列的操作都對(duì)同一個(gè)對(duì)象反復(fù)加鎖解鎖,甚至加鎖操作出現(xiàn)在循環(huán)中,此時(shí)會(huì)將加鎖同步的范圍粗化到整個(gè)操作系列的外部。
鎖粒度:不要鎖住一些無關(guān)的代碼。
鎖粗化:可以一次性執(zhí)行完的不要多次加鎖執(zhí)行。
二. 為什么wait()、notify()和 notifyAll()必須在同步方法或者同步塊中被調(diào)用?
Java中,任何對(duì)象都可以作為鎖,并且 wait(),notify()等方法用于等待對(duì)象的鎖或者喚醒線程,在 Java 的線程中并沒有可供任何對(duì)象使用的鎖,所以任意對(duì)象調(diào)用方法一定定義在Object類中。
wait(), notify()和 notifyAll()這些方法在同步代碼塊中調(diào)用。
有的人會(huì)說,既然是線程放棄對(duì)象鎖,那也可以把wait()定義在Thread類里面啊,新定義的線程繼承于Thread類,也不需要重新定義wait()方法的實(shí)現(xiàn)。然而,這樣做有一個(gè)非常大的問題,一個(gè)線程完全可以持有很多鎖,你一個(gè)線程放棄鎖的時(shí)候,到底要放棄哪個(gè)鎖?當(dāng)然了,這種設(shè)計(jì)并不是不能實(shí)現(xiàn),只是管理起來更加復(fù)雜。
綜上所述,wait()、notify()和notifyAll()方法要定義在Object類中。
三. Java 如何實(shí)現(xiàn)多線程之間的通訊和協(xié)作?
可以通過中斷 和 共享變量的方式實(shí)現(xiàn)線程間的通訊和協(xié)作。
比如說最經(jīng)典的生產(chǎn)者-消費(fèi)者模型。當(dāng)隊(duì)列滿時(shí),生產(chǎn)者需要等待隊(duì)列有空間才能繼續(xù)往里面放入商品,而在等待的期間內(nèi),生產(chǎn)者必須釋放對(duì)臨界資源(即隊(duì)列)的占用權(quán)。因?yàn)樯a(chǎn)者如果不釋放對(duì)臨界資源的占用權(quán),那么消費(fèi)者就無法消費(fèi)隊(duì)列中的商品,就不會(huì)讓隊(duì)列有空間,那么生產(chǎn)者就會(huì)一直無限等待下去。因此,一般情況下,當(dāng)隊(duì)列滿時(shí),會(huì)讓生產(chǎn)者交出對(duì)臨界資源的占用權(quán),并進(jìn)入掛起狀態(tài)。然后等待消費(fèi)者消費(fèi)了商品,然后消費(fèi)者通知生產(chǎn)者隊(duì)列有空間了。同樣地,當(dāng)隊(duì)列空時(shí),消費(fèi)者也必須等待,等待生產(chǎn)者通知它隊(duì)列中有商品了。這種互相通信的過程就是線程間的協(xié)作。
Java中線程通信協(xié)作的最常見的兩種方式:
syncrhoized加鎖的線程的Object類的wait()/notify()/notifyAll()
ReentrantLock類加鎖的線程的Condition類的await()/signal()/signalAll()
通過管道進(jìn)行線程間通信:
字節(jié)流;
字符流
四. Thread 類中的 yield 方法有什么作用?
yield()應(yīng)該做的是讓當(dāng)前運(yùn)行線程回到可運(yùn)行狀態(tài),以允許具有相同優(yōu)先級(jí)的其他線程獲得運(yùn)行機(jī)會(huì)。因此,使用yield()的目的是讓相同優(yōu)先級(jí)的線程之間能適當(dāng)?shù)妮嗈D(zhuǎn)執(zhí)行。但是,實(shí)際中無法保證yield()達(dá)到讓步目的,因?yàn)樽尣降木€程還有可能被線程調(diào)度程序再次選中。
結(jié)論:yield()從未導(dǎo)致線程轉(zhuǎn)到等待/睡眠/阻塞狀態(tài)。在大多數(shù)情況下,yield()將導(dǎo)致線程從運(yùn)行狀態(tài)轉(zhuǎn)到可運(yùn)行狀態(tài),但有可能沒有效果。
更多關(guān)于“Java培訓(xùn)”的問題,歡迎咨詢千鋒教育在線名師。千鋒已有十余年的培訓(xùn)經(jīng)驗(yàn),課程大綱更科學(xué)更專業(yè),有針對(duì)零基礎(chǔ)的就業(yè)班,有針對(duì)想提升技術(shù)的好程序員班,高品質(zhì)課程助力你實(shí)現(xiàn)java程序員夢(mèng)想。