欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java并發(fā)系列之AbstractQueuedSynchronizer源碼分析(條件隊(duì)列)

 更新時(shí)間:2018年02月27日 09:53:43   作者:勞夫子  
這篇文章主要為大家詳細(xì)介紹了Java并發(fā)系列之AbstractQueuedSynchronizer源碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下

通過(guò)前面三篇的分析,我們深入了解了AbstractQueuedSynchronizer的內(nèi)部結(jié)構(gòu)和一些設(shè)計(jì)理念,知道了AbstractQueuedSynchronizer內(nèi)部維護(hù)了一個(gè)同步狀態(tài)和兩個(gè)排隊(duì)區(qū),這兩個(gè)排隊(duì)區(qū)分別是同步隊(duì)列和條件隊(duì)列。我們還是拿公共廁所做比喻,同步隊(duì)列是主要的排隊(duì)區(qū),如果公共廁所沒(méi)開(kāi)放,所有想要進(jìn)入廁所的人都得在這里排隊(duì)。而條件隊(duì)列主要是為條件等待設(shè)置的,我們想象一下如果一個(gè)人通過(guò)排隊(duì)終于成功獲取鎖進(jìn)入了廁所,但在方便之前發(fā)現(xiàn)自己沒(méi)帶手紙,碰到這種情況雖然很無(wú)奈,但是它也必須接受這個(gè)事實(shí),這時(shí)它只好乖乖的出去先準(zhǔn)備好手紙(進(jìn)入條件隊(duì)列等待),當(dāng)然在出去之前還得把鎖給釋放了好讓其他人能夠進(jìn)來(lái),在準(zhǔn)備好了手紙(條件滿(mǎn)足)之后它又得重新回到同步隊(duì)列中去排隊(duì)。當(dāng)然進(jìn)入房間的人并不都是因?yàn)闆](méi)帶手紙,可能還有其他一些原因必須中斷操作先去條件隊(duì)列中去排隊(duì),所以條件隊(duì)列可以有多個(gè),依不同的等待條件而設(shè)置不同的條件隊(duì)列。條件隊(duì)列是一條單向鏈表,Condition接口定義了條件隊(duì)列中的所有操作,AbstractQueuedSynchronizer內(nèi)部的ConditionObject類(lèi)實(shí)現(xiàn)了Condition接口,下面我們看看Condition接口都定義了哪些操作。

public interface Condition {
  
  //響應(yīng)線(xiàn)程中斷的條件等待
  void await() throws InterruptedException;
  
  //不響應(yīng)線(xiàn)程中斷的條件等待
  void awaitUninterruptibly();
  
  //設(shè)置相對(duì)時(shí)間的條件等待(不進(jìn)行自旋)
  long awaitNanos(long nanosTimeout) throws InterruptedException;
  
  //設(shè)置相對(duì)時(shí)間的條件等待(進(jìn)行自旋)
  boolean await(long time, TimeUnit unit) throws InterruptedException;
  
  //設(shè)置絕對(duì)時(shí)間的條件等待
  boolean awaitUntil(Date deadline) throws InterruptedException;
  
  //喚醒條件隊(duì)列中的頭結(jié)點(diǎn)
  void signal();
  
  //喚醒條件隊(duì)列的所有結(jié)點(diǎn)
  void signalAll();
  
}

Condition接口雖然定義了這么多方法,但總共就分為兩類(lèi),以await開(kāi)頭的是線(xiàn)程進(jìn)入條件隊(duì)列等待的方法,以signal開(kāi)頭的是將條件隊(duì)列中的線(xiàn)程“喚醒”的方法。這里要注意的是,調(diào)用signal方法可能喚醒線(xiàn)程也可能不會(huì)喚醒線(xiàn)程,什么時(shí)候會(huì)喚醒線(xiàn)程這得看情況,后面會(huì)講到,但是調(diào)用signal方法一定會(huì)將線(xiàn)程從條件隊(duì)列中移到同步隊(duì)列尾部。這里為了敘述方便,我們先暫時(shí)不糾結(jié)這么多,統(tǒng)一稱(chēng)signal方法為喚醒條件隊(duì)列線(xiàn)程的操作。大家注意看一下,await方法分為5種,分別是響應(yīng)線(xiàn)程中斷等待,不響應(yīng)線(xiàn)程中斷等待,設(shè)置相對(duì)時(shí)間不自旋等待,設(shè)置相對(duì)時(shí)間自旋等待,設(shè)置絕對(duì)時(shí)間等待;signal方法只有2種,分別是只喚醒條件隊(duì)列頭結(jié)點(diǎn)和喚醒條件隊(duì)列所有結(jié)點(diǎn)的操作。同一類(lèi)的方法基本上是相通的,由于篇幅所限,我們不可能也不需要將這些方法全部仔細(xì)的講到,只需要將一個(gè)代表方法搞懂了再看其他方法就能夠觸類(lèi)旁通。所以在本文中我只會(huì)細(xì)講await方法和signal方法,其他方法不細(xì)講但會(huì)貼出源碼來(lái)以供大家參考。

