1. 程式人生 > >ReentrantLock工作原理分析

ReentrantLock工作原理分析

ReentrantLock是一個可重入鎖,意思就是說可以遞迴的呼叫鎖,而不會因為遞迴進入加鎖方法而發生死鎖,這裡後面會新增解釋 

ReentrantLock是基於AQS實現,其原理和AQS大致相同,分為公平鎖和非公平鎖,他們都會維護一個CLH雙端佇列,本質上是一

個雙端連結串列,本質上都要繼承AQS並重寫相應的方法 tryAcquire()方法 還有tryRelease()

final void lock() { acquire(1);}

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

 嘗試獲取鎖 acquire的意思是 嘗試獲取鎖tryAcquire()方法如果返回true 說明獲取鎖成功 直接返回去執行業務程式碼 如果失敗 看下一個方法判斷acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) 包裝成一個節點新增到CLH佇列中

protected final boolean tryAcquire(int acquires) {
   final Thread current = Thread.currentThread();
   int c = getState();
   if (c == 0) {
       if (!hasQueuedPredecessors() &&
           compareAndSetState(0, acquires)) {
           setExclusiveOwnerThread(current);
           return true;
       }
   }
   else if (current == getExclusiveOwnerThread()) {
       int nextc = c + acquires;
       if (nextc < 0)
           throw new Error("Maximum lock count exceeded");
       setState(nextc);
       return true;
   }
   return false;
}

如果state是0並且CLH佇列中沒有節點就嘗試做CAS更改state的值得操作 返回true 執行業務程式碼 要求提現了公平性,排隊佇列的特性 如果不符合 ok 看下一條

private Node addWaiter(Node mode) {
   Node node = new Node(Thread.currentThread(), mode);
   // Try the fast path of enq; backup to full enq on failure
   Node pred = tail;
   if (pred != null) {
       node.prev = pred;
       if (compareAndSetTail(pred, node)) {
           pred.next = node;
           return node;
       }
   }
   enq(node);
   return node;
}

包裝成節點先一次嘗試新增到CLH佇列中去 如果不成功 操作enq()方法 

private Node enq(final Node node) {
    for (;;) {
        Node t = tail;
        if (t == null) { // Must initialize
            if (compareAndSetHead(new Node()))
                tail = head;
        } else {
            node.prev = t;
            if (compareAndSetTail(t, node)) {
                t.next = node;
                return t;
            }
        }
    }
}

自旋CAS併發處理的新增到CLH佇列中去 

final boolean acquireQueued(final Node node, int arg) {
    boolean failed = true;
    try {
        boolean interrupted = false;
        for (;;) {
            //1
            final Node p = node.predecessor();
            if (p == head && tryAcquire(arg)) {
                setHead(node);
                p.next = null; // help GC
                failed = false;
                return interrupted;
            }
            //2
            if (shouldParkAfterFailedAcquire(p, node) &&
                parkAndCheckInterrupt())
                interrupted = true;
        }
    } finally {
        if (failed)
            cancelAcquire(node);
    }
}

新增到佇列中去了 要對節點做相應的處理 會嘗試喚醒節點 如果有方法呼叫了release方法 那麼就會喚醒重新開始自旋CAS 如果是頭結點的下一個節點 就可以嘗試獲得鎖 

解鎖 

public void unlock() {
    sync.release(1);
}
public final boolean release(int arg) {
    if (tryRelease(arg)) {
        Node h = head;
        if (h != null && h.waitStatus != 0)
            unparkSuccessor(h);
        return true;
    }
    return false;
}

喚醒節點 本質上是喚醒h節點的下一個節點 

protected final boolean tryRelease(int releases) {
    int c = getState() - releases;
    if (Thread.currentThread() != getExclusiveOwnerThread())
        throw new IllegalMonitorStateException();
    boolean free = false;
    if (c == 0) {
        free = true;
        setExclusiveOwnerThread(null);
    }
    setState(c);
    return free;
}

只有state等於0的時候才會返回true 意味著這是可重入鎖 可以多次加鎖 最後也需要多次解鎖 直到state等於0 

