JUC之AQS必知必會,這樣說就夠了...

AQS是JDK併發工具包下的一個模板類,做爲併發包下的工具工具基礎實現,咱們常常使用的ReentrantLock,CountDownLatch,CyclicBarrier等都是基於它實現的,而且經過它咱們能夠很容易的實現本身的同步機制。bash

做爲JUC中這麼重要的一個類,有些東西仍是要掌握的。數據結構

主要內容:併發

  • AQS原理
  • 如何利用AQS編寫本身的同步機制
  • 基於AQS的重入鎖和Synchronized有什麼區別
  • 從AQS源碼中你學到了什麼

AQS原理

JDK源碼要說原理,首先要提到其內部數據結構。其內部有兩個子類:工具

  • ConditionObject : 提供Java代碼實現的Object.wait,notify,notifyAll等方法,而且支持屢次wait,能夠看作是Object這些方法的加強版。其內部也維護了一個隊列,加上AQS的隊列,總共有兩個隊列
  • Node:AQS內部主要經過維護一個雙向鏈表來存儲參與同步機制的線程狀態。雙向鏈表基於Node節點來構建,每個Node表明一個線程
    • waitStatus: Node節點的一個熟悉,用於標記當前線程的等待狀態。
      • CANCELLED:即1,表明當前線程已經被取消了
      • SIGNAL: -1,表明當前的線程等待被喚醒,即unparking
      • CONDITION: -2,表明當前線程在條件隊列上等待
      • PROPAGATE:-3,當前線程節點的後續節點的acquireShare方法可以被無條件執行

另外AQS內部有一個state屬性,AQS內部沒有直接去操做state的地方,可是留給了咱們三個方法去操做它。主要用於標記同步器的狀態學習

  • getState
  • setState
  • compareAndSetState

image-20200221093528341

AQS的隊列操做

  • head執行隊列的頭部
  • tail執行隊列的尾部
  • 隊列由Node組成,Node能獲取其表明的Thread

img

AQS的Condition內部隊列

image-20200221092800481

簡述

能提到幾個點,我以爲就OK了:ui

  • 雙向隊列
  • Node的waitStatus,大體那些
  • state操做

利用AQS編寫本身同步機制

根據上面提到的原理,想要使用AQS這個類:spa

1 編寫一個新類線程

2 重寫AQS的模板方法code

  • tryAcquire 嘗試獲取獨佔鎖,
  • tryRelease 嘗試釋放排它鎖
  • tryAcquireShared 嘗試獲取共享鎖,返回負數表明失敗,返回0表明當前的鎖獲取成功,可是後續沒法獲取,返回正數,表明後續的節點仍然能夠繼續獲取
  • tryReleaseShared 嘗試釋放共享鎖
  • isHeldExclusively 是否排它狀態

3 利用AQS提供的基礎方法補全模板方法,tryXXX開頭的方法內容,已重入鎖ReentrantLock爲例,比較清晰。cdn

protected final boolean tryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            // c = 0表明沒有線程修改過狀態,那麼嘗試設置同步器的state。若是設置成功標記當前線程持有鎖
            if (c == 0) {
                if (compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            
            // 若是當前的線程持有鎖。state + 1
            // 不然返回false,表明沒法獲取
            else if (current == getExclusiveOwnerThread()) {
                int nextc = c + acquires;
                if (nextc < 0)
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false;
        }
複製代碼

4 調用AQS提供的方法來使用,三個維度:是否可中斷、是否共享、是否超時

  • acquire
  • acquireInterruptibly
  • acquireShared
  • acquireSharedInterruptibly
  • tryAcquireNanos
  • tryAcquireSharedNanos
  • release
  • releaseShared

關於AQS幾個Acquire方法的區別:www.jianshu.com/p/c48793646…

簡單來講就是要知道try開頭的方法是要咱們本身實現的。能提到try開頭的方法便可,最好了解AQS內部的方法大體有哪些

ReentrantLock和Synchronized區別

常規區別:

  • ReentrantLock更加靈活,提供了超時獲取鎖,可中斷鎖。提供了非公平鎖和非公平鎖,而synchronized僅僅是非公平鎖。
  • 用法上,ReentrantLock必須手動釋放鎖,而且只能修飾代碼塊。而synchronized不用手動釋放鎖,除此以外能夠修飾方法。

再問一句,ReentrantLock提供的不一樣獲取鎖的方式,好比超時獲取,可中斷獲取,在AQS上的體現是什麼呢?

即上面說的利用的是AQS的acquire,acquireInterruptibly,tryAcquireNanos。

至因而否公平的判斷則是根據當前線程前是否仍有節點在等待。

學習感覺

瞭解了AQS的關鍵點以後,代碼並非很複雜,主要知識點:維護雙向鏈表,更新鏈表節點的狀態,Lock.park,線程中斷。

若是本身之後寫模板類,AQS是一個很好的參照品。

其他也沒太多想說的了,源碼不是很複雜,因此沒有貼源碼出來

相關文章
相關標籤/搜索