AQS源碼

博客地址:https://monkeysayhi.github.io/2017/12/05/%E6%BA%90%E7%A0%81%7C%E5%B9%B6%E5%8F%91%E4%B8%80%E6%9E%9D%E8%8A%B1%E4%B9%8BReentrantLock%E4%B8%8EAQS%EF%BC%881%EF%BC%89%EF%BC%9Alock%E3%80%81unlock/


ReentrantLock和ReentrantReadWriteLock從類的形式上看并沒有關(guān)聯(lián)宽堆,但是底層都是采用AQS的實(shí)現(xiàn)
我們知道我們JDK 的鎖都是基于AQS
而在其上面主要有讀寫鎖(即所謂的獨(dú)占鎖和非獨(dú)占鎖)
方法也只有l(wèi)ock 或者unlock
除了鎖 還有condition
這些鎖都支持可重入
公平鎖和非公平鎖的最大區(qū)別就是:非公平鎖是先嘗試獲取鎖哆窿,獲取不到在按照公平鎖的方法進(jìn)入隊(duì)列排隊(duì)獲取
鎖為什么不能升級--升級會死鎖稽物,目的也是為了數(shù)據(jù)可見性,如果讀鎖已經(jīng)被多個(gè)線程獲取加酵,其中任意線程成功獲取了寫鎖并且更新了數(shù)據(jù),這個(gè)更新對其他已經(jīng)獲取到讀鎖的線程是不可見的供屉。

  1. 當(dāng)有線程獲取讀鎖時(shí)往产,不允許再有線程獲得寫鎖

  2. 當(dāng)有線程獲得寫鎖時(shí),不允許其他線程獲得讀鎖和寫鎖

為什么要支持鎖降級
降級的過程為持有寫鎖撒犀,把持住不釋放并獲取讀鎖福压,然后再釋放寫鎖,如果釋放寫鎖再獲取讀鎖則不能稱之為鎖降級或舞。支持降級的原因是為了實(shí)現(xiàn)讀寫連續(xù)荆姆,減少線程切換的開銷。如果不能降級的話映凳,A線程在對數(shù)據(jù)修改完畢后立馬釋放寫鎖胆筒,假如A線程后續(xù)緊跟一個(gè)讀的操作,在獲取讀鎖之前B線程拿到了寫鎖诈豌,由于讀寫不能并發(fā)仆救,A線程就只能阻塞

首先我們分析下ReentrantLock

獲取鎖,如果獲取不到則會一直阻塞
不會響應(yīng)中斷
readLock.lock();
嘗試獲取鎖矫渔,獲取不到就返回 不會響應(yīng)中斷
readLock.tryLock();
獲取鎖彤蔽,如果獲取不到則會一直阻塞
會響應(yīng)中斷
readLock.lockInterruptibly();
嘗試獲取鎖,獲取不到就等待一段時(shí)間 會響應(yīng)中斷
readLock.tryLock(10,TimeUnit.SECONDS);

