欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java中的自旋鎖與適應(yīng)性自旋鎖詳解

 更新時(shí)間:2023年10月13日 09:11:02   作者:yyangjun  
這篇文章主要介紹了Java中的自旋鎖與適應(yīng)性自旋鎖詳解,在多處理器環(huán)境中某些資源的有限性,有時(shí)需要互斥訪問,這時(shí)候就需要引入鎖的概念,只有獲取了鎖的線程才能對(duì)資源進(jìn)行訪問,多線程的核心是CPU的時(shí)間分片,所以同一時(shí)刻只能有一個(gè)線程獲取到鎖,需要的朋友可以參考下

一、為什么需要自旋鎖與適應(yīng)性自旋鎖

1.1、自旋鎖的提出背景

由于在多處理器環(huán)境中某些資源的有限性,有時(shí)需要互斥訪問,這時(shí)候就需要引入鎖的概念,只有獲取了鎖的線程才能對(duì)資源進(jìn)行訪問,由于多線程的核心是CPU的時(shí)間分片,所以同一時(shí)刻只能有一個(gè)線程獲取到鎖。那么就面臨一個(gè)問題,那么沒有獲取到鎖的線程應(yīng)該怎么辦?

通常有兩種處理方式:

  1. 一種是沒有獲取到鎖的線程就一直循環(huán)等待判斷該資源是否已經(jīng)釋放鎖,這種鎖叫做自旋鎖,它不用將線程阻塞起來(lái)(NON-BLOCKING);
  2. 還有一種處理方式就是把自己阻塞起來(lái),等待重新調(diào)度請(qǐng)求,這種叫做互斥鎖。

使用自旋鎖的最大的一個(gè)好處是因?yàn)樽孕i存在于linux內(nèi)核中,如果持有鎖的線程能夠在短時(shí)間內(nèi)釋放鎖,那么那些等待競(jìng)爭(zhēng)鎖的線程就不需要做內(nèi)核態(tài)與用戶態(tài)之間的切換從而進(jìn)入阻塞狀態(tài)。

二、自旋鎖與適應(yīng)性自旋鎖底層原理解析

2.1、自旋鎖與適應(yīng)性自旋鎖底層原理解析

自旋鎖早在JDK1.4 中就引入了,只是當(dāng)時(shí)默認(rèn)時(shí)關(guān)閉的。在JDK 1.6后默認(rèn)為開啟狀態(tài)。自旋鎖本質(zhì)上與阻塞并不相同,先不考慮其對(duì)多處理器的要求,如果鎖占用的時(shí)間非常的短,那么自旋鎖的性能會(huì)非常的好,相反,其會(huì)帶來(lái)更多的性能開銷(因?yàn)樵诰€程自旋時(shí),始終會(huì)占用CPU的時(shí)間片,如果鎖占用的時(shí)間太長(zhǎng),那么自旋的線程會(huì)白白消耗掉CPU資源)。

因此自旋等待的時(shí)間必須要有一定的限度,如果自旋超過了限定的次數(shù)仍然沒有成功獲取到鎖,就應(yīng)該使用傳統(tǒng)的方式去掛起線程了,在JDK定義中,自旋鎖默認(rèn)的自旋次數(shù)為10次,用戶可以使用參數(shù)-XX:PreBlockSpin來(lái)更改。

可是現(xiàn)在又出現(xiàn)了一個(gè)問題:如果線程鎖在線程自旋剛結(jié)束就釋放掉了鎖,那么是不是有點(diǎn)得不償失。所以這時(shí)候我們需要更加聰明的鎖來(lái)實(shí)現(xiàn)更加靈活的自旋。來(lái)提高并發(fā)的性能。(這里則需要自適應(yīng)自旋鎖!) 在JDK 1.6中引入了自適應(yīng)自旋鎖。

這就意味著自旋的時(shí)間不再固定了,而是由前一次在同一個(gè)鎖上的自旋 時(shí)間及鎖的擁有者的狀態(tài)來(lái)決定的。如果在同一個(gè)鎖對(duì)象上,自旋等待剛剛成功獲取過鎖,并且持有鎖的線程正在運(yùn)行中,那么JVM會(huì)認(rèn)為該鎖自旋獲取到鎖的可能性很大,會(huì)自動(dòng)增加等待時(shí)間。比如增加到100此循環(huán)。相反,如果對(duì)于某個(gè)鎖,自旋很少成功獲取鎖。

