對於AQS的理解
1、JUC包中的 CountDownLatch、CyclicBarrier、ReentrantLock和Semaphore都是基於AQS(AbstractQuenedSynchronizer)實現的
在ReentrantLoc這個元件裡,stste表示獲取鎖的執行緒數,假如state=0,表示還沒有執行緒獲取鎖,1表示有執行緒獲取了鎖。大於1表示重入鎖的數量。
繼承:子類通過繼承並通過實現它的方法管理其狀態(acquire和release方法操縱狀態)。
可以同時實現排它鎖和共享鎖模式(獨佔、共享),站在一個使用者的角度,AQS的功能主要分為兩類:獨佔和共享。它的所有子類中,要麼實現並使用了它的獨佔功能的api,要麼使用了共享鎖的功能,而不會同時使用兩套api,即便是最有名的子類ReentrantReadWriteLock也是通過兩個內部類讀鎖和寫鎖分別實現了兩套api來實現的
2、AQS底層實現了一個FIFO的佇列。底層的資料結構是一個雙向連結串列;
3、AQS核心思想
如果被請求的共享資源空閒,則將當前請求資源的執行緒設定為有效的工作執行緒,並且將共享資源設定為鎖定狀態。如果被請求的共享資源被佔用,那麼就需要一套執行緒阻塞等待以及被喚醒時鎖分配的機制,這個機制AQS是用CLH佇列鎖實現的,即將暫時獲取不到鎖的執行緒加入到佇列中。
4、CLH佇列(FIFO)
CLH佇列是一個虛擬佇列,沒有佇列例項只有節點與節點之間的關係。
AQS使用一個int成員變數來表示同步狀態,通過內建的FIFO佇列來完成獲取資源執行緒的排隊工作。AQS使用CAS對該同步狀態進行原子操作實現對其值的修改。
當一個執行緒嘗試獲取鎖失敗後,就會把失敗資訊封裝成一個node節點嘗試加入這個同步佇列。因為可能有多個執行緒都想加入佇列尾部,所以加入佇列是採用了cas + volatile。
加入佇列後獲取鎖的操作:佇列裡面的節點會觀察pre節點即前置節點的狀態,如果是不是頭結點就會阻塞,如果前面一個節點是頭結點就會被喚醒一直迴圈嘗試獲取鎖。
5、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); } }