一、什么是AQS
AQS:用來構建鎖或其他同步器組件的重量級基礎框架及整個JUC體系的基石,通過內置的FIFO隊列來完成資源獲取線程的排隊工作,並通過一個int類型變量表示持有鎖的狀態。如果共享資源被占用,就需要一定的阻塞等待喚醒機制來保證鎖的分配。主要通過CLH隊列的變體實現,將暫時獲取不到鎖的線程加入到隊列中,這個隊列就是AQS抽象的表現。它將請求共享資源的線程封裝成隊列的節點(Node),通過CAS自旋以及LockSupport.park()的方式,維護state變量的狀態,使並發達到同步的控制效果。
CLH隊列:Craig、Landin and Hagersten隊列,是一個單向鏈表,AQS中的隊列是CLH變體的虛擬雙向隊列,虛擬的雙向隊列即不存在隊列實例,僅存在節點之間的關聯關系。
java.util.concurrent.locks.AbstractOenableSynchronizer;
解釋:是用來構建鎖或者其他同步器組件的重量級基礎框架及整個JUC體系的基石,通過內置的FIFO(先進先出)隊列來完成資源獲取線程的排隊工作,並通過一個int類變量表示持有鎖的狀態
和AQS有關的類:
ReentrantLock:
CountDownLatch
ReentrantReadWriteLock:
Semaphore:
鎖和AQS的關系:鎖面向鎖的使用者,定義了程序員和鎖交互的使用層API,隱藏了實現細節
同步器AQS是鎖的實現
二、AQS源碼分析
AQS使用一個volatile的int類型的成員變量來表示同步狀態,通過內置的 FIFO隊列來完成資源獲取的排隊工作將每條要去搶占資源的線程封裝成 一個Node節點來實現鎖的分配,通過CAS完成對State值的修改。
AQS的同步狀態state成員變量 零說明沒有資源占用,自由狀態可以辦理 大於等於1 有線程占用資源
AQS的CLH隊列
AQS同步隊列的基本結構
AQS底層是怎么排隊的 :是用LockSupport.park()來進行排隊的
三、通過ReentrantLock中的非公平鎖進行分析
主要是通過以下幾個方法進行實現的:
通過銀行辦理業務的例子來深入了解:
三個線程A,B,C來銀行窗口辦理業務,服務窗口每次只能服務一個人,初識的時候窗口是沒人的!
lock()
這邊線程A拿到了去窗口辦理業務的機會,通過compareAndSetState比較並交換,將AQS中變量state設置成1
acquire()
線程A已經占用了窗口,線程B只能走acquire這個方法
tryAcquire()
在來看acquire() 的方法,B線程返回false,取反的是true,往下面看下一個方法
addWaiter(Node.EXCLUSLVE)
完成B節點的入隊,通過enq源碼可以知道,B線程第一次並沒有進行入隊,到第二次循環才將B線程入隊返回
acquireQueued(addWaiter(Node.EXCLUSIVE), arg)
B搶成功了去去窗口辦理業務,搶占不成功就在等待,直到被喚醒。
unlock();
A 辦完業務,准備離開,B上位