并發(fā)編程-AQS同步器

上一篇 <<<Java基礎(chǔ)-對(duì)象布局
下一篇 >>>Condition


AQS(AbstractQueuedSynchronizer同步器):它提供了一個(gè)FIFO隊(duì)列,是用來(lái)構(gòu)建鎖或者其他同步組件的基礎(chǔ)框架。
AQS是一個(gè)抽象類,主要是通過(guò)繼承的方式來(lái)使用,它本身沒(méi)有實(shí)現(xiàn)任何的同步接口,僅僅是定義了同步狀態(tài)的獲取以及釋放的方法來(lái)提供自定義的同步組件。

常用框架

ReentrantLock、Fork/Join、CountDownLatch(計(jì)數(shù)器)、Semaphore(限流信號(hào)量)等

底層實(shí)現(xiàn)原理

結(jié)合CAS compareAndSwapInt實(shí)現(xiàn)。

執(zhí)行流程圖

Condition 單向鏈表,調(diào)用await釋放鎖,當(dāng)前線程阻塞。

核心參數(shù)
a.Node結(jié)點(diǎn) 采用雙向鏈表的形式存放正在等待的線程 waitStatus狀態(tài)、thread等到鎖的線程
CANCELLED,值為1,表示當(dāng)前的線程被取消;
SIGNAL,值為-1,釋放資源后需喚醒后繼節(jié)點(diǎn);
CONDITION,值為-2, 等待condition喚醒;
PROPAGATE,值為-3,工作于共享鎖狀態(tài),需要向后傳播,比如根據(jù)資源是否剩余,喚醒后繼節(jié)點(diǎn);
值為0,表示當(dāng)前節(jié)點(diǎn)在sync隊(duì)列中,等待著獲取鎖。
b.Head 頭結(jié)點(diǎn) 等待隊(duì)列的頭結(jié)點(diǎn)
c.Tail 尾結(jié)點(diǎn) 正在等待的線程
d.State 鎖的狀態(tài) 0無(wú)鎖、1已經(jīng)有線程獲取鎖,默認(rèn)為0
當(dāng)前線程重入時(shí)State不斷+1 ,當(dāng)調(diào)用unlock方法時(shí)State-1,完全釋放鎖的情況下歸零,且設(shè)置exclusiveOwnerThread=null
e.exclusiveOwnerThread 記錄鎖的持有

核心方法
tryAcquire ---重試獲取鎖
tryRelease--釋放鎖
acquireSharedInterruptibly---將當(dāng)前線程變?yōu)樽枞麪顟B(tài)
releaseShared ---讓等待的線程,被喚醒 同時(shí)狀態(tài)變?yōu)?

AQS為什么頭結(jié)點(diǎn)是為空的

頭結(jié)點(diǎn)存儲(chǔ)的是獲取到鎖的線程,當(dāng)釋放鎖的時(shí)候就將對(duì)象置空,方便GC回收,防止浪費(fèi)內(nèi)存空間。

模擬AQS的底層寫法(LockSupport+CAS的結(jié)合實(shí)現(xiàn))核心代碼

/**
 * 獲取鎖
 */
public void lock() {
    //e=0,n=1 v=0
    // 底層使用cas 修改鎖的狀態(tài)從0變?yōu)?  硬件層面幫助我們實(shí)現(xiàn)
    if (acquire()) {
        return;
    }
    // 使用cas 修改鎖的狀態(tài)失敗 設(shè)計(jì)重試次數(shù)
    Thread currentThread = Thread.currentThread();
    // 如果該線程已經(jīng)存在的情況下
    waitThreads.add(currentThread);
    for (; ; ) {
        //短暫重試
        if (acquire()) {
            // 移除隊(duì)列
            waitThreads.push(currentThread);
            return;
        }
        // 重試一次還是沒(méi)有獲取到鎖,將當(dāng)前的這個(gè)線程變?yōu)樽枞麪顟B(tài)
        LockSupport.park();
    }
}

/**
 * 釋放鎖
 */
public void unLock() {
    if (exclusiveOwnerThread != Thread.currentThread()) {
        throw new RuntimeException("不是當(dāng)前線程在釋放鎖");
    }
    // 釋放鎖
    if (compareAndSetState(1, 0)) {
        this.exclusiveOwnerThread = null;
        // 取出阻塞的線程 喚醒
        Thread pollThread = waitThreads.poll();
        if (pollThread != null)
            // 喚醒剛才阻塞的線程
            LockSupport.unpark(pollThread);
    }
}

相關(guān)文章鏈接:
<<<多線程基礎(chǔ)
<<<線程安全與解決方案
<<<鎖的深入化
<<<鎖的優(yōu)化
<<<Java內(nèi)存模型(JMM)
<<<Volatile解決JMM的可見(jiàn)性問(wèn)題
<<<Volatile的偽共享和重排序
<<<CAS無(wú)鎖模式及ABA問(wèn)題
<<<Synchronized鎖
<<<Lock鎖
<<<Condition
<<<CountDownLatch同步計(jì)數(shù)器
<<<Semaphore信號(hào)量
<<<CyclicBarrier屏障
<<<線程池
<<<并發(fā)隊(duì)列
<<<Callable與Future模式
<<<Fork/Join框架
<<<Threadlocal
<<<Disruptor框架
<<<如何優(yōu)化多線程總結(jié)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容