1. 響應(yīng)線(xiàn)程中斷的條件等待

//響應(yīng)線(xiàn)程中斷的條件等待
public final void await() throws InterruptedException {
  //如果線(xiàn)程被中斷則拋出異常
  if (Thread.interrupted()) {
    throw new InterruptedException();
  }
  //將當(dāng)前線(xiàn)程添加到條件隊(duì)列尾部
  Node node = addConditionWaiter();
  //在進(jìn)入條件等待之前先完全釋放鎖
  int savedState = fullyRelease(node);
  int interruptMode = 0;
  //線(xiàn)程一直在while循環(huán)里進(jìn)行條件等待
  while (!isOnSyncQueue(node)) {
    //進(jìn)行條件等待的線(xiàn)程都在這里被掛起, 線(xiàn)程被喚醒的情況有以下幾種:
    //1.同步隊(duì)列的前繼結(jié)點(diǎn)已取消
    //2.設(shè)置同步隊(duì)列的前繼結(jié)點(diǎn)的狀態(tài)為SIGNAL失敗
    //3.前繼結(jié)點(diǎn)釋放鎖后喚醒當(dāng)前結(jié)點(diǎn)
    LockSupport.park(this);
    //當(dāng)前線(xiàn)程醒來(lái)后立馬檢查是否被中斷, 如果是則代表結(jié)點(diǎn)取消條件等待, 此時(shí)需要將結(jié)點(diǎn)移出條件隊(duì)列
    if ((interruptMode = checkInterruptWhileWaiting(node)) != 0) {
      break;
    }
  }
  //線(xiàn)程醒來(lái)后就會(huì)以獨(dú)占模式獲取鎖
  if (acquireQueued(node, savedState) && interruptMode != THROW_IE) {
    interruptMode = REINTERRUPT;
  }
  //這步操作主要為防止線(xiàn)程在signal之前中斷而導(dǎo)致沒(méi)與條件隊(duì)列斷絕聯(lián)系
  if (node.nextWaiter != null) {
    unlinkCancelledWaiters();
  }
  //根據(jù)中斷模式進(jìn)行響應(yīng)的中斷處理
  if (interruptMode != 0) {
    reportInterruptAfterWait(interruptMode);
  }
}

當(dāng)線(xiàn)程調(diào)用await方法的時(shí)候,首先會(huì)將當(dāng)前線(xiàn)程包裝成node結(jié)點(diǎn)放入條件隊(duì)列尾部。在addConditionWaiter方法中,如果發(fā)現(xiàn)條件隊(duì)列尾結(jié)點(diǎn)已取消就會(huì)調(diào)用unlinkCancelledWaiters方法將條件隊(duì)列所有的已取消結(jié)點(diǎn)清空。這步操作是插入結(jié)點(diǎn)的準(zhǔn)備工作,那么確保了尾結(jié)點(diǎn)的狀態(tài)也是CONDITION之后,就會(huì)新建一個(gè)node結(jié)點(diǎn)將當(dāng)前線(xiàn)程包裝起來(lái)然后放入條件隊(duì)列尾部。注意,這個(gè)過(guò)程只是將結(jié)點(diǎn)添加到同步隊(duì)列尾部而沒(méi)有掛起線(xiàn)程哦。

第二步:完全將鎖釋放