ReentrantLock的lock源碼
 public final void acquire(int arg) {
 首先嘗試獲取鎖失敗庙洼,則加入等待隊(duì)列顿痪,acquireQueued返回true代表
 在等待獲取鎖的過程中中斷過
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            因?yàn)橹爸袛嗪竽髟珹QS恢復(fù)了中斷標(biāo)識,這邊自我中斷下吧中斷標(biāo)識
            設(shè)置為true蚁袭。這樣如果有業(yè)務(wù)邏輯需要判斷中斷標(biāo)識征懈,可以得知是否中斷過
            selfInterrupt();
    }
    非公平鎖是先嘗試獲取鎖
      final boolean nonfairTryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            因?yàn)槭仟?dú)占鎖
            int c = getState();
            當(dāng)鎖沒有被持有的時(shí)候,直接去獲取 不需要管是否有其他人在等待
            if (c == 0) {
            設(shè)置state
                if (compareAndSetState(0, acquires)) {
                設(shè)置獨(dú)占標(biāo)識的線程
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }如果當(dāng)前線程等于獨(dú)占標(biāo)識的線程
            else if (current == getExclusiveOwnerThread()) {
                int nextc = c + acquires;
                更新state揩悄,如果state小于0 代表重入超過最大值了
                if (nextc < 0) // overflow
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            獲取失敗
            return false;
        }
        公平的獲取鎖
          protected final boolean tryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            如果這個(gè)鎖還沒人獲取
            if (c == 0) {
            如果不存在等待隊(duì)列且設(shè)置state成功 即獲取了鎖受裹,設(shè)置獨(dú)占標(biāo)識的線程
                if (!hasQueuedPredecessors() &&
                    compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            else if (current == getExclusiveOwnerThread()) {
            重入設(shè)定
                int nextc = c + acquires;
                if (nextc < 0)
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false;
        }

        
            public final boolean hasQueuedPredecessors() {
      
        Node t = tail; // Read fields in reverse initialization order
        Node h = head;
        Node s;
        h!=t 代表最少有2個(gè)元素 一個(gè)是head 一個(gè)是tail
        return h != t &&
        第一個(gè)如果為true 正好執(zhí)行到tail了 即s=tail節(jié)點(diǎn)
        否則只要判斷下s.thread不等于當(dāng)前線程
            ((s = h.next) == null || s.thread != Thread.currentThread());
    }
    
    按照鎖的模式把當(dāng)前線程包裝成節(jié)點(diǎn)
    注意初始化之后head和老的tail節(jié)點(diǎn)的next都是第一個(gè)正常節(jié)點(diǎn),也就是新的tail節(jié)點(diǎn)
    而不是新的head-->old tail-->新的tail 真正的是head-->新的tail 和old tail-->新的tail
    其中head和oldtail 是同一個(gè)對象的兩種不同的引用 也就是說最終就是head-->tail tail是正常節(jié)點(diǎn)
    head是dummpy節(jié)點(diǎn)
     private Node addWaiter(Node mode) {
        Node node = new Node(Thread.currentThread(), mode);
    首先利用cas直接放入尾部
        Node pred = tail;
        if (pred != null) {
            node.prev = pred;
            if (compareAndSetTail(pred, node)) {
                pred.next = node;
                return node;
            }
        }
for循環(huán)利用cas放入隊(duì)列
        enq(node);
        return node;
    }
    
    這邊將tail賦值給t非常好虏束,當(dāng)我們將node設(shè)置尾部tail成功時(shí)候
t還是只想tail前一個(gè)繼續(xù)操作next綁定node棉饶,就算這個(gè)時(shí)候并發(fā)另外一個(gè)線程很快
也設(shè)置tail成功也不影響前面的設(shè)置
當(dāng)head=tail說明剛初始化好

   private Node enq(final Node node) {
        for (;;) {
獲取尾部 
            Node t = tail;
如果尾部不存在,說明還沒初始化镇匀,先初始化隊(duì)列
            if (t == null) { // Must initialize
設(shè)置head節(jié)點(diǎn) 如果成功了就把head和tail 賦值為一個(gè)new出來的node節(jié)點(diǎn),然后在重新循環(huán)將該隊(duì)列設(shè)置到尾部照藻,剛初始化的節(jié)點(diǎn)是沒用的后期都會移除
                if (compareAndSetHead(new Node()))
                    tail = head;
            } else {
嘗試把節(jié)點(diǎn)加入尾部,這邊存在 pre一致 但是原始的tail的next 還是null的情況
                node.prev = t;
                if (compareAndSetTail(t, node)) {
                    t.next = node;
                    return t;
                }
            }
        }
    }
循環(huán)等待該node獲取鎖汗侵,并記錄自己被中斷
 final boolean acquireQueued(final Node node, int arg) {
        boolean failed = true;
        try {
            boolean interrupted = false;
            for (;;) {
獲取node的前置節(jié)點(diǎn)幸缕,前置節(jié)點(diǎn)有可能是正常的node
也有可能是head和tail 這種剛初始化dummpy節(jié)點(diǎn)
                final Node p = node.predecessor();
如果前置節(jié)點(diǎn)就是head,那么就嘗試獲取下鎖(這時(shí)候程序在運(yùn)行的情況分為
剛加入隊(duì)列晰韵,或者被head節(jié)點(diǎn)喚醒且正在釋放鎖或者還未釋放完)
                if (p == head && tryAcquire(arg)) {
獲取鎖成功把這個(gè)node設(shè)置為head
                    setHead(node);
                    p.next = null; // help GC
                    failed = false;
返回
                    return interrupted;
                }
如果p不等head 或者獲取鎖失敗发乔,
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                    interrupted = true;
            }
        } finally {
執(zhí)行到這一步且failed=true 代表發(fā)送了異常,取消獲取
            if (failed)
                cancelAcquire(node);
        }
    }

waitStatus四種狀態(tài)
SIGNAL:標(biāo)識這個(gè)節(jié)點(diǎn)如果后期獲取到鎖 在釋放的時(shí)候需要喚醒他的后繼節(jié)點(diǎn)
CANCELLED:因?yàn)槌瑫r(shí)或者被中斷雪猪,其線程不會再阻塞
CONDITION:這個(gè)還記得咱們的Condition這個(gè)對象嗎栏尚?這個(gè)代表節(jié)點(diǎn)還在condition隊(duì)列中 還未進(jìn)入咱們的同步隊(duì)列
PROPAGATE:調(diào)用共享鎖的時(shí)候的是否應(yīng)該無條件的傳播
head節(jié)點(diǎn)就是signal其后面的正常節(jié)點(diǎn)就是condition
0:剛創(chuàng)建的節(jié)點(diǎn)都是0,這個(gè)方法就是把所以的0都轉(zhuǎn)換為signal 
 private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
 假如是剛初始化的時(shí)候 那么head的waitstatus是0
        int ws = pred.waitStatus;
        當(dāng)SIGNAL時(shí)候代表head節(jié)點(diǎn)正在持有鎖 還沒釋放鎖 所以后置節(jié)點(diǎn)應(yīng)該沉睡
        等待head把他喚起
        if (ws == Node.SIGNAL)
            /*
             * This node has already set status asking a release
             * to signal it, so it can safely park.
             */
            return true;
            如果大于0說明節(jié)點(diǎn)是被取消的 應(yīng)該移除這些節(jié)點(diǎn)
            
        if (ws > 0) {
            /*
             * Predecessor was cancelled. Skip over predecessors and
             * indicate retry.
             */
            do {
                node.prev = pred = pred.prev;
                這邊有個(gè)問題 pre這個(gè)廢棄節(jié)點(diǎn)如果想完全移除出鏈表
                不需要  pred.next = null  因?yàn)閏ancelAcquire(node); 已經(jīng)
                執(zhí)行過這段代碼了
            } while (pred.waitStatus > 0);
            pred.next = node;
        } else {
            /*
             * waitStatus must be 0 or PROPAGATE.  Indicate that we
             * need a signal, but don't park yet.  Caller will need to
             * retry to make sure it cannot acquire before parking.
             */
             一般到這一步了說明是0或者是PROPAGATE 嘗試把head節(jié)點(diǎn)設(shè)置為
             SIGNAL
            compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
        }
        return false;
    }