private void unparkSuccessor(Node node) {
    int ws = node.waitStatus;
    if (ws < 0)
        compareAndSetWaitStatus(node, ws, 0);

    Node s = node.next;
    if (s == null || s.waitStatus > 0) {
        s = null;
        for (Node t = tail; t != null && t != node; t = t.prev)
            if (t.waitStatus <= 0)
                s = t;
    }
    if (s != null)
        LockSupport.unpark(s.thread);
}

解鎖後一個節點 如果不成功(每一個節點都有多種狀態 可能被取消)就從最後一個節點開始往前遍歷做喚醒才做

LockSupport.unpark(s.thread);

喚醒後

final boolean acquireQueued(final Node node, int arg) {
    boolean failed = true;
    try {
        boolean interrupted = false;
        for (;;) {
            //1
            final Node p = node.predecessor();
            if (p == head && tryAcquire(arg)) {
                setHead(node);
                p.next = null; // help GC
                failed = false;
                return interrupted;
            }
            //2
            if (shouldParkAfterFailedAcquire(p, node) &&
                parkAndCheckInterrupt())
                interrupted = true;
        }
    } finally {
        if (failed)
            cancelAcquire(node);
    }
}

喚醒的節點會在自旋CAS中又嘗試獲取鎖 

非公平鎖不同

final void lock() {
    if (compareAndSetState(0, 1))
        setExclusiveOwnerThread(Thread.currentThread());
    else
        acquire(1);
}

先去搶先CAS改值 體現了搶佔式 非公平 不理會CLH佇列情況 其他的和公平鎖差不多了 

相關推薦

ReentrantLock工作原理分析

ReentrantLock是一個可重入鎖,意思就是說可以遞迴的呼叫鎖,而不會因為遞迴進入加鎖方法而發生死鎖,這裡後面會新增解釋  ReentrantLock是基於AQS實現,其原理和AQS大致相同,分為公平鎖和非公平鎖,他們都會維護一個CLH雙端佇列,本質上是一 個雙

LTC3780 工作原理分析

限制 誤差 bsp logs 分享 逆時針 一個 原理分析 工作原理 流程分析 當 CV調節 調節順時針調節CV的時候 接入電路部分的電阻變大 Vosense變小 LTC內部的誤差放大器 輸出的變大 LTC內部邏輯調節 增大電壓 我估計最終電壓還是大約800mv左右 可

激光切割機的工作原理分析

傳遞 切割 dex com clas title 分析 bubuko inf 激光切割機是一種最新的技術,目前已經運用到各種行業,包金屬切割、玻璃切割雕刻等廣泛領域。 激光切割機工作原理:激光通過激光器產生後由反射鏡傳遞並通過聚集鏡照射到加工物品上,使加工物品(表面)受到強

jdk TreeMap工作原理分析

fix boolean 不變 變量 get ... delete tails 總結 TreeMap是jdk中基於紅黑樹的一種map實現。HashMap底層是使用鏈表法解決沖突的哈希表,LinkedHashMap繼承自HashMap,內部同樣也是使用鏈表法解決沖突的哈希表,但

tcpkill工作原理分析

此文已由作者張耕源授權網易雲社群釋出。 歡迎訪問網易雲社群,瞭解更多網易技術產品運營經驗。 日常工作生活中大家在維護自己的伺服器、VPS有時會碰到這樣的情況:伺服器上突然出現了許多來自未知ip的網路連線與流量,我們需要第一時間切斷這些可能有害的網路連線。除了iptables/ipset, blackhole

ping 與 traceroute 的工作原理分析

一、ping        ping 程式的主要目的是測試主機是否可達,它傳送 ICMP 回顯請求報文給目的主機,並等待返回 ICMP 回顯應答        ping 程式一般會週期性持續地傳送

spi協議及工作原理分析

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

AJ的筆記之上拉電阻的工作原理分析

第二章:聊一聊上拉電阻的工作原理 **********本文所採用的微控制器是:STC89C52RC系******************** 【重點提要】其實,理解上拉電阻的原理,關鍵是理解這兩個詞:鎖存器&開漏輸出。 (1)關於鎖存器 我們知道,微控制器是由微處理器、儲存器以及輸入輸出介面組

