對於AQS的理解

一、JUC包中的 CountDownLatch、CyclicBarrier、ReentrantLock和Semaphore都是基於AQS(AbstractQuenedSynchronizer)實現的node

在ReentrantLoc這個組件裏,stste表示獲取鎖的線程數,假如state=0,表示尚未線程獲取鎖,1表示有線程獲取了鎖。大於1表示重入鎖的數量。api

繼承:子類經過繼承並經過實現它的方法管理其狀態(acquire和release方法操縱狀態)。數據結構

能夠同時實現排它鎖和共享鎖模式(獨佔、共享),站在一個使用者的角度,AQS的功能主要分爲兩類:獨佔和共享。它的全部子類中,要麼實現並使用了它的獨佔功能的api,要麼使用了共享鎖的功能,而不會同時使用兩套api,即使是最有名的子類ReentrantReadWriteLock也是經過兩個內部類讀鎖和寫鎖分別實現了兩套api來實現的ui

 

二、AQS底層實現了一個FIFO的隊列。底層的數據結構是一個雙向鏈表;spa

 

三、AQS核心思想線程

若是被請求的共享資源空閒,則將當前請求資源的線程設置爲有效的工做線程,而且將共享資源設置爲鎖定狀態。若是被請求的共享資源被佔用,那麼就須要一套線程阻塞等待以及被喚醒時鎖分配的機制,這個機制AQS是用CLH隊列鎖實現的,即將暫時獲取不到鎖的線程加入到隊列中。code


四、CLH隊列(FIFO)對象

                                          

 

 

CLH隊列是一個虛擬隊列,沒有隊列實例只有節點與節點之間的關係。blog

 

AQS使用一個int成員變量來表示同步狀態,經過內置的FIFO隊列來完成獲取資源線程的排隊工做。AQS使用CAS對該同步狀態進行原子操做實現對其值的修改。繼承

 

當一個線程嘗試獲取鎖失敗後,就會把失敗信息封裝成一個node節點嘗試加入這個同步隊列。由於可能有多個線程都想加入隊列尾部,因此加入隊列是採用了cas + volatile。

加入隊列後獲取鎖的操做:隊列裏面的節點會觀察pre節點即前置節點的狀態,若是是否是頭結點就會阻塞,若是前面一個節點是頭結點就會被喚醒一直循環嘗試獲取鎖。

 

五、VarHandle

 

varHandle是jdk9以後加入的,handle的意思是句柄,VARHandle指的就是引用變量指向具體對象的那個引用

                                                               

varHandle能夠直接給變量賦值,而且作一些原子操做

public class Demo {
    int x = 10;
    private static VarHandle varHandle;

    static {
        try {
            varHandle = MethodHandles.lookup().findVarHandle(Demo.class, "x", int.class);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        Demo demo = new Demo();

        //獲取變量值
        System.out.println((int)varHandle.get(demo));

        //爲變量賦值
        varHandle.set(demo, 1);
        System.out.println(demo.x);

        //進行原子操做
        varHandle.getAndAdd(demo,3);
        System.out.println(demo.x);
    }
}
相關文章
相關標籤/搜索