阻塞只恨,然后返回釋放interupt译仗,是的話設(shè)置interupt標(biāo)識
    private final boolean parkAndCheckInterrupt() {
    該線程沉睡
        LockSupport.park(this);
        return Thread.interrupted();
    }
取消獲取失敗的節(jié)點(diǎn)
 private void cancelAcquire(Node node) {
        // Ignore if node doesn't exist
        if (node == null)
            return;
        將該節(jié)點(diǎn)的thread置空
        node.thread = null;
如果node的前置節(jié)點(diǎn)是取消狀態(tài),直接跳過
        Node pred = node.prev;
        while (pred.waitStatus > 0)
            node.prev = pred = pred.prev;

        前置節(jié)點(diǎn)的next正常沒有并發(fā)的情況下就是我們的node節(jié)點(diǎn)
        Node predNext = pred.next;
        將節(jié)點(diǎn)狀態(tài)變?yōu)槿∠?        node.waitStatus = Node.CANCELLED;

     如果當(dāng)前節(jié)點(diǎn)就是tail 那么我們把tail設(shè)置為pre(pre有可能是head 也有可能是其他的節(jié)點(diǎn))
        if (node == tail && compareAndSetTail(node, pred)) {
            把這個(gè)節(jié)點(diǎn)的next設(shè)置為null
            compareAndSetNext(pred, predNext, null);
        } else {
            說明不是tail 
            我們看看如果pre不是head 且pre是SIGNAL或者 ws<0 我們把pre的waitstatus設(shè)置為signal
            且pre的thread不為空
            int ws;
            if (pred != head &&
                ((ws = pred.waitStatus) == Node.SIGNAL ||
                 (ws <= 0 && compareAndSetWaitStatus(pred, ws, Node.SIGNAL))) &&
                pred.thread != null) {
                獲取node的下一個(gè)正常節(jié)點(diǎn)塞入pre的next
                Node next = node.next;
                if (next != null && next.waitStatus <= 0)
                    compareAndSetNext(pred, predNext, next);
            } else {
            如果是head 那么我們就需要喚醒下一個(gè)節(jié)點(diǎn)
                unparkSuccessor(node);
            }
            把脫離的節(jié)點(diǎn)從鏈表中拿出來
            node.next = node; // help GC
        }
    }

    
       private void unparkSuccessor(Node node) {
            設(shè)置waitstatus為0官觅,因?yàn)樗南乱粋€(gè)節(jié)點(diǎn)不需要signal纵菌,我們正在signal
            設(shè)置為0失敗也沒關(guān)系
        int ws = node.waitStatus;
        if (ws < 0)
            compareAndSetWaitStatus(node, ws, 0);
        如果節(jié)點(diǎn)的下一個(gè)是null 或者為取消狀態(tài)
        Node s = node.next;
        if (s == null || s.waitStatus > 0) {
            s = null;
            從尾部開始尋找,node節(jié)點(diǎn)不等于當(dāng)前且waitstatus小于等于0
            假如你從前往后遍歷的動作發(fā)生在enq方法中的cas之后和賦值之前最后一個(gè)節(jié)點(diǎn)是漏掉的
            在enq中我們是先把新的tail的pre和老的tail 鏈接在一起 等cas成功了 在設(shè)置老tail的next和新的tail
            如果我們從前往后遍歷的時(shí)間剛好發(fā)生在cas之和賦值之前 那么我們tail節(jié)將被遺漏
            但是我們這邊喚醒最后一個(gè)可用的 也不用怕休涤,因?yàn)槠淝爸霉?jié)點(diǎn)不是head 所以其不會獲得鎖
            但是會幫我們清理取消的節(jié)點(diǎn) 這樣就可以正常的獲取下一個(gè)節(jié)點(diǎn)進(jìn)行喚醒獲得鎖的操作
            for (Node t = tail; t != null && t != node; t = t.prev)
                if (t.waitStatus <= 0)
                    s = t;
        }
        喚醒該線程
        if (s != null)
            LockSupport.unpark(s.thread);
    }