K8S 原始碼探祕 之 nginx-ingress 工作原理分析

一、引言        Nginx-ingress 是 Kubernetes 生態中的重要成員,主要負責向外暴露服務,同時提供負載均衡等附加功能;        截至目前,nginx-ingress 已經能夠

SpringCloud-Ribbon工作原理分析

由於歷史原因,原有業務系統的大部分介面都是通過SpringBoot RESTFul暴露服務的且能過Nginx做閘道器。微服務架構近幾年也非常的火,各個公司開始將業務服務  在使用Ribbon進行服務消費的時候,我們用到了RestTemplate,但是熟悉Spring的人

網路爬蟲工作原理分析

網路爬蟲工作原理  1、聚焦爬蟲工作原理及關鍵技術概述  網路爬蟲是一個自動提取網頁的程式,它為搜尋引擎從Internet網上下載網頁,是搜尋引擎的重要組成。傳統爬蟲從一個或若干初始網頁的URL開始,獲得初始網頁上的URL,在抓取網頁的過程中,不斷從當前頁面上抽取新的URL放入佇列,直到滿足系統的一定停止條件

Azure WAF防火牆工作原理分析和配置嚮導

作者:沙濤 轉自:http://www.cnblogs.com/taosha/p/6716434.html  本地資料中心往雲端遷移的的趨勢越來越明顯,安全始終是最熱門的話題之一。 本文討論的內容是Azure WAF,即微軟公有云Azure的Web application firewall(下均簡

Maven依賴機制 工作原理 (分析maven專案和非maven專案的差別)

一句話總結: 在 Maven 依賴機制的幫助下自動下載所有必需的依賴庫,並保持版本升級。   詳細解釋: 讓我們看一個案例研究,以瞭解它是如何工作的。假設你想使用 Log4j 作為專案的日誌。這裡你要

聯發科MT6139射頻處理器工作原理分析

MT6139工作原理:本電路為,射頻處理IC--MT6139+功放RF3146+天線開關LMSP33QA- 382TEMP組合。共同完成手機射頻訊號的的收發及RXI \Q基帶訊號的解調,和TXI \Q訊號的調製,以及發射與接收頻率合成電路。     &nb

汽車ABS結構和工作原理分析

          ABS的主體結構和液壓調節結構 基礎理論 汽車在行駛過程中,強制地減速以至停車且維持行駛方向穩定性的能力-----------汽車的制動性。 評價制動效能的指標 1)制動效能——汽車在行駛中,強制減速以至停車的能力稱為制動效能。 即汽車以一定的初速度制

kafka的工作原理分析(三) -- 高可用副本機制

一、副本機制簡介 在kafka中,topic是可以拆分為多個分割槽進行儲存資料的,每個分割槽儲存的資料都是不一樣的。在kafka的叢集環境下,為了避免出現單節點宕機導致的資料丟失迭代情況,kafka提供了一種分割槽資料的副本機制,保證在某個分割槽的讀寫節點宕機

SPI工作原理分析

說明.文章摘自:SPI協議及其工作原理淺析 http://bbs.chinaunix.net/thread-1916003-1-1.html 一、概述.      SPI, Serial Perripheral Interface, 序列外圍裝置介面, 是 Motorola 公司推出的一種同步序列介面技

三極體工作原理分析!精闢、透徹

隨著科學技的發展,電子技術的應用幾乎滲透到了人們生產生活的方方面面。晶體三極體作為電子技術中一個最為基本的常用器件,其原理對於學習電子技術的人自然應該是一個重點。三極體原理的關鍵是要說明以下三點: 1、集電結為何會發生反偏導通併產生Ic,這看起來與二極體原理強調的PN接面

Spark Streaming工作原理分析與使用

Spark Streaming入門1. 概述Spark Streaming 是 Spark Core API 的擴充套件, 它支援彈性的, 高吞吐的, 容錯的實時資料流的處理。spark streaming提供是一種分散式計算能力。資料來源資料可以通過多種資料來源獲取, 例如

spring原始碼分析之@ImportSelector、@Import、ImportResource工作原理分析

/** * Apply processing and build a complete {@link ConfigurationClass} by reading the * annotations, members and methods from the source class.