那再以后要獲取這個(gè)鎖時(shí)將可能省略掉自旋過程,以避免浪費(fèi)處理器資源。有了自適應(yīng)自旋,JVM對(duì)程序的鎖的狀態(tài)預(yù)測(cè)會(huì)越來(lái)越準(zhǔn)確,JVM也會(huì)越來(lái)越聰明。

三、自旋鎖與適應(yīng)性自旋鎖的使用

3.1、自旋鎖的實(shí)現(xiàn)

public class SpinLockTest {
	private AtomicBoolean available =new AtomicBoolean(false);
	public void lock(){
	    //循環(huán)檢測(cè)嘗試獲取鎖
	    while(!tryLock()){
	    //doSomething...
	    }
	}
    public boolean tryLock(){
    	//嘗試獲取鎖,成功返回true,失敗返回false
    	return available.compareAndSet(false,true);
    }
    public void unLock(){
    	if(!available.compareAndSet(false,true)){
    		throw new RuntimeException("釋放鎖失敗");
    	}
    }
}

3.2、適應(yīng)性自旋鎖的實(shí)現(xiàn)

自旋等待雖然避免了線程切換的開銷,但它要占用處理器時(shí)間。如果鎖被占用的時(shí)間很短,自旋等待的效果就會(huì)非常好。反之,如果鎖被占用的時(shí)間很長(zhǎng),那么自旋的線程只會(huì)白浪費(fèi)處理器資源。所以,自旋等待的時(shí)間必須要有一定的限度,如果自旋超過了限定次數(shù)(默認(rèn)是10次,可以使用-XX:PreBlockSpin來(lái)更改)沒有成功獲得鎖,就應(yīng)當(dāng)掛起線程。

自旋鎖的實(shí)現(xiàn)原理同樣也是CAS,AtomicInteger中調(diào)用unsafe進(jìn)行自增操作的源碼中的do-while循環(huán)就是一個(gè)自旋操作,如果修改數(shù)值失敗則通過循環(huán)來(lái)執(zhí)行自旋,直至修改成功。 改進(jìn)的自旋鎖主要有TicketLock、CLHLock、MCSLock,這幾種自旋鎖改進(jìn)方案內(nèi)容比較多,實(shí)現(xiàn)方式參考 幾種自旋鎖的java實(shí)現(xiàn)824b2e4f1eed

四、自旋鎖與適應(yīng)性自旋鎖中存在的問題與優(yōu)化方案

自旋鎖盡可能的減少線程的阻塞,這對(duì)于鎖的競(jìng)爭(zhēng)不激烈,且占用鎖時(shí)間非常短的代碼塊來(lái)說性能可以大幅度提升,因?yàn)樽孕南臅?huì)小于線程阻塞掛起再喚醒的操作的消耗,這些操作會(huì)導(dǎo)致線程發(fā)生兩次上下文切換!

但是如果鎖的競(jìng)爭(zhēng)激烈,或者持有鎖的線程需要長(zhǎng)時(shí)間占用鎖執(zhí)行同步塊,這時(shí)候就不適合使用自旋鎖了,因?yàn)樽孕i在獲取鎖前一直都是占用cpu做無(wú)用功,同時(shí)有大量線程在競(jìng)爭(zhēng)一個(gè)鎖,會(huì)導(dǎo)致獲取鎖的時(shí)間很長(zhǎng),線程自旋的消耗大于線程阻塞掛起操作的消耗,其它需要cup的線程又不能獲取到cpu,造成 cpu的浪費(fèi)。所以這種情況下我們要關(guān)閉自旋鎖;自旋鎖時(shí)間閾值(1.6 引入了適應(yīng)性自旋鎖)。

自旋鎖的目的是為了占著CPU的資源不釋放,等到獲取到鎖立即進(jìn)行處理。但是如何去選擇自旋的執(zhí)行時(shí)間呢?如果自旋執(zhí)行時(shí)間太長(zhǎng),會(huì)有大量的線程處于自旋狀態(tài)占用CPU資源,進(jìn)而會(huì)影響整體系統(tǒng)的性能。因此自旋的周期選的額外重要!

JVM 對(duì)于自旋周期的選擇,Jdk1.5這個(gè)限度是一定的寫死的,在1.6引入了適應(yīng)性自旋鎖,適應(yīng)性自旋鎖意味著自旋的時(shí)間不在是固定的了,而是由前一次在同一個(gè)鎖上的自旋時(shí)間以及鎖的擁有者的狀態(tài)來(lái)決定,基本認(rèn)為一個(gè)線程上下文切換的時(shí)間是最佳的一個(gè)時(shí)間,同時(shí)JVM還針對(duì)當(dāng)前CPU的負(fù)荷情況做了較多的優(yōu)化,如果平均負(fù)載小于CPUs則一直自旋,如果有超過(CPUs/2)個(gè)線程正在自旋,則后來(lái)線程直接阻塞,如果正在自旋的線程發(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)放棄線程優(yōu)先級(jí)之間的差異。

