日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

初识Lock与AbstractQueuedSynchronizer(AQS)

發(fā)布時(shí)間:2025/3/15 编程问答 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 初识Lock与AbstractQueuedSynchronizer(AQS) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

本文轉(zhuǎn)載于:https://juejin.im/post/5aeb055b6fb9a07abf725c8c

一、concurrent包的結(jié)構(gòu)層次

在針對(duì)并發(fā)編程中,Doug Lea大師為我們提供了大量實(shí)用,高性能的工具類,針對(duì)這些代碼進(jìn)行研究會(huì)讓我們隊(duì)并發(fā)編程的掌握更加透徹也會(huì)大大提升我們隊(duì)并發(fā)編程技術(shù)的熱愛。這些代碼在java.util.concurrent包下。如下圖,即為concurrent包的目錄結(jié)構(gòu)圖。

其中包含了兩個(gè)子包:atomic以及l(fā)ock,另外在concurrent下的阻塞隊(duì)列以及executors,這些就是concurrent包中的精華,之后會(huì)一一進(jìn)行學(xué)習(xí)。而這些類的實(shí)現(xiàn)主要是依賴于volatile以及CAS,從整體上來看concurrent包的整體實(shí)現(xiàn)圖如下圖所示:

二、lock簡介

我們下來看concurent包下的lock子包。鎖是用來控制多個(gè)線程訪問共享資源的方式,一般來說,一個(gè)鎖能夠防止多個(gè)線程同時(shí)訪問共享資源。在Lock接口出現(xiàn)之前,java程序主要是靠synchronized關(guān)鍵字實(shí)現(xiàn)鎖功能的,而java SE5之后,并發(fā)包中增加了lock接口,它提供了與synchronized一樣的鎖功能。雖然它失去了像synchronize關(guān)鍵字隱式加鎖解鎖的便捷性,但是卻擁有了鎖獲取和釋放的可操作性,可中斷的獲取鎖以及超時(shí)獲取鎖等多種synchronized關(guān)鍵字所不具備的同步特性。通常使用顯式使用lock的形式如下:

Lock lock = new ReentrantLock(); lock.lock(); try{....... }finally{lock.unlock(); }

