更新時(shí)間:2020-05-26 來(lái)源:黑馬程序員 瀏覽量:
自旋鎖原理非常簡(jiǎn)單,如果持有鎖的線(xiàn)程能在很短時(shí)間內(nèi)釋放鎖資源,那么那些等待競(jìng)爭(zhēng)鎖的線(xiàn)程就不需要做內(nèi)核態(tài)和用戶(hù)態(tài)之間的切換進(jìn)入阻塞掛起狀態(tài),它們只需要等一等(自旋),等持有鎖的線(xiàn)程釋放鎖后即可立即獲取鎖,這樣就避免用戶(hù)線(xiàn)程和內(nèi)核的切換的消耗。
線(xiàn)程自旋是需要消耗cup的,說(shuō)白了就是讓cup在做無(wú)用功,如果一直獲取不到鎖,那線(xiàn)程也不能一直占用cup自旋做無(wú)用功,所以需要設(shè)定一個(gè)自旋等待的最大時(shí)間。
如果持有鎖的線(xiàn)程執(zhí)行的時(shí)間超過(guò)自旋等待的最大時(shí)間扔沒(méi)有釋放鎖,就會(huì)導(dǎo)致其它爭(zhēng)用鎖的線(xiàn)程在最大等待時(shí)間內(nèi)還是獲取不到鎖,這時(shí)爭(zhēng)用線(xiàn)程會(huì)停止自旋進(jìn)入阻塞狀態(tài)。
自旋鎖有什么優(yōu)缺點(diǎn)?
自旋鎖盡可能的減少線(xiàn)程的阻塞,這對(duì)于鎖的競(jìng)爭(zhēng)不激烈,且占用鎖時(shí)間非常短的代碼塊來(lái)說(shuō)性能可以大幅度提升,因?yàn)樽孕南臅?huì)小于線(xiàn)程阻塞掛起再喚醒的操作的消耗,這些操作會(huì)導(dǎo)致線(xiàn)程發(fā)生兩次上下文切換!
但是如果鎖的競(jìng)爭(zhēng)激烈,或者持有鎖的線(xiàn)程需要長(zhǎng)時(shí)間占用鎖執(zhí)行同步塊,這時(shí)候就不適合使用自旋鎖了,因?yàn)樽孕i在獲取鎖前一直都是占用cpu做無(wú)用功,同時(shí)有大量線(xiàn)程在競(jìng)爭(zhēng)一個(gè)鎖,會(huì)導(dǎo)致獲取鎖的時(shí)間很長(zhǎng),線(xiàn)程自旋的消耗大于線(xiàn)程阻塞掛起操作的消耗,其它需要cup的線(xiàn)程又不能獲取到cpu,造成 cpu的浪費(fèi)。所以這種情況下我們要關(guān)閉自旋鎖;自旋鎖時(shí)間閾值(1.6 引入了適應(yīng)性自旋鎖)。
自旋鎖的目的是為了占著CPU的資源不釋放,等到獲取到鎖立即進(jìn)行處理。但是如何去選擇自旋的執(zhí)行時(shí)間呢?如果自旋執(zhí)行時(shí)間太長(zhǎng),會(huì)有大量的線(xiàn)程處于自旋狀態(tài)占用CPU資源,進(jìn)而會(huì)影響整體系統(tǒng)的性能。因此自旋的周期選的額外重要!
JVM 對(duì)于自旋周期的選擇,Jdk1.5這個(gè)限度是一定的寫(xiě)死的,在1.6引入了適應(yīng)性自旋鎖,適應(yīng)性自旋鎖意味著自旋的時(shí)間不在是固定的了,而是由前一次在同一個(gè)鎖上的自旋時(shí)間以及鎖的擁有者的狀態(tài)來(lái)決定,基本認(rèn)為一個(gè)線(xiàn)程上下文切換的時(shí)間是最佳的一個(gè)時(shí)間,同時(shí)JVM還針對(duì)當(dāng)前CPU的負(fù)荷情況做了較多的優(yōu)化,如果平均負(fù)載小于CPUs則一直自旋,如果有超過(guò)(CPUs/2)個(gè)線(xiàn)程正在自旋,則后來(lái)線(xiàn)程直接阻塞,如果正在自旋的線(xiàn)程發(fā)現(xiàn)Owner發(fā)生了變化則延遲自旋時(shí)間(自旋計(jì)數(shù))或進(jìn)入阻塞,如果 CPU 處于節(jié)電模式則停止自旋,自旋時(shí)間的最壞情況是CPU的存儲(chǔ)延遲(CPU A 存儲(chǔ)了一個(gè)數(shù)據(jù),到CPU B得知這個(gè)數(shù)據(jù)直接的時(shí)間差),自旋時(shí)會(huì)適當(dāng)放棄線(xiàn)程優(yōu)先級(jí)之間的差異。
以上我們介紹了自旋鎖的原理和優(yōu)缺點(diǎn)希望對(duì)你有所幫助,如果您系統(tǒng)學(xué)習(xí)java提升java技術(shù)能力,推薦了解黑馬程序員java中級(jí)程序員培訓(xùn)課程。
在黑馬程序員學(xué)習(xí)java是什么體驗(yàn)?下面我們通過(guò)一個(gè)視頻來(lái)了解
猜你喜歡