lockInterruptibly

  public final void acquireInterruptibly(int arg)
            throws InterruptedException {
如果檢測到線程中的 拋出異常
        if (Thread.interrupted())
            throw new InterruptedException();
獲取線程
        if (!tryAcquire(arg))
這個(gè)過程我們之前分析過至少這邊如果檢測到中斷就直接拋出
我們正常的節(jié)點(diǎn)喚醒是通過unsafe的unpark方法
            doAcquireInterruptibly(arg);
    }


ReentrantLock的trylock 底層默認(rèn)的是采用unfaire咱圆,我們上面已經(jīng)分析過了,獲取不到直接返回
ReentrantLock的trylock 攜帶時(shí)間的參數(shù)底層也有多種實(shí)現(xiàn) 功氨,可以響應(yīng)中斷
    public final boolean tryAcquireNanos(int arg, long nanosTimeout)
            throws InterruptedException {
        if (Thread.interrupted())
            throw new InterruptedException();
        return tryAcquire(arg) ||
            doAcquireNanos(arg, nanosTimeout);
    }
我們主要分析下如何做到時(shí)間控制
   private boolean doAcquireNanos(int arg, long nanosTimeout)
            throws InterruptedException {
        if (nanosTimeout <= 0L)
            return false;
計(jì)算超時(shí)時(shí)間
        final long deadline = System.nanoTime() + nanosTimeout;
添加節(jié)點(diǎn)
        final Node node = addWaiter(Node.EXCLUSIVE);
        boolean failed = true;
        try {
            for (;;) {
開始獲取鎖
                final Node p = node.predecessor();
                if (p == head && tryAcquire(arg)) {
                    setHead(node);
                    p.next = null; // help GC
                    failed = false;
                    return true;
                }
                nanosTimeout = deadline - System.nanoTime();
                if (nanosTimeout <= 0L)
                    return false;
如果未獲取到通過LockSupport.parkNanos來沉睡
                if (shouldParkAfterFailedAcquire(p, node) &&
                    nanosTimeout > spinForTimeoutThreshold)
                    LockSupport.parkNanos(this, nanosTimeout);
                if (Thread.interrupted())
                    throw new InterruptedException();
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }
ReentrantLock的unlock
   public final boolean release(int arg) {
嘗試釋放節(jié)點(diǎn)
        if (tryRelease(arg)) {
釋放成功的話把序苏,喚醒head節(jié)點(diǎn)的下一個(gè)
            Node h = head;
            if (h != null && h.waitStatus != 0)
                unparkSuccessor(h);
            return true;
        }
        return false;
    }

   protected final boolean tryRelease(int releases) {
如果當(dāng)前線程不是獲取獨(dú)占鎖的線程 拋出異常
            int c = getState() - releases;
            if (Thread.currentThread() != getExclusiveOwnerThread())
                throw new IllegalMonitorStateException();
            boolean free = false;
            if (c == 0) {
如果鎖都釋放了 則解除獨(dú)占狀態(tài)
                free = true;
                setExclusiveOwnerThread(null);
            }
重新設(shè)置state
            setState(c);
            return free;
        }

再分析ReentrantReadWriteLock.WriteLock

ReentrantReadWriteLock.WriteLock 的lock
  public final void acquire(int arg) {
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }
  主要是tryAcquire與reentrant不一樣我們分析下
     protected final boolean tryAcquire(int acquires) {
       
            Thread current = Thread.currentThread();
            int c = getState();
            int w = exclusiveCount(c);
當(dāng)c!=0 w=0 代表共享鎖被獲取了 但是獨(dú)占鎖沒有疑故,而我們此時(shí)是獲取獨(dú)占鎖的
所以直接返回杠览,也就是說代碼中直接拒絕 了我們 不允許 讀鎖降級為寫鎖
當(dāng)w弯菊!=0 且不是獨(dú)占鎖的線程也不可獲取鎖
            if (c != 0) {
                // (Note: if c != 0 and w == 0 then shared count != 0)
                if (w == 0 || current != getExclusiveOwnerThread())
                    return false;
如果獲取鎖超過了最大值 拋出異常
                if (w + exclusiveCount(acquires) > MAX_COUNT)
                    throw new Error("Maximum lock count exceeded");
                // Reentrant acquire
設(shè)置state狀態(tài)
                setState(c + acquires);
                return true;
            }
對于公平鎖來說 當(dāng)鎖還未被獲取纵势,且有隊(duì)列存在 那么write應(yīng)該block
對于非公平來說直接返回false
            if (writerShouldBlock() ||
嘗試獲取鎖
                !compareAndSetState(c, c + acquires))
                return false;
獲取成功設(shè)置獨(dú)占標(biāo)識
            setExclusiveOwnerThread(current);
            return true;
        }
ReentrantReadWriteLock.ReadLock的lock

共享鎖---當(dāng)我們的寫鎖被其他線程持有 那么我們是不可以獲取讀鎖踱阿,寫鎖排斥任何的鎖

   public final void acquireShared(int arg) {
        if (tryAcquireShared(arg) < 0)
            doAcquireShared(arg);
    }


   protected final int tryAcquireShared(int unused) {
          
            Thread current = Thread.currentThread();
當(dāng)前獲取的鎖
            int c = getState();
如果寫鎖存在而且非本線程持有 直接返回
            if (exclusiveCount(c) != 0 &&
                getExclusiveOwnerThread() != current)
                return -1;
            int r = sharedCount(c);
公平方面主要就是看看是否存在等待隊(duì)列
 非公平方式的實(shí)現(xiàn)主要就是判斷head的下一個(gè)是否是寫鎖,也就是說如果是血鎖钦铁,就不去搶软舌,否則就去搶鎖
            if (!readerShouldBlock() &&
                r < MAX_COUNT &&
SHARED_UNIT可以留意
                compareAndSetState(c, c + SHARED_UNIT)) {
                if (r == 0) {
如果是第一次獲取 設(shè)置 firstReader 和firstReaderHoldCount 
                    firstReader = current;
                    firstReaderHoldCount = 1;
                } else if (firstReader == current) {
如果是第一個(gè)線程重復(fù)獲取 更新 firstReaderHoldCount
                    firstReaderHoldCount++;
                } else {
代表是其他線程獲取
cachedHoldCounter 代表最后一個(gè)線程的對象,依賴threadlocal存儲著重入的次數(shù)
                    HoldCounter rh = cachedHoldCounter;
如果是第一次被其他線程獲取或者多次被其他線程獲取 (通過對比id)
                    if (rh == null || rh.tid != getThreadId(current))
生成一個(gè)新的cachedHoldCounter 
                        cachedHoldCounter = rh = readHolds.get();
是當(dāng)前線程且rh不等于null
                    else if (rh.count == 0)
                        readHolds.set(rh);
給count增加1
                    rh.count++;
                }
                return 1;
            }
輪詢的方式重復(fù)了上面的步驟
            return fullTryAcquireShared(current);
        }
  執(zhí)行到這一步要么前面是head的next存在寫鎖(非公平)
要么是就是公平鎖下面有隊(duì)列   
     final int fullTryAcquireShared(Thread current) {
     
            HoldCounter rh = null;
            for (;;) {
                int c = getState();
先檢測寫鎖是否被其他線程獲取牛曹,如果是直接返回
                if (exclusiveCount(c) != 0) {
                    if (getExclusiveOwnerThread() != current)
                        return -1;

                } else if (readerShouldBlock()) {
如果write應(yīng)該block 如果firstReader == current
可以嘗試去獲取讀鎖
          
                    if (firstReader == current) {
                        // assert firstReaderHoldCount > 0;
                    } else {
如果rh==null佛点,檢測最后一個(gè)獲取讀鎖的線程是否有問題
                        if (rh == null) {
                            rh = cachedHoldCounter;
                            if (rh == null || rh.tid != getThreadId(current)) {
                                rh = readHolds.get();
                                if (rh.count == 0)
                                    readHolds.remove();
                            }
                        }
這邊如果獲取鎖不可能count=-1 直接返回
                        if (rh.count == 0)
                            return -1;
                    }
                }
超出獲取的最大值 拋出異常
                if (sharedCount(c) == MAX_COUNT)
                    throw new Error("Maximum lock count exceeded");
重復(fù)了我們上面的步驟
                if (compareAndSetState(c, c + SHARED_UNIT)) {
                    if (sharedCount(c) == 0) {
                        firstReader = current;
                        firstReaderHoldCount = 1;
                    } else if (firstReader == current) {
                        firstReaderHoldCount++;
                    } else {

                        if (rh == null)
                            rh = cachedHoldCounter;
                        if (rh == null || rh.tid != getThreadId(current))
                            rh = readHolds.get();
                        else if (rh.count == 0)
                            readHolds.set(rh);
                        rh.count++;
                        cachedHoldCounter = rh; // cache for release
                    }
                    return 1;
                }
            }
        }

 private void doAcquireShared(int arg) {
加入節(jié)點(diǎn)
        final Node node = addWaiter(Node.SHARED);
        boolean failed = true;
        try {
            boolean interrupted = false;
            for (;;) {
                final Node p = node.predecessor();
如果前置節(jié)點(diǎn)是head 就獲取鎖,
                if (p == head) {
                    int r = tryAcquireShared(arg);
獲取成功就設(shè)置head
                    if (r >= 0) {
設(shè)置head并釋放寫鎖
                        setHeadAndPropagate(node, r);
                        p.next = null; // help GC
                        if (interrupted)
                            selfInterrupt();
                        failed = false;
                        return;
                    }
                }
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                    interrupted = true;
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }

readerShouldBlock
公平方面主要就是看看是否存在等待隊(duì)列
 非公平方式的實(shí)現(xiàn)主要就是判斷head的下一個(gè)是否是寫鎖黎比,也就是說如果是血鎖超营,就不去搶,否則就去搶鎖
    final boolean apparentlyFirstQueuedIsExclusive() {
        Node h, s;
        return (h = head) != null &&
            (s = h.next)  != null &&
            !s.isShared()         &&
            s.thread != null;
    }

共享鎖的是否就是阅虫,先去消除線程中持有鎖的計(jì)數(shù)演闭,然后在修改state

protected final boolean tryReleaseShared(int unused) {
            Thread current = Thread.currentThread();
            if (firstReader == current) {
                // assert firstReaderHoldCount > 0;
                if (firstReaderHoldCount == 1)
                    firstReader = null;
                else
                    firstReaderHoldCount--;
            } else {
                HoldCounter rh = cachedHoldCounter;
                if (rh == null || rh.tid != getThreadId(current))
                    rh = readHolds.get();
                int count = rh.count;
                if (count <= 1) {
                    readHolds.remove();
                    if (count <= 0)
                        throw unmatchedUnlockException();
                }
                --rh.count;
            }
            for (;;) {
                int c = getState();
                int nextc = c - SHARED_UNIT;
                if (compareAndSetState(c, nextc))
                    // Releasing the read lock has no effect on readers,
                    // but it may allow waiting writers to proceed if
                    // both read and write locks are now free.
                    return nextc == 0;
            }
        }

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市颓帝,隨后出現(xiàn)的幾起案子米碰,更是在濱河造成了極大的恐慌,老刑警劉巖购城,帶你破解...
    沈念sama閱讀 211,348評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件吕座,死亡現(xiàn)場離奇詭異,居然都是意外死亡瘪板,警方通過查閱死者的電腦和手機(jī)吴趴,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,122評論 2 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來侮攀,“玉大人史侣,你說我怎么就攤上這事∥荷恚” “怎么了惊橱?”我有些...
    開封第一講書人閱讀 156,936評論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀的道長箭昵。 經(jīng)常有香客問我税朴,道長,這世上最難降的妖魔是什么家制? 我笑而不...
    開封第一講書人閱讀 56,427評論 1 283
  • 正文 為了忘掉前任正林,我火速辦了婚禮,結(jié)果婚禮上颤殴,老公的妹妹穿的比我還像新娘觅廓。我一直安慰自己,他們只是感情好涵但,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,467評論 6 385
  • 文/花漫 我一把揭開白布杈绸。 她就那樣靜靜地躺著帖蔓,像睡著了一般。 火紅的嫁衣襯著肌膚如雪瞳脓。 梳的紋絲不亂的頭發(fā)上塑娇,一...
    開封第一講書人閱讀 49,785評論 1 290
  • 那天,我揣著相機(jī)與錄音劫侧,去河邊找鬼埋酬。 笑死,一個(gè)胖子當(dāng)著我的面吹牛烧栋,可吹牛的內(nèi)容都是我干的写妥。 我是一名探鬼主播,決...
    沈念sama閱讀 38,931評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼审姓,長吁一口氣:“原來是場噩夢啊……” “哼耳标!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起邑跪,我...
    開封第一講書人閱讀 37,696評論 0 266
  • 序言:老撾萬榮一對情侶失蹤次坡,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后画畅,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體砸琅,經(jīng)...
    沈念sama閱讀 44,141評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,483評論 2 327
  • 正文 我和宋清朗相戀三年轴踱,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了症脂。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,625評論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡淫僻,死狀恐怖诱篷,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情雳灵,我是刑警寧澤棕所,帶...
    沈念sama閱讀 34,291評論 4 329
  • 正文 年R本政府宣布,位于F島的核電站悯辙,受9級特大地震影響琳省,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜躲撰,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,892評論 3 312
  • 文/蒙蒙 一针贬、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧拢蛋,春花似錦桦他、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽圆仔。三九已至,卻和暖如春嗓节,著一層夾襖步出監(jiān)牢的瞬間荧缘,已是汗流浹背皆警。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工拦宣, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人信姓。 一個(gè)月前我還...
    沈念sama閱讀 46,324評論 2 360
  • 正文 我出身青樓鸵隧,卻偏偏與公主長得像,于是被迫代替她去往敵國和親意推。 傳聞我的和親對象是個(gè)殘疾皇子豆瘫,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,492評論 2 348

推薦閱讀更多精彩內(nèi)容