一、入隊操作
當一個執行緒獲取鎖失敗之后會被轉換為Node節點,然后會使用enq方法,將該節點插入到AQS的阻塞佇列,下面看一下這個方法如何實作
private Node enq(final Node node) {
for(;;) {
Node t = tail;
if( t == null) {
if(compareAndSetHead(new Node())) {
tail = head;
}
}else {
node.prev = t;
if(compareAndSetTail(t,node)) {
t.next = node;
}
}
}
}
決議:進入到第一次回圈,tail和head此時都是null,如圖default,然后讓t指向tail,即null,如圖I,此時都是null,然后隨便產生一個實體,也就是II所示,讓head指向它,然后執行陳述句,讓tail也指向它; 接下來進行第二次回圈,讓t也指向這個實體,如圖III,然后進入到else陳述句,先讓node的前向指向哨兵,如圖IV;然后,把tail設定為node,在把哨兵的next指向tail,如圖VI,也就結束了, 
二、AQS-條件變數的支持
notify和wait方法是配合synchronized內置鎖實作執行緒同步的,條件變數的signal和await方法也是用來配合鎖(使用AQS實作的鎖),實作執行緒間同步的基礎設施 它們的不同在于,synchronized同時只能與一個共享變數的notify或者wait方法實作同步,而AQS的一個鎖可以對應多個條件變數,我們先看下面的例子
package com.ruigege.LockSourceAnalysis6;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
public class TestReentrantLock {
public static void main(String[] args) {
ReentrantLock lock = new ReentrantLock();
Condition condition = lock.newCondition();
// Condition類是鎖對應的一個條件變數,一個lock物件是可以創建多個條件變數的
lock.lock(); // 首先獲取獨占鎖
try {
System.out.println("begin wait");
condition.await(); // 阻塞當前執行緒,當其他執行緒呼叫條件變數的signal方法的時候,被阻塞的執行緒就會這
// 這里放回,需要注意的是和呼叫Object的wait方法一樣,如果在沒有獲取鎖之前呼叫了
// 條件變數的await方法,就會拋出java.lang.IllegalMonitorStateException
System.out.println("end wait");
}catch(Exception e) {
e.printStackTrace();
}finally {
lock.unlock(); // 釋放了鎖
}
lock.lock();
try {
System.out.println("begin signal");
condition.signal();
System.out.println("end signal");
}catch(Exception e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
}

其實這里的Lock物件就相當于synchronized加上了共享變數,呼叫lock.lock()就相當于進入了synchronized塊(獲取了共享變數的內置鎖),呼叫lock.unlock()方法就相當于推出了synchronized塊,呼叫條件變數的signal方法就相當于呼叫共享變數的notify方法,signalAll()相當于notifyAll()方法 在上面的代碼中,lock.newCondition()的作用其實就是new了一個在AQS內部宣告的ConditionObject物件,ConditionObject是AQS的內部類,可以方法AQS內部的變數(例如狀態變數state)和方法,在每個條件變數內部都維護了一個條件佇列,用來存放呼叫條件變數的await()方法時被阻塞的執行緒,注意這個條件佇列和AQS佇列不是一回事, 下面便是await方法原始碼,當執行緒呼叫條件變數的await()方法時(必須先呼叫鎖的lock方法獲取鎖),在內部會構造一個型別為Node.CONDITION的node節點,然后將該節點插入到條件佇列末尾,之后當前執行緒會釋放獲取得鎖(也就是會操作鎖對應的state變數的值),并被阻塞掛起,這時候如果有其他執行緒呼叫lock.lock()嘗試獲取鎖,就會有一個執行緒獲取到鎖,如果獲取到的鎖的執行緒呼叫了條件變數的await方法,則該執行緒會被放入到條件變數的阻塞佇列中,然后釋放獲取到的鎖,在await方法處阻塞,
public final void await() throws InterruptedException {
if(Thread.interrupted()) {
throw new InterruptedException();
}
// 創建新的Node節點,并且插入到條件佇列末尾
Node node = addContionWaiter();
// 釋放當前執行緒獲取到的鎖
int savedState = fullyRelease(node);
int interruptMode = 0;
// 呼叫park方法阻塞掛起當前執行緒
while(!isOnSyncQueue(node)) {
LockSupport.park(this);
if((interruprMode = checkInterruptWhileWaiting(node)) != 0) {
break;
}
}
}
三、原始碼:
所在包:com.ruigege.ConcurrentListSouceCodeAnalysis5 https://github.com/ruigege66/ConcurrentJavaCSDN:https://blog.csdn.net/weixin_44630050 博客園:https://www.cnblogs.com/ruigege0000/ 歡迎關注微信公眾號:傅里葉變換,個人賬號,僅用于技術交流 
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/262359.html
標籤:Java
下一篇:maven(1)