//完全釋放鎖
final int fullyRelease(Node node) {
  boolean failed = true;
  try {
    //獲取當(dāng)前的同步狀態(tài)
    int savedState = getState();
    //使用當(dāng)前的同步狀態(tài)去釋放鎖
    if (release(savedState)) {
      failed = false;
      //如果釋放鎖成功就返回當(dāng)前同步狀態(tài)
      return savedState;
    } else {
      //如果釋放鎖失敗就拋出運(yùn)行時(shí)異常
      throw new IllegalMonitorStateException();
    }
  } finally {
    //保證沒(méi)有成功釋放鎖就將該結(jié)點(diǎn)設(shè)置為取消狀態(tài)
    if (failed) {
      node.waitStatus = Node.CANCELLED;
    }
  }
}

將當(dāng)前線(xiàn)程包裝成結(jié)點(diǎn)添加到條件隊(duì)列尾部后,緊接著就調(diào)用fullyRelease方法釋放鎖。注意,方法名為fullyRelease也就這步操作會(huì)完全的釋放鎖,因?yàn)殒i是可重入的,所以在進(jìn)行條件等待前需要將鎖全部釋放了,不然的話(huà)別人就獲取不了鎖了。如果釋放鎖失敗的話(huà)就會(huì)拋出一個(gè)運(yùn)行時(shí)異常,如果成功釋放了鎖的話(huà)就返回之前的同步狀態(tài)。

第三步:進(jìn)行條件等待

//線(xiàn)程一直在while循環(huán)里進(jìn)行條件等待
while (!isOnSyncQueue(node)) {
  //進(jìn)行條件等待的線(xiàn)程都在這里被掛起, 線(xiàn)程被喚醒的情況有以下幾種:
  //1.同步隊(duì)列的前繼結(jié)點(diǎn)已取消
  //2.設(shè)置同步隊(duì)列的前繼結(jié)點(diǎn)的狀態(tài)為SIGNAL失敗
  //3.前繼結(jié)點(diǎn)釋放鎖后喚醒當(dāng)前結(jié)點(diǎn)
  LockSupport.park(this);
  //當(dāng)前線(xiàn)程醒來(lái)后立馬檢查是否被中斷, 如果是則代表結(jié)點(diǎn)取消條件等待, 此時(shí)需要將結(jié)點(diǎn)移出條件隊(duì)列
  if ((interruptMode = checkInterruptWhileWaiting(node)) != 0) {
    break;
  }
}

//檢查條件等待時(shí)的線(xiàn)程中斷情況
private int checkInterruptWhileWaiting(Node node) {
  //中斷請(qǐng)求在signal操作之前:THROW_IE
  //中斷請(qǐng)求在signal操作之后:REINTERRUPT
  //期間沒(méi)有收到任何中斷請(qǐng)求:0
  return Thread.interrupted() ? (transferAfterCancelledWait(node) ? THROW_IE : REINTERRUPT) : 0;
}

//將取消條件等待的結(jié)點(diǎn)從條件隊(duì)列轉(zhuǎn)移到同步隊(duì)列中
final boolean transferAfterCancelledWait(Node node) {
  //如果這步CAS操作成功的話(huà)就表明中斷發(fā)生在signal方法之前
  if (compareAndSetWaitStatus(node, Node.CONDITION, 0)) {
    //狀態(tài)修改成功后就將該結(jié)點(diǎn)放入同步隊(duì)列尾部
    enq(node);
    return true;
  }
  //到這里表明CAS操作失敗, 說(shuō)明中斷發(fā)生在signal方法之后
  while (!isOnSyncQueue(node)) {
    //如果sinal方法還沒(méi)有將結(jié)點(diǎn)轉(zhuǎn)移到同步隊(duì)列, 就通過(guò)自旋等待一下
    Thread.yield();
  }
  return false;
}

