最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

淺談Java并發(fā) J.U.C之AQS:CLH同步隊列

 更新時間:2019年05月21日 09:35:46   作者:chenssy  
AQS內(nèi)部維護(hù)著一個FIFO隊列,該隊列就是CLH同步隊列。下面小編來簡單介紹下這個隊列

CLH同步隊列是一個FIFO雙向隊列,AQS依賴它來完成同步狀態(tài)的管理,當(dāng)前線程如果獲取同步狀態(tài)失敗時,AQS則會將當(dāng)前線程已經(jīng)等待狀態(tài)等信息構(gòu)造成一個節(jié)點(Node)并將其加入到CLH同步隊列,同時會阻塞當(dāng)前線程,當(dāng)同步狀態(tài)釋放時,會把首節(jié)點喚醒(公平鎖),使其再次嘗試獲取同步狀態(tài)。

在CLH同步隊列中,一個節(jié)點表示一個線程,它保存著線程的引用(thread)、狀態(tài)(waitStatus)、前驅(qū)節(jié)點(prev)、后繼節(jié)點(next),其定義如下:

static final class Node {
 /** 共享 */
 static final Node SHARED = new Node();

 /** 獨占 */
 static final Node EXCLUSIVE = null;

 /**
 * 因為超時或者中斷,節(jié)點會被設(shè)置為取消狀態(tài),被取消的節(jié)點時不會參與到競爭中的,他會一直保持取消狀態(tài)不會轉(zhuǎn)變?yōu)槠渌麪顟B(tài);
 */
 static final int CANCELLED = 1;

 /**
 * 后繼節(jié)點的線程處于等待狀態(tài),而當(dāng)前節(jié)點的線程如果釋放了同步狀態(tài)或者被取消,將會通知后繼節(jié)點,使后繼節(jié)點的線程得以運行
 */
 static final int SIGNAL = -1;

 /**
 * 節(jié)點在等待隊列中,節(jié)點線程等待在Condition上,當(dāng)其他線程對Condition調(diào)用了signal()后,改節(jié)點將會從等待隊列中轉(zhuǎn)移到同步隊列中,加入到同步狀態(tài)的獲取中
 */
 static final int CONDITION = -2;

 /**
 * 表示下一次共享式同步狀態(tài)獲取將會無條件地傳播下去
 */
 static final int PROPAGATE = -3;

 /** 等待狀態(tài) */
 volatile int waitStatus;

 /** 前驅(qū)節(jié)點 */
 volatile Node prev;

 /** 后繼節(jié)點 */
 volatile Node next;

 /** 獲取同步狀態(tài)的線程 */
 volatile Thread thread;

 Node nextWaiter;

 final boolean isShared() {
 return nextWaiter == SHARED;
 }

 final Node predecessor() throws NullPointerException {
 Node p = prev;
 if (p == null)
 throw new NullPointerException();
 else
 return p;
 }

 Node() {
 }

 Node(Thread thread, Node mode) {
 this.nextWaiter = mode;
 this.thread = thread;
 }

 Node(Thread thread, int waitStatus) {
 this.waitStatus = waitStatus;
 this.thread = thread;
 }
}

CLH同步隊列結(jié)構(gòu)圖如下:

入列

學(xué)了數(shù)據(jù)結(jié)構(gòu)的我們,CLH隊列入列是再簡單不過了,無非就是tail指向新節(jié)點、新節(jié)點的prev指向當(dāng)前最后的節(jié)點,當(dāng)前最后一個節(jié)點的next指向當(dāng)前節(jié)點。代碼我們可以看看addWaiter(Node node)方法:

 private Node addWaiter(Node mode) {
 //新建Node
 Node node = new Node(Thread.currentThread(), mode);
 //快速嘗試添加尾節(jié)點
 Node pred = tail;
 if (pred != null) {
 node.prev = pred;
 //CAS設(shè)置尾節(jié)點
 if (compareAndSetTail(pred, node)) {
 pred.next = node;
 return node;
 }
 }
 //多次嘗試
 enq(node);
 return node;
 }

addWaiter(Node node)先通過快速嘗試設(shè)置尾節(jié)點,如果失敗,則調(diào)用enq(Node node)方法設(shè)置尾節(jié)點

 private Node enq(final Node node) {
 //多次嘗試,直到成功為止
 for (;;) {
 Node t = tail;
 //tail不存在,設(shè)置為首節(jié)點
 if (t == null) {
 if (compareAndSetHead(new Node()))
 tail = head;
 } else {
 //設(shè)置為尾節(jié)點
 node.prev = t;
 if (compareAndSetTail(t, node)) {
 t.next = node;
 return t;
 }
 }
 }
 }

在上面代碼中,兩個方法都是通過一個CAS方法compareAndSetTail(Node expect, Node update)來設(shè)置尾節(jié)點,該方法可以確保節(jié)點是線程安全添加的。在enq(Node node)方法中,AQS通過“死循環(huán)”的方式來保證節(jié)點可以正確添加,只有成功添加后,當(dāng)前線程才會從該方法返回,否則會一直執(zhí)行下去。

過程圖如下:

出列

CLH同步隊列遵循FIFO,首節(jié)點的線程釋放同步狀態(tài)后,將會喚醒它的后繼節(jié)點(next),而后繼節(jié)點將會在獲取同步狀態(tài)成功時將自己設(shè)置為首節(jié)點,這個過程非常簡單,head執(zhí)行該節(jié)點并斷開原首節(jié)點的next和當(dāng)前節(jié)點的prev即可,注意在這個過程是不需要使用CAS來保證的,因為只有一個線程能夠成功獲取到同步狀態(tài)。過程圖如下:

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家

相關(guān)文章

最新評論

鄱阳县| 扎兰屯市| 普定县| 舞钢市| 长乐市| 吴旗县| 玛沁县| 安图县| 伊吾县| 和田县| 察隅县| 万年县| 昌吉市| 河池市| 定日县| 旅游| 桃园市| 盐津县| 龙岩市| 嘉禾县| 沁阳市| 阿尔山市| 那曲县| 广丰县| 易门县| 搜索| 南充市| 屏边| 探索| 大名县| 外汇| 临安市| 彭泽县| 阿巴嘎旗| 上林县| 论坛| 鲁甸县| 徐闻县| 突泉县| 南昌县| 临邑县|