需要注意的是synchronized同步塊執(zhí)行完成或者遇到異常是鎖會(huì)自動(dòng)釋放,而lock必須調(diào)用unlock()方法釋放鎖,因此在finally塊中釋放鎖。

  • Lock接口API
    Lock接口定義的方法:
  • public interface Lock { void lock(); //獲取鎖 void lockInterruptibly() throws InterruptedException;//獲取鎖的過程能夠響應(yīng)中斷 boolean tryLock();//非阻塞式響應(yīng)中斷能立即返回,獲取鎖放回true反之返回fasle boolean tryLock(long time, TimeUnit unit) throws InterruptedException;//超時(shí)獲取鎖,在超時(shí)內(nèi)或者未中斷的情況下能夠獲取鎖 Condition newCondition();//獲取與lock綁定的等待通知組件,//當(dāng)前線程必須獲得了鎖才能進(jìn)行等待,//進(jìn)行等待時(shí)會(huì)先釋放鎖,當(dāng)再次獲取鎖時(shí)才能從等待中返回 }
  • locks包下有哪些類實(shí)現(xiàn)了Lock接口
    從最熟悉的ReentrantLock說起
  • public class ReentrantLock implements Lock, java.io.Serializable

    很顯然ReentrantLock實(shí)現(xiàn)了lock接口,接下來我們來仔細(xì)研究一下它是怎樣實(shí)現(xiàn)的。當(dāng)你查看源碼時(shí)你會(huì)驚訝的發(fā)現(xiàn)ReentrantLock并沒有多少代碼,另外有一個(gè)很明顯的特點(diǎn)是:基本上所有的方法的實(shí)現(xiàn)實(shí)際上都是調(diào)用了其靜態(tài)內(nèi)存類Sync中的方法,而Sync類繼承了AbstractQueuedSynchronizer(AQS)。可以看出要想理解ReentrantLock關(guān)鍵核心在于對(duì)隊(duì)列同步器AbstractQueuedSynchronizer(簡稱同步器)的理解。

    三、初識(shí)AQS

  • 根據(jù)源碼注釋翻譯如下:
  • 同步器是用來構(gòu)建鎖和其他同步組件的基礎(chǔ)框架,它的實(shí)現(xiàn)主要依賴一個(gè)int成員變量來表示同步狀態(tài)以及通過一個(gè)FIFO隊(duì)列構(gòu)成等待隊(duì)列。它的子類必須重寫AQS的幾個(gè)protected修飾的用來改變同步狀態(tài)的方法,其他方法主要是實(shí)現(xiàn)了排隊(duì)和阻塞機(jī)制。狀態(tài)的更新使用getState,setState以及compareAndSetState這三個(gè)方法。
    子類被推薦定義為自定義同步組件的靜態(tài)內(nèi)部類,同步器自身沒有實(shí)現(xiàn)任何同步接口,它僅僅是定義了若干同步狀態(tài)的獲取和釋放方法來供自定義同步組件的使用,同步器既支持獨(dú)占式獲取同步狀態(tài),也可以支持共享式獲取同步狀態(tài),這樣就可以方便的實(shí)現(xiàn)不同類型的同步組件。
    同步器是實(shí)現(xiàn)鎖(也可以是任意同步組件)的關(guān)鍵,在鎖的實(shí)現(xiàn)中聚合同步器,利用同步器實(shí)現(xiàn)鎖的語義。可以這樣理解二者的關(guān)系:鎖是面向使用者,它定義了使用者與鎖交互的接口,隱藏了實(shí)現(xiàn)細(xì)節(jié);同步器是面向鎖的實(shí)現(xiàn)者,它簡化了鎖的實(shí)現(xiàn)方式,屏蔽了同步狀態(tài)的管理,線程的排隊(duì),等待和喚醒等底層操作。鎖和同步器很好的隔離了使用者和實(shí)現(xiàn)者所需關(guān)注的領(lǐng)域。

  • AQS的模板方法設(shè)計(jì)模式
    AQS的設(shè)計(jì)是使用模板方法設(shè)計(jì)模式,它將一些方法開放給子類進(jìn)行重寫,而同步器給同步組件所提供模板方法又會(huì)重新調(diào)用被子類所重寫的方法。舉個(gè)例子,AQS中需要重寫的方法tryAcquire:
  • protected boolean tryAcquire(int arg) {throw new UnsupportedOperationException(); }

    ReentrantLock中NonfairSync(繼承AQS)會(huì)重寫該方法為:

    protected final boolean tryAcquire(int acquires) {return nonfairTryAcquire(acquires); }

    而AQS中的模板方法acquire():

    public final void acquire(int arg) {if (!tryAcquire(arg) &&acquireQueued(addWaiter(Node.EXCLUSIVE), arg))selfInterrupt();}

    會(huì)調(diào)用tryAcquire方法,而此時(shí)當(dāng)繼承AQS的NonfairSync調(diào)用模板方法acquire時(shí)就會(huì)調(diào)用已經(jīng)被NonfairSync重寫的tryAcquire方法。這就是使用AQS的方式,在弄懂這點(diǎn)后會(huì)lock的實(shí)現(xiàn)理解有很大的提升。可以歸納總結(jié)為這么幾點(diǎn):

    1.同步組件(這里不僅僅值鎖,還包括CountDownLatch等)的實(shí)現(xiàn)依賴于同步器AQS,在同步組件實(shí)現(xiàn)中,使用AQS的方式被推薦定義繼承AQS的靜態(tài)內(nèi)存類;

    2.AQS采用模板方法進(jìn)行設(shè)計(jì),AQS的protected修飾的方法需要由繼承AQS的子類進(jìn)行重寫實(shí)現(xiàn),當(dāng)調(diào)用AQS的子類的方法時(shí)就會(huì)調(diào)用被重寫的方法;
    3.AQS負(fù)責(zé)同步狀態(tài)的管理,線程的排隊(duì),等待和喚醒這些底層操作,而Lock等同步組件主要專注于實(shí)現(xiàn)同步語義;
    4.在重寫AQS的方式時(shí),使用AQS提供的getState(),setState(),compareAndSetState()方法進(jìn)行修改同步狀態(tài)

    AQS可重寫的方法如下圖(摘自《java并發(fā)編程的藝術(shù)》一書):

    在實(shí)現(xiàn)同步組件時(shí)AQS提供的模板方法如下圖:

  • AQS提供的模板方法可以分為3類:
  • 獨(dú)占式獲取與釋放同步狀態(tài);
    共享式獲取與釋放同步狀態(tài);
    查詢同步隊(duì)列中等待線程情況;

    同步組件通過AQS提供的模板方法實(shí)現(xiàn)自己的同步語義。

    總結(jié)

    以上是生活随笔為你收集整理的初识Lock与AbstractQueuedSynchronizer(AQS)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。