在以上兩個(gè)操作完成了之后就會(huì)進(jìn)入while循環(huán),可以看到while循環(huán)里面首先調(diào)用LockSupport.park(this)將線(xiàn)程掛起了,所以線(xiàn)程就會(huì)一直在這里阻塞。在調(diào)用signal方法后僅僅只是將結(jié)點(diǎn)從條件隊(duì)列轉(zhuǎn)移到同步隊(duì)列中去,至于會(huì)不會(huì)喚醒線(xiàn)程需要看情況。如果轉(zhuǎn)移結(jié)點(diǎn)時(shí)發(fā)現(xiàn)同步隊(duì)列中的前繼結(jié)點(diǎn)已取消,或者是更新前繼結(jié)點(diǎn)的狀態(tài)為SIGNAL失敗,這兩種情況都會(huì)立即喚醒線(xiàn)程,否則的話(huà)在signal方法結(jié)束時(shí)就不會(huì)去喚醒已在同步隊(duì)列中的線(xiàn)程,而是等到它的前繼結(jié)點(diǎn)來(lái)喚醒。當(dāng)然,線(xiàn)程阻塞在這里除了可以調(diào)用signal方法喚醒之外,線(xiàn)程還可以響應(yīng)中斷,如果線(xiàn)程在這里收到中斷請(qǐng)求就會(huì)繼續(xù)往下執(zhí)行??梢钥吹骄€(xiàn)程醒來(lái)后會(huì)馬上檢查是否是由于中斷喚醒的還是通過(guò)signal方法喚醒的,如果是因?yàn)橹袛鄦拘训耐瑯訒?huì)將這個(gè)結(jié)點(diǎn)轉(zhuǎn)移到同步隊(duì)列中去,只不過(guò)是通過(guò)調(diào)用transferAfterCancelledWait方法來(lái)實(shí)現(xiàn)的。最后執(zhí)行完這一步之后就會(huì)返回中斷情況并跳出while循環(huán)。

第四步:結(jié)點(diǎn)移出條件隊(duì)列后的操作

//線(xiàn)程醒來(lái)后就會(huì)以獨(dú)占模式獲取鎖
if (acquireQueued(node, savedState) && interruptMode != THROW_IE) {
  interruptMode = REINTERRUPT;
}
//這步操作主要為防止線(xiàn)程在signal之前中斷而導(dǎo)致沒(méi)與條件隊(duì)列斷絕聯(lián)系
if (node.nextWaiter != null) {
  unlinkCancelledWaiters();
}
//根據(jù)中斷模式進(jìn)行響應(yīng)的中斷處理
if (interruptMode != 0) {
  reportInterruptAfterWait(interruptMode);
}

//結(jié)束條件等待后根據(jù)中斷情況做出相應(yīng)處理
private void reportInterruptAfterWait(int interruptMode) throws InterruptedException {
  //如果中斷模式是THROW_IE就拋出異常
  if (interruptMode == THROW_IE) {
    throw new InterruptedException();
  //如果中斷模式是REINTERRUPT就自己掛起
  } else if (interruptMode == REINTERRUPT) {
    selfInterrupt();
  }
}

當(dāng)線(xiàn)程終止了while循環(huán)也就是條件等待后,就會(huì)回到同步隊(duì)列中。不管是因?yàn)檎{(diào)用signal方法回去的還是因?yàn)榫€(xiàn)程中斷導(dǎo)致的,結(jié)點(diǎn)最終都會(huì)在同步隊(duì)列中。這時(shí)就會(huì)調(diào)用acquireQueued方法執(zhí)行在同步隊(duì)列中獲取鎖的操作,這個(gè)方法我們?cè)讵?dú)占模式這一篇已經(jīng)詳細(xì)的講過(guò)。也就是說(shuō),結(jié)點(diǎn)從條件隊(duì)列出來(lái)后又是乖乖的走獨(dú)占模式下獲取鎖的那一套,等這個(gè)結(jié)點(diǎn)再次獲得鎖之后,就會(huì)調(diào)用reportInterruptAfterWait方法來(lái)根據(jù)這期間的中斷情況做出相應(yīng)的響應(yīng)。如果中斷發(fā)生在signal方法之前,interruptMode就為T(mén)HROW_IE,再次獲得鎖后就拋出異常;如果中斷發(fā)生在signal方法之后,interruptMode就為REINTERRUPT,再次獲得鎖后就重新中斷。

2.不響應(yīng)線(xiàn)程中斷的條件等待

//不響應(yīng)線(xiàn)程中斷的條件等待
public final void awaitUninterruptibly() {
  //將當(dāng)前線(xiàn)程添加到條件隊(duì)列尾部
  Node node = addConditionWaiter();
  //完全釋放鎖并返回當(dāng)前同步狀態(tài)
  int savedState = fullyRelease(node);
  boolean interrupted = false;
  //結(jié)點(diǎn)一直在while循環(huán)里進(jìn)行條件等待
  while (!isOnSyncQueue(node)) {
    //條件隊(duì)列中所有的線(xiàn)程都在這里被掛起
    LockSupport.park(this);
    //線(xiàn)程醒來(lái)發(fā)現(xiàn)中斷并不會(huì)馬上去響應(yīng)
    if (Thread.interrupted()) {
      interrupted = true;
    }
  }
  if (acquireQueued(node, savedState) || interrupted) {
    //在這里響應(yīng)所有中斷請(qǐng)求, 滿(mǎn)足以下兩個(gè)條件之一就會(huì)將自己掛起
    //1.線(xiàn)程在條件等待時(shí)收到中斷請(qǐng)求
    //2.線(xiàn)程在acquireQueued方法里收到中斷請(qǐng)求
    selfInterrupt();
  }
}