到此這篇關(guān)于Java中的自旋鎖與適應(yīng)性自旋鎖詳解的文章就介紹到這了,更多相關(guān)Java中的自旋鎖內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java程序執(zhí)行Cmd指令所遇問題記錄及解決方案

    Java程序執(zhí)行Cmd指令所遇問題記錄及解決方案

    這篇文章主要介紹了Java程序執(zhí)行Cmd指令所遇問題記錄,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-09-09
  • Java實(shí)現(xiàn)LRU緩存算法的參考示例

    Java實(shí)現(xiàn)LRU緩存算法的參考示例

    這篇文章主要介紹了JAVA實(shí)現(xiàn)LRU緩存算法的參考示例,幫助大家根據(jù)需求實(shí)現(xiàn)算法,對(duì)大家的學(xué)習(xí)或工作有一定的參考價(jià)值,需要的朋友可以參考下
    2023-05-05
  • 過濾器 和 攔截器的 6個(gè)區(qū)別(別再傻傻分不清了)

    過濾器 和 攔截器的 6個(gè)區(qū)別(別再傻傻分不清了)

    這篇文章主要介紹了過濾器 和 攔截器的 6個(gè)區(qū)別,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-06-06
  • java快速解析路徑中的參數(shù)(&與=拼接的參數(shù))

    java快速解析路徑中的參數(shù)(&與=拼接的參數(shù))

    這篇文章主要介紹了java快速解析路徑中的參數(shù)(&與=拼接的參數(shù)),本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2024-02-02
  • Java利用反射動(dòng)態(tài)設(shè)置對(duì)象字段值的實(shí)現(xiàn)

    Java利用反射動(dòng)態(tài)設(shè)置對(duì)象字段值的實(shí)現(xiàn)

    橋梁信息維護(hù)需要做到字段級(jí)別的權(quán)限控制,本文主要介紹了Java利用反射動(dòng)態(tài)設(shè)置對(duì)象字段值的實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-01-01
  • 圖文詳解Java中的字節(jié)輸入與輸出流

    圖文詳解Java中的字節(jié)輸入與輸出流

    在Java中所有數(shù)據(jù)都是使用流讀寫的,流是一組有序的數(shù)據(jù)序列,將數(shù)據(jù)從一個(gè)地方帶到另一個(gè)地方,這篇文章主要給大家介紹了關(guān)于Java中字節(jié)輸入與輸出流的相關(guān)資料,需要的朋友可以參考下
    2021-08-08
  • SpringBoot獲取Request對(duì)象的幾種方法

    SpringBoot獲取Request對(duì)象的幾種方法

    HttpServletRequest 簡(jiǎn)稱 Request,它是一個(gè) Servlet API 提供的對(duì)象,用于獲取客戶端發(fā)起的 HTTP 請(qǐng)求信息,那么問題來(lái)了,在 Spring Boot 中,獲取 Request 對(duì)象的方法有哪些?所以本文給大家介紹了SpringBoot獲取Request對(duì)象的幾種方法,需要的朋友可以參考下
    2024-11-11
  • MyBatis select標(biāo)簽的使用示例

    MyBatis select標(biāo)簽的使用示例

    MyBatis中,select 標(biāo)簽是最常用也是功能最強(qiáng)大的 SQL 語(yǔ)言,用于執(zhí)行查詢操作,本文就來(lái)介紹了MyBatis select標(biāo)簽的使用示例,具有一定的參考價(jià)值,感興趣的可以了解一下
    2023-10-10
  • 如何基于java向mysql數(shù)據(jù)庫(kù)中存取圖片

    如何基于java向mysql數(shù)據(jù)庫(kù)中存取圖片

    這篇文章主要介紹了如何基于java向mysql數(shù)據(jù)庫(kù)中存取圖片,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-02-02
  • Java調(diào)用wsdl接口的兩種方法(axis和wsimport)

    Java調(diào)用wsdl接口的兩種方法(axis和wsimport)

    本文主要介紹了Java調(diào)用wsdl接口的兩種方法(axis和wsimport),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-03-03

最新評(píng)論