日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

java aqs源码_java中AQS源码分析

發布時間:2023/12/10 编程问答 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java aqs源码_java中AQS源码分析 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

AQS內部采用CLH隊列。CLH隊列是由節點組成。內部的Node節點包含的狀態有

static?final?int?CANCELLED?=??1;

static?final?int?SIGNAL????=?-1;

static?final?int?CONDITION?=?-2;

static?final?int?PROPAGATE?=?-3;

其中取消狀態表示任務的取消,SIGNAL狀態表示后續節點需要喚醒,CONDITION表示等待狀態,PROPAGRATE表示的是傳播狀態通常用于共享鎖的釋放。初始節點的狀態為0。

AQS中比較重要的操作包括:

public?final?void?acquire(int?arg);

public?final?void?acquireInterruptibly(int?arg);

public?final?void?acquireShared(int?arg);

public?final?void?acquireSharedInterruptibly(int?arg);

protected?boolean?tryAcquire(int?arg);

protected?int?tryAcquireShared(int?arg);

public?final?boolean?tryAcquireNanos(int?arg,?long?nanosTimeout)?throws?InterruptedException;

public?final?boolean?tryAcquireSharedNanos(int?arg,?long?nanosTimeout)?throws?InterruptedException;

其中:public final void acquire(int arg) {

if (!tryAcquire(arg) &&acquireQueued(addWaiter(Node.EXCLUSIVE), arg))

selfInterrupt();

}

其中tryAcquire方法為抽象方法。不同的子類有不同的實現方式。AQS中該方法的實現知識拋出了一個異常。

final boolean acquireQueued(final Node node, int arg) {

boolean failed = true;//標記是否成功拿到資源

try {

boolean interrupted = false;//標記等待過程中是否被中斷過

//自旋的過程

for (;;) {

final Node p = node.predecessor();//拿到前驅

//如果前驅是head,即該結點已成老二,那么便有資格去嘗試獲取資源(可能是老大釋放完資源喚醒自己的,當然也可能被interrupt了)。

if (p == head && tryAcquire(arg)) {

setHead(node);//拿到資源后,將head指向該結點。所以head所指的標桿結點,就是當前獲取到資源的那個結點或null。

p.next = null; // setHead中node.prev已置為null,此處再將head.next置為null,就是為了方便GC回收以前的head結點。也就意味著之前拿完資源的結點出隊了!

failed = false;

return interrupted;//返回等待過程中是否被中斷過

}

//如果自己可以休息了,就進入waiting狀態,直到被unpark()

if (shouldParkAfterFailedAcquire(p, node) &&

parkAndCheckInterrupt())

interrupted = true;//如果等待過程中被中斷過,哪怕只有那么一次,就將interrupted標記為true

}

} finally {

if (failed)

cancelAcquire(node);

}

}

可以從該方法中看出。這里會繼續嘗試去獲取一下資源

private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {

int ws = pred.waitStatus;//拿到前驅的狀態

if (ws == Node.SIGNAL)

//如果已經告訴前驅拿完號后通知自己一下,那就可以安心休息了

return true;

if (ws > 0) {

/*

* 如果前驅放棄了,那就一直往前找,直到找到最近一個正常等待的狀態,并排在它的后邊。

* 注意:那些放棄的結點,由于被自己“加塞”到它們前邊,它們相當于形成一個無引用鏈,稍后就會被保安大叔趕走了(GC回收)!

*/

do {

node.prev = pred = pred.prev;

} while (pred.waitStatus > 0);

pred.next = node;

} else {

//如果前驅正常,那就把前驅的狀態設置成SIGNAL,告訴它拿完號后通知自己一下。有可能失敗,人家說不定剛剛釋放完呢!

compareAndSetWaitStatus(pred, ws, Node.SIGNAL);

}

return false;

}

在該方法中會檢測當前節點中前面的節點是否有CANCELLED狀態的如果有。待會兒后續的操作這些節點會被GC回收。

如果一切正常當前節點的前一個節點會被設置為SIGNAL狀態。

1 private final boolean parkAndCheckInterrupt() {

2???? LockSupport.park(this);//調用park()使線程進入waiting狀態

3???? return Thread.interrupted();//如果被喚醒,查看自己是不是被中斷的。

4 }

線程進入waiting狀態。線程被喚醒的方式有被unpark和被中斷。

public final boolean release(int arg) {

if (tryRelease(arg)) {

Node h = head;//找到頭結點

if (h != null && h.waitStatus != 0)

unparkSuccessor(h);//喚醒等待隊列里的下一個線程

return true;

}

return false;

}

這里tryRelease也是一個抽象方法不同的子類有不同的實現。

private void unparkSuccessor(Node node) 內部首先會設置當前節點的狀態為初始狀態。同時找到一個有效的后繼節點的狀態小于0的進行節點的釋放。?LockSupport.unpark(s.thread);//喚醒對應的線程。

總結

以上是生活随笔為你收集整理的java aqs源码_java中AQS源码分析的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。