3.設(shè)置相對(duì)時(shí)間的條件等待(不進(jìn)行自旋)

//設(shè)置定時(shí)條件等待(相對(duì)時(shí)間), 不進(jìn)行自旋等待
public final long awaitNanos(long nanosTimeout) throws InterruptedException {
  //如果線(xiàn)程被中斷則拋出異常
  if (Thread.interrupted()) {
    throw new InterruptedException();
  }
  //將當(dāng)前線(xiàn)程添加到條件隊(duì)列尾部
  Node node = addConditionWaiter();
  //在進(jìn)入條件等待之前先完全釋放鎖
  int savedState = fullyRelease(node);
  long lastTime = System.nanoTime();
  int interruptMode = 0;
  while (!isOnSyncQueue(node)) {
    //判斷超時(shí)時(shí)間是否用完了
    if (nanosTimeout <= 0L) {
      //如果已超時(shí)就需要執(zhí)行取消條件等待操作
      transferAfterCancelledWait(node);
      break;
    }
    //將當(dāng)前線(xiàn)程掛起一段時(shí)間, 線(xiàn)程在這期間可能被喚醒, 也可能自己醒來(lái)
    LockSupport.parkNanos(this, nanosTimeout);
    //線(xiàn)程醒來(lái)后先檢查中斷信息
    if ((interruptMode = checkInterruptWhileWaiting(node)) != 0) {
      break;
    }
    long now = System.nanoTime();
    //超時(shí)時(shí)間每次減去條件等待的時(shí)間
    nanosTimeout -= now - lastTime;
    lastTime = now;
  }
  //線(xiàn)程醒來(lái)后就會(huì)以獨(dú)占模式獲取鎖
  if (acquireQueued(node, savedState) && interruptMode != THROW_IE) {
    interruptMode = REINTERRUPT;
  }
  //由于transferAfterCancelledWait方法沒(méi)有把nextWaiter置空, 所有這里要再清理一遍
  if (node.nextWaiter != null) {
    unlinkCancelledWaiters();
  }
  //根據(jù)中斷模式進(jìn)行響應(yīng)的中斷處理
  if (interruptMode != 0) {
    reportInterruptAfterWait(interruptMode);
  }
  //返回剩余時(shí)間
  return nanosTimeout - (System.nanoTime() - lastTime);
}

4.設(shè)置相對(duì)時(shí)間的條件等待(進(jìn)行自旋)

//設(shè)置定時(shí)條件等待(相對(duì)時(shí)間), 進(jìn)行自旋等待
public final boolean await(long time, TimeUnit unit) throws InterruptedException {
  if (unit == null) { throw new NullPointerException(); }
  //獲取超時(shí)時(shí)間的毫秒數(shù)
  long nanosTimeout = unit.toNanos(time);
  //如果線(xiàn)程被中斷則拋出異常
  if (Thread.interrupted()) { throw new InterruptedException(); }
  //將當(dāng)前線(xiàn)程添加條件隊(duì)列尾部
  Node node = addConditionWaiter();
  //在進(jìn)入條件等待之前先完全釋放鎖
  int savedState = fullyRelease(node);
  //獲取當(dāng)前時(shí)間的毫秒數(shù)
  long lastTime = System.nanoTime();
  boolean timedout = false;
  int interruptMode = 0;
  while (!isOnSyncQueue(node)) {
    //如果超時(shí)就需要執(zhí)行取消條件等待操作
    if (nanosTimeout <= 0L) {
      timedout = transferAfterCancelledWait(node);
      break;
    }
    //如果超時(shí)時(shí)間大于自旋時(shí)間, 就將線(xiàn)程掛起一段時(shí)間
    if (nanosTimeout >= spinForTimeoutThreshold) {
      LockSupport.parkNanos(this, nanosTimeout);
    }
    //線(xiàn)程醒來(lái)后先檢查中斷信息
    if ((interruptMode = checkInterruptWhileWaiting(node)) != 0) {
      break;
    }
    long now = System.nanoTime();
    //超時(shí)時(shí)間每次減去條件等待的時(shí)間
    nanosTimeout -= now - lastTime;
    lastTime = now;
  }
  //線(xiàn)程醒來(lái)后就會(huì)以獨(dú)占模式獲取鎖
  if (acquireQueued(node, savedState) && interruptMode != THROW_IE) {
    interruptMode = REINTERRUPT;
  }
  //由于transferAfterCancelledWait方法沒(méi)有把nextWaiter置空, 所有這里要再清理一遍
  if (node.nextWaiter != null) {
    unlinkCancelledWaiters();
  }
  //根據(jù)中斷模式進(jìn)行響應(yīng)的中斷處理
  if (interruptMode != 0) {
    reportInterruptAfterWait(interruptMode);
  }
  //返回是否超時(shí)標(biāo)志
  return !timedout;
}

