一、abstractqueuedsynchronizer
的用途( 下面簡稱
aqs,jdk 1.8)
aqs是借助
fifo等待佇列,用來實現同步器的同步框架,通俗的來說,它是用來實現鎖的工具,一般來說,它需要實現這些功能:
二、aqs
的工作原理
aqs的核心是基於鍊錶實現的
fifo等待佇列,該佇列用於存放需要等待的執行緒節點,
aqs中
node內部類用於儲存等待執行緒的相關資訊。
1、 等待佇列結構
工作機制:
aqs的等待佇列是基於鍊錶實現的
fifo
的等待佇列,佇列每個節點只關心其前驅節點的狀態,執行緒喚醒時只喚醒隊頭等待執行緒(即
head
的後繼節點,並且等待狀態不大於0)。
2、node內部類
node內部類用於儲存等待執行緒的相關資訊
主要的資料成員有:
static final node shared;//表明該節點在共享模式下等待;
static final node exclusive;//表明該節點在互斥模式下等待;
volatile int waitstatus;//該節點的等待狀態:1 cancelled,-1 signal, -2 condition, -3 propagate, 0 others;
volatile node prev;//該節點的前驅節點
volatile node next;//該節點的後繼節點
volatile thread thread;//該節點關聯的執行緒
主要的方法成員有:
final boolean isshared();//當前節點是否在共享模式下等待;
final node predecessor();// 返回當前節點的前驅節點;
3、aqs的資料成員
private transient volatile node head;//等待佇列的頭節點,該節點的等待狀態不為cancelled;
private transient volatile node tail;//等待佇列的尾節點;
private volatile int state;//同步器的狀態;
4、aqs方法成員之節點基本操作
注:只寫了一些比較主要的,像sethead(), hasqueuedthreads(), hascontented(), ….可以直接檢視原始碼,比較簡單
將執行緒作放入等待佇列中
private node addwaiter(node mode);
功能:以指定模式建立當前執行緒的node,並新增到等待佇列中,返回新增的節點。
具體操作:
原始碼:private node addwaiter(node mode)
} enq(node);
return node;
}private node enq(final node node);
功能:將node新增到等待佇列中,一直迴圈直到新增成功
具體操作:
原始碼:private node enq(final node node) else
} }}喚醒給定節點的後繼節點
private void unparksuccessor(node node);
具體操作:
原始碼:private void unparksuccessor(node node)
if (s != null)
locksupport.unpark(s.thread);
}取消獲取鎖
private void cancelacquire(node node);
具體操作:
原始碼:private void cancelacquire(node node) else else
node.next = node; // help gc
} }private static booleanshouldparkafte***iledacquire(node pred, node node);
功能:獲取鎖失敗後檢查並更新節點的狀態,如果執行緒應該阻塞的話,返回true
具體操作:
原始碼:private static boolean shouldparkafte***iledacquire(node pred, node node) while (pred.waitstatus > 0);
pred.next = node;
} else
return false;
}注:對於該方法的功能,我是這樣理解的,
應用場景:
該方法經常用於阻塞執行緒的方法中(比如acquirequeued(finalnode node, int arg), doacquireinterruptibly(int arg)等),並且經常在for死迴圈中重複呼叫。
情形一:如果node節點的前驅節點的等待狀態為signal,說明前驅節點正在等待獲取鎖,node節點肯定不能直接獲取鎖的,必須等待,因此可以安全阻塞,返回true,可以在阻塞執行緒的方法中將當前執行緒掛起;
情形二:如果node節點的前驅節點的等待狀態為cancelled,更新node節點的前驅節點(跳過取消的前驅節點),返回false。更新完成後,node節點的前驅節點有可能就是head節點,即node節點可以直接嘗試獲取鎖,因此在退出該方法後在阻塞執行緒的方法中重新執行迴圈;
情形三:否則的話,node節點的前驅節點的等待狀態為0或者propagate,將前驅節點的等待狀態更新為signal,返回false後,在阻塞執行緒的方法中重新執行迴圈就可以達到情形一。
private final booleanparkandcheckinterrupt()
功能:park乙個執行緒,當執行緒被unparkh後,返回中斷狀態
原始碼:private final boolean parkandcheckinterrupt()
方法很簡單,簡要說一下:
5、aqs方法成員之獲取鎖的操作
說明:因為原理都差不多,因此主要講兩個方法:非中斷模式下獨佔式獲取鎖public final void acquire(int arg)和中斷模式下獨佔式獲取鎖publicfinal void acquireinterruptibly(int arg):
非中斷模式下獨佔式獲取鎖
public final void acquire(int arg)
具體操作:
原始碼:public final void acquire(int arg)
final boolean acquirequeued(final node node, int arg)
功能:非中斷模式下獨佔式獲取鎖,返回值為等待獲取鎖的過程中該執行緒是否被中斷
具體操作:
解釋:該方法會阻塞執行緒,直到執行緒成功獲得鎖,返回
interrupted
。期間如果遇到中斷的話,僅僅是將
interrupted
值置為true
。也就是說不論是否中斷,等待佇列中的
執行緒不可以取消獲取鎖,獲取鎖成功後才會從等待佇列中移除。
原始碼:final boolean acquirequeued(final node node, int arg)
if (shouldparkafte***iledacquire(p, node) &&
parkandcheckinterrupt())
interrupted = true;
} } finally
}中斷模式下獨佔式獲取鎖
public final void acquireinterruptibly(int arg)
具體操作:
原始碼:public final void acquireinterruptibly(int arg)
throws interruptedexception
private voiddoacquireinterruptibly(int arg)
功能:執行緒以可中斷的互斥模式下獲取鎖
具體操作:
解釋:該方法會阻塞執行緒,執行緒要想從該方法中返回的有兩種途徑,一是成功獲取鎖,二是遇到中斷,如果入到中斷的話會取消獲取鎖。
6、aqs方法成員之釋放鎖的操作
釋放鎖分類同獲取鎖,獨佔式地釋放鎖呼叫tryrelease()方法,共享式釋放鎖呼叫tryreleaseshared()方法,共享式釋放鎖會一直嘗試釋放鎖,直到釋放成功;獨佔式釋放鎖不一定可以成功釋放鎖,釋放成功返回true,失敗返回false。
原始碼不講了,思路很簡單,通過呼叫unparksuccessor(node node)方法喚醒等待佇列中最靠前且未取消的節點。
7、aqs方法成員之必須重寫的方法
protected boolean tryacquire(int arg);
protected int tryacquireshared(int arg)
protected boolean tryrelease(int arg);
protected boolean tryreleaseshared(int arg);
protected boolean isheldexclusively()。
三、aqs
的執行流程
以獲取鎖為例:
併發程式設計核心框架AQS之獨佔鎖原理詳解
如何設計符合冪等性的高質量restful api 理解restful的冪等性,並且設計符合冪等規範的高質量restful api。http冪等方法,是指無論呼叫多少次都不會有不同結果的 http 方法。不管你呼叫一次,還是呼叫一百次,一千次,結果都是相同的。還是以之前的博文的例子為例。get tic...
java併發之AQS共享模式原始碼解讀
共享鎖的乙個實現類就是訊號量semaphore,semaphores一般用於對某種訪問資源的限制,乙個訊號量相當於持有一些許可 permits 執行緒可以呼叫semaphore物件的acquire 方法獲取乙個許可,呼叫release 來歸還乙個許可。同樣semaphore有公平和非公平兩種模式。預...
併發程式設計之AQS的同步原理
aqs abstractqueuedsynchronizer 抽象佇列同步器。aqs的同步狀態 aqs使用乙個int成員變數來表示同步狀態,通過內建的fifo佇列來完成獲取資源執行緒的排隊工作。aqs使用cas對該同步狀態進行原子操作實現對其值的修改。private volatile int sta...