日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

AQS --- 漸入佳境

 貪挽懶月 2022-06-20 發(fā)布于廣東

上一講了解了 AQS 是什么,接下來看看它到底是怎樣的結(jié)構(gòu)。

一. 工作原理

AQS 使用一個(gè) volatile 的 int 類型的成員變量來表示同步狀態(tài),通過內(nèi)置的 FIFO 隊(duì)列來完成資源獲取和排隊(duì)工作,將每條要去搶占資源的線程封裝成一個(gè) node 節(jié)點(diǎn)來實(shí)現(xiàn)鎖的分配,通過 CAS 來完成對(duì) state 值的修改。

HashMap 進(jìn)行 put 的時(shí)候,也不是直接存儲(chǔ) key value 鍵值對(duì),而是將 key value 鍵值對(duì)封裝成 Node 節(jié)點(diǎn),然后用數(shù)組 + 鏈表 + 紅黑樹存儲(chǔ) Node。AQS 也類似,將要搶占資源的 Thread 封裝成 Node節(jié)點(diǎn)。

二. 相關(guān)源碼:

public abstract class AbstractQueuedSynchronizer
    extends AbstractOwnableSynchronizer
    implements java.io.Serializable {
   
    static final class Node {
       ……
       volatile int waitStatus;
       volatile Node prev;
       volatile Node next;
       volatile Thread thread;
       ……
    }

    private transient volatile Node head;
    private transient volatile Node tail;

    /**
     * The synchronization state.
     */
    private volatile int state;
}

看到這個(gè)是不是就清清楚楚明明白白真真切切了。首先 AQS 外層是 state + CLH 隊(duì)列,state 表示同步的狀態(tài),默認(rèn)是0,為0時(shí)表示可以獲取鎖,不為0時(shí),線程就得老老實(shí)實(shí)到隊(duì)列中排隊(duì)去;CLH 隊(duì)列就是一個(gè)有頭結(jié)點(diǎn)和尾結(jié)點(diǎn)的雙端隊(duì)列,如下圖:

           +------+  prev +-----+       +-----+
      head |      | <---- |     | <---- |     |  tail
           +------+       +-----+       +-----+

AQS 的內(nèi)層是一個(gè) Node內(nèi)部類,這個(gè) Node 類主要有兩個(gè)指針 prev 和 next、一個(gè) waitStatus 表示線程的狀、,一個(gè) Thread 類型的變量保存等待的線程。

三. 從 ReentrantLock 看 AQS:

之前說了 AQS 是 JUC 并發(fā)包的基石,那就從我們接觸最多的 ReentrantLock 入手,揭開它的神秘面紗。

先來看看 ReentrantLock 的結(jié)構(gòu)圖:

結(jié)構(gòu)圖

首先它實(shí)現(xiàn)了 Lock 接口,其內(nèi)部主要是一個(gè) Sync 內(nèi)部類,這個(gè)內(nèi)部類又有兩個(gè)子類,一個(gè) FairSync 和一個(gè) NonfairSync,分別用來實(shí)現(xiàn)公平鎖和非公平鎖。而這個(gè) Sync 內(nèi)部類,又是 AbstractQueuedSynchronizer 的子類。

1. 我們 new ReentrantLock 的時(shí)候做了什么事?

/**
 * Creates an instance of {@code ReentrantLock}.
 * This is equivalent to using {@code ReentrantLock(false)}.
 */
 public ReentrantLock() {
     sync = new NonfairSync();
 }

通過這個(gè)構(gòu)造方法可以知道,實(shí)際上是構(gòu)建了一個(gè)非公平鎖。如果 new 的時(shí)候傳了 true,調(diào)用的構(gòu)造方法就是:

/**
 * Creates an instance of {@code ReentrantLock} with the
 * given fairness policy.
 *
 * @param fair {@code trueif this lock should use a fair ordering policy
 */
 public ReentrantLock(boolean fair) {
     sync = fair ? new FairSync() : new NonfairSync();
 }

所以傳的是 true,構(gòu)建的就是公平鎖。

2. 公平和非公平有什么區(qū)別?

非公平鎖源碼:

final boolean nonfairTryAcquire(int acquires) {
 final Thread current = Thread.currentThread();
 int c = getState();
 if (c == 0) {
  if (compareAndSetState(0, acquires)) {
   setExclusiveOwnerThread(current);
   return true;
  }
 }
 else if (current == getExclusiveOwnerThread()) {
  int nextc = c + acquires;
  if (nextc < 0) // overflow
   throw new Error("Maximum lock count exceeded");
  setState(nextc);
  return true;
 }
 return false;
}

公平鎖源碼:

 protected final boolean tryAcquire(int acquires) {
 final Thread current = Thread.currentThread();
 int c = getState();
 if (c == 0) {
  if (!hasQueuedPredecessors() &&
   compareAndSetState(0, acquires)) {
   setExclusiveOwnerThread(current);
   return true;
  }
 }
 else if (current == getExclusiveOwnerThread()) {
  int nextc = c + acquires;
  if (nextc < 0)
   throw new Error("Maximum lock count exceeded");
  setState(nextc);
  return true;
 }
 return false;
}

乍一看兩段代碼好像沒啥不一樣,其實(shí)不同之處在,if (c == 0)這段判斷中。公平鎖多了一個(gè)判斷條件,即!hasQueuedPredecessors(),看看這個(gè)方法的源碼:

public final boolean hasQueuedPredecessors() {
 // The correctness of this depends on head being initialized
 // before tail and on head.next being accurate if the current
 // thread is first in queue.
 Node t = tail; // Read fields in reverse initialization order
 Node h = head;
 Node s;
 return h != t &&
  ((s = h.next) == null || s.thread != Thread.currentThread());
}

這個(gè)方法也很簡單,首先是頭節(jié)點(diǎn)不等于尾節(jié)點(diǎn),然后就是頭節(jié)點(diǎn)的下一個(gè)節(jié)點(diǎn)為空或者頭節(jié)點(diǎn)的下一個(gè)節(jié)點(diǎn)保存的 Thread 不等于當(dāng)前的 Thread。簡單地說就是看隊(duì)列中有沒有除了當(dāng)前 Thread 以為的 Thread 在等待獲取鎖,有就返回 true,否則返回 false。所以公平鎖就是多了這個(gè)判斷,其他都一樣。

下一篇文章將會(huì)從源碼層面分析 ReentrantLock 的加鎖過程,敬請(qǐng)期待!


掃描二維碼

    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多