5.設(shè)置絕對(duì)時(shí)間的條件等待

//設(shè)置定時(shí)條件等待(絕對(duì)時(shí)間)
public final boolean awaitUntil(Date deadline) throws InterruptedException {
  if (deadline == null) { throw new NullPointerException(); } 
  //獲取絕對(duì)時(shí)間的毫秒數(shù)
  long abstime = deadline.getTime();
  //如果線(xiàn)程被中斷則拋出異常
  if (Thread.interrupted()) { throw new InterruptedException(); }
  //將當(dāng)前線(xiàn)程添加到條件隊(duì)列尾部
  Node node = addConditionWaiter();
  //在進(jìn)入條件等待之前先完全釋放鎖
  int savedState = fullyRelease(node);
  boolean timedout = false;
  int interruptMode = 0;
  while (!isOnSyncQueue(node)) {
    //如果超時(shí)就需要執(zhí)行取消條件等待操作
    if (System.currentTimeMillis() > abstime) {
      timedout = transferAfterCancelledWait(node);
      break;
    }
    //將線(xiàn)程掛起一段時(shí)間, 期間線(xiàn)程可能被喚醒, 也可能到了點(diǎn)自己醒來(lái)
    LockSupport.parkUntil(this, abstime);
    //線(xiàn)程醒來(lái)后先檢查中斷信息
    if ((interruptMode = checkInterruptWhileWaiting(node)) != 0) {
      break;
    }
  }
  //線(xiàn)程醒來(lái)后就會(huì)以獨(dú)占模式獲取鎖
  if (acquireQueued(node, savedState) && interruptMode != THROW_IE) {
    interruptMode = REINTERRUPT;
  }
  //由于transferAfterCancelledWait方法沒(méi)有把nextWaiter置空, 所有這里要再清理一遍
  if (node.nextWaiter != null) {
    unlinkCancelledWaiters();
  }
  //根據(jù)中斷模式進(jìn)行響應(yīng)的中斷處理
  if (interruptMode != 0) {
    reportInterruptAfterWait(interruptMode);
  }
  //返回是否超時(shí)標(biāo)志
  return !timedout;
}

6.喚醒條件隊(duì)列中的頭結(jié)點(diǎn)

//喚醒條件隊(duì)列中的下一個(gè)結(jié)點(diǎn)
public final void signal() {
  //判斷當(dāng)前線(xiàn)程是否持有鎖
  if (!isHeldExclusively()) {
    throw new IllegalMonitorStateException();
  }
  Node first = firstWaiter;
  //如果條件隊(duì)列中有排隊(duì)者
  if (first != null) {
    //喚醒條件隊(duì)列中的頭結(jié)點(diǎn)
    doSignal(first);
  }
}

//喚醒條件隊(duì)列中的頭結(jié)點(diǎn)
private void doSignal(Node first) {
  do {
    //1.將firstWaiter引用向后移動(dòng)一位
    if ( (firstWaiter = first.nextWaiter) == null) {
      lastWaiter = null;
    }
    //2.將頭結(jié)點(diǎn)的后繼結(jié)點(diǎn)引用置空
    first.nextWaiter = null;
    //3.將頭結(jié)點(diǎn)轉(zhuǎn)移到同步隊(duì)列, 轉(zhuǎn)移完成后有可能喚醒線(xiàn)程
    //4.如果transferForSignal操作失敗就去喚醒下一個(gè)結(jié)點(diǎn)
  } while (!transferForSignal(first) && (first = firstWaiter) != null);
}

//將指定結(jié)點(diǎn)從條件隊(duì)列轉(zhuǎn)移到同步隊(duì)列中
final boolean transferForSignal(Node node) {
  //將等待狀態(tài)從CONDITION設(shè)置為0
  if (!compareAndSetWaitStatus(node, Node.CONDITION, 0)) {
    //如果更新?tīng)顟B(tài)的操作失敗就直接返回false
    //可能是transferAfterCancelledWait方法先將狀態(tài)改變了, 導(dǎo)致這步CAS操作失敗
    return false;
  }
  //將該結(jié)點(diǎn)添加到同步隊(duì)列尾部
  Node p = enq(node);
  int ws = p.waitStatus;
  if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL)) {
    //出現(xiàn)以下情況就會(huì)喚醒當(dāng)前線(xiàn)程
    //1.前繼結(jié)點(diǎn)是取消狀態(tài)
    //2.更新前繼結(jié)點(diǎn)的狀態(tài)為SIGNAL操作失敗
    LockSupport.unpark(node.thread);
  }
  return true;
}

可以看到signal方法最終的核心就是去調(diào)用transferForSignal方法,在transferForSignal方法中首先會(huì)用CAS操作將結(jié)點(diǎn)的狀態(tài)從CONDITION設(shè)置為0,然后再調(diào)用enq方法將該結(jié)點(diǎn)添加到同步隊(duì)列尾部。我們?cè)倏吹浇酉聛?lái)的if判斷語(yǔ)句,這個(gè)判斷語(yǔ)句主要是用來(lái)判斷什么時(shí)候會(huì)去喚醒線(xiàn)程,出現(xiàn)這兩種情況就會(huì)立即喚醒線(xiàn)程,一種是當(dāng)發(fā)現(xiàn)前繼結(jié)點(diǎn)的狀態(tài)是取消狀態(tài)時(shí),還有一種是更新前繼結(jié)點(diǎn)的狀態(tài)失敗時(shí)。這兩種情況都會(huì)馬上去喚醒線(xiàn)程,否則的話(huà)就僅僅只是將結(jié)點(diǎn)從條件隊(duì)列中轉(zhuǎn)移到同步隊(duì)列中就完了,而不會(huì)立馬去喚醒結(jié)點(diǎn)中的線(xiàn)程。signalAll方法也大致類(lèi)似,只不過(guò)它是去循環(huán)遍歷條件隊(duì)列中的所有結(jié)點(diǎn),并將它們轉(zhuǎn)移到同步隊(duì)列,轉(zhuǎn)移結(jié)點(diǎn)的方法也還是調(diào)用transferForSignal方法。

7.喚醒條件隊(duì)列的所有結(jié)點(diǎn)

//喚醒條件隊(duì)列后面的全部結(jié)點(diǎn)
public final void signalAll() {
  //判斷當(dāng)前線(xiàn)程是否持有鎖
  if (!isHeldExclusively()) {
    throw new IllegalMonitorStateException();
  }
  //獲取條件隊(duì)列頭結(jié)點(diǎn)
  Node first = firstWaiter;
  if (first != null) {
    //喚醒條件隊(duì)列的所有結(jié)點(diǎn)
    doSignalAll(first);
  }
}

//喚醒條件隊(duì)列的所有結(jié)點(diǎn)
private void doSignalAll(Node first) {
  //先把頭結(jié)點(diǎn)和尾結(jié)點(diǎn)的引用置空
  lastWaiter = firstWaiter = null;
  do {
    //先獲取后繼結(jié)點(diǎn)的引用
    Node next = first.nextWaiter;
    //把即將轉(zhuǎn)移的結(jié)點(diǎn)的后繼引用置空
    first.nextWaiter = null;
    //將結(jié)點(diǎn)從條件隊(duì)列轉(zhuǎn)移到同步隊(duì)列
    transferForSignal(first);
    //將引用指向下一個(gè)結(jié)點(diǎn)
    first = next;
  } while (first != null);
}

至此,我們整個(gè)的AbstractQueuedSynchronizer源碼分析就結(jié)束了,相信通過(guò)這四篇的分析,大家能更好的掌握并理解AQS。這個(gè)類(lèi)確實(shí)很重要,因?yàn)樗瞧渌芏嗤筋?lèi)的基石,由于筆者水平和表達(dá)能力有限,如果哪些地方?jīng)]有表述清楚的,或者理解不到位的,還請(qǐng)廣大讀者們能夠及時(shí)指正,共同探討學(xué)習(xí)。可在下方留言閱讀中所遇到的問(wèn)題,如果有需要AQS注釋源碼的也可聯(lián)系筆者索取。

注:以上全部分析基于JDK1.7,不同版本間會(huì)有差異,讀者需要注意。

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

相關(guān)文章

  • Java中的.concat()方法實(shí)例詳解

    Java中的.concat()方法實(shí)例詳解

    concat()方法用于將指定的字符串參數(shù)連接到字符串上,.concat()方法是一種連接兩個(gè)字符串的簡(jiǎn)單方法,可以幫助我們?cè)贘ava中處理字符串,對(duì)java .concat()方法用法感興趣的朋友一起看看吧
    2024-01-01
  • RxJava2 Scheduler使用實(shí)例深入解析

    RxJava2 Scheduler使用實(shí)例深入解析

    這篇文章主要為大家介紹了RxJava2 Scheduler使用實(shí)例深入解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-10-10
  • 很詳細(xì)的Log4j配置步驟

    很詳細(xì)的Log4j配置步驟

    Log4J的配置文件(Configuration File)就是用來(lái)設(shè)置記錄器的級(jí)別、存放器和布局的,它可接key=value格式的設(shè)置或xml格式的設(shè)置信息。通過(guò)配置,可以創(chuàng)建出Log4J的運(yùn)行環(huán)境。
    2008-11-11
  • java程序代碼與文本對(duì)比實(shí)用工具簡(jiǎn)介

    java程序代碼與文本對(duì)比實(shí)用工具簡(jiǎn)介

    可以對(duì)兩段文本進(jìn)行對(duì)比,檢測(cè)/比較兩個(gè)文本有什么不同的差異,以便修改,常用于程序代碼,就是不需要人工查看,尤其是大文件,有幾百上千行的代碼,這時(shí)候就建議使用比較工具了,不用浪費(fèi)過(guò)多時(shí)間去尋找
    2021-09-09
  • spring boot下 500 404 錯(cuò)誤頁(yè)面處理的方法

    spring boot下 500 404 錯(cuò)誤頁(yè)面處理的方法

    本篇文章主要介紹了spring boot下 500 404 錯(cuò)誤頁(yè)面處理的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-04-04
  • Java編程中的HashSet和BitSet詳解

    Java編程中的HashSet和BitSet詳解

    這篇文章主要介紹了Java編程中的HashSet和BitSet詳解的相關(guān)資料,需要的朋友可以參考下
    2017-03-03
  • java對(duì)象轉(zhuǎn)成byte數(shù)組的3種方法

    java對(duì)象轉(zhuǎn)成byte數(shù)組的3種方法

    這篇文章主要為大家詳細(xì)介紹了java對(duì)象轉(zhuǎn)成byte數(shù)組的3種方法,具有一定的參考價(jià)值,感興趣的朋友可以參考一下
    2018-06-06
  • 詳解hibernate4基本實(shí)現(xiàn)原理

    詳解hibernate4基本實(shí)現(xiàn)原理

    本文通過(guò)圖文并茂的形式給大家介紹的hibernate4基本實(shí)現(xiàn)原理,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友參考下吧
    2017-09-09
  • 淺談為什么同一個(gè)java文件只能有一個(gè)public類(lèi)

    淺談為什么同一個(gè)java文件只能有一個(gè)public類(lèi)

    這篇文章主要介紹了淺談為什么同一個(gè)java文件只能有一個(gè)public類(lèi),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-11-11
  • Yml轉(zhuǎn)properties文件工具類(lèi)YmlUtils的詳細(xì)過(guò)程(不用引任何插件和依賴(lài))

    Yml轉(zhuǎn)properties文件工具類(lèi)YmlUtils的詳細(xì)過(guò)程(不用引任何插件和依賴(lài))

    這篇文章主要介紹了Yml轉(zhuǎn)properties文件工具類(lèi)YmlUtils(不用引任何插件和依賴(lài)),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-08-08

最新評(píng)論