亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Java多線程Condition接口原理介紹

 更新時(shí)間:2020年09月30日 14:36:20   作者:拉里·佩奇  
這篇文章主要介紹了Java多線程Condition接口原理介紹,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧

Condition接口提供了類似Object的監(jiān)視器方法,與Lock配合可以實(shí)現(xiàn)等待/通知模式,但是這兩者在使用方式以及功能特性上還是有差別的

Condition接口詳解

Condition定義了等待/通知兩種類型的方法,當(dāng)前線程調(diào)用這些方法時(shí),需要提前獲取到Condition對(duì)象關(guān)聯(lián)的鎖。Condition對(duì)象是由Lock對(duì)象(調(diào)用Lock對(duì)象的newCondition()方法)創(chuàng)建出來(lái)的,換句話說(shuō),Condition是依賴Lock對(duì)象的。

Lock lock = new ReentrantLock();
 Condition condition = lock.newCondition();
 public void conditionWait() throws InterruptedException {
  lock.lock();
  try {
   condition.await();
  } finally {
   lock.unlock();
  }
 }
 public void conditionSignal() throws InterruptedException {
  lock.lock();
  try {
   condition.signal();
  } finally {
   lock.unlock();
  }
 }

一般都會(huì)將Condition對(duì)象作為成員變量。當(dāng)調(diào)用await()方法后,當(dāng)前線程會(huì)釋放鎖并在此等待,而其他線程調(diào)用Condition對(duì)象的signal()方法,通知當(dāng)前線程后,當(dāng)前線程才從await()方法返回,并且在返回前已經(jīng)獲取了鎖。

 /**
  * 當(dāng)前線程進(jìn)入等待狀態(tài)直到被通知(signal)或中斷,當(dāng)前線程進(jìn)入后臺(tái)運(yùn)行狀態(tài)且從await()方法返回
  * 其他線程調(diào)用該Condition的signal或者signalAll方法,而當(dāng)前線程被選中喚醒
  * 1、其他線程(interrupt)中斷當(dāng)前線程
  * 2、如果當(dāng)前等待線程從await方法返回,那么表明當(dāng)前線程已經(jīng)獲取了Condition對(duì)象的鎖
  */
 void await() throws InterruptedException;

 /**
  * 當(dāng)前線程進(jìn)入等待狀態(tài)直到被通知,對(duì)中斷不響應(yīng)
  */
 void awaitUninterruptibly();

 /**
  * <pre> {@code
  * boolean aMethod(long timeout, TimeUnit unit) {
  * long nanos = unit.toNanos(timeout);
  * lock.lock();
  * try {
  *  while (!conditionBeingWaitedFor()) {
  *  if (nanos <= 0L)
  *   return false;
  *  nanos = theCondition.awaitNanos(nanos);
  *  }
  *  // ...
  * } finally {
  *  lock.unlock();
  * }
  * }}</pre>
  * 當(dāng)前線程進(jìn)入等待狀態(tài)直到被通知、中斷或超時(shí)。返回值表示剩余時(shí)間,如果在nanosTimeout納秒之前被喚醒,那么返回值就是nanosTimeout-實(shí)際耗時(shí)
  * 返回值<=0說(shuō)明超時(shí)
  * 
  */
 long awaitNanos(long nanosTimeout) throws InterruptedException;

 /**
  * 當(dāng)前線程進(jìn)入等待狀態(tài)直到被通知、中斷或超時(shí),如果沒(méi)有到指定時(shí)間被通知返回true,否則返回false
  */
 boolean await(long time, TimeUnit unit) throws InterruptedException;

 /**
  * 喚醒一個(gè)等待在Condition上的線程,該線程從等待方法返回之前必須獲得與Condition相關(guān)聯(lián)的鎖
  */
 void signal();

獲取一個(gè)Condition必須通過(guò)Lock的newCondition()方法。下面通過(guò)一個(gè)有界隊(duì)列的示例來(lái)深入了解Condition的使用方式。

有界隊(duì)列是一種特殊的隊(duì)列,當(dāng)隊(duì)列為空時(shí),隊(duì)列的獲取操作將會(huì)阻塞獲取線程,直到隊(duì)列中有新增元素,當(dāng)隊(duì)列已滿時(shí),隊(duì)列的插入操作將會(huì)阻塞插入線程,直到隊(duì)列出現(xiàn)“空位”

public class BoundedQueue<T> {
 private Object[] items;

 // 添加的下標(biāo),刪除的下標(biāo)和數(shù)組當(dāng)前數(shù)量
 private int addIndex,removeIndex,count;
 private Lock lock = new ReentrantLock();
 private Condition notEmpty = lock.newCondition();
 private Condition notFull = lock.newCondition();
 public BoundedQueue(int size){
  items = new Object[size];
 }

 /**
  * 添加一個(gè)元素,如果數(shù)組滿,則添加線程進(jìn)入等待狀態(tài),直到有"空位"
  * @author fuyuwei
  * 2017年5月21日 下午6:14:55
  * @param t
  * @throws InterruptedException
  */
 public void add(T t) throws InterruptedException{
  lock.lock();
  try{
   while(count == items.length){
    notFull.await();
   }
   items[addIndex] = t;
   if(++addIndex == items.length)
    addIndex = 0;
   ++count;
   notEmpty.signal();
  }finally{
   lock.unlock();
  }
 }

 /**
  * 由頭部刪除一個(gè)元素,如果數(shù)組空,則刪除線程進(jìn)入等待狀態(tài),直到有新添加元素
  * @author fuyuwei
  * 2017年5月21日 下午6:20:54
  * @return
  * @throws InterruptedException
  */
 @SuppressWarnings("unchecked")
 public T remove() throws InterruptedException{
  lock.lock();
  try{
   while(count == 0)
    notEmpty.await();
   Object x = items[removeIndex];
   if(++removeIndex == items.length)
    removeIndex = 0;
   --count;
   notFull.signal();
   return (T)x;
  }finally{
   lock.unlock();
  }
 }
}

首先需要獲得鎖,目的是確保數(shù)組修改的可見(jiàn)性和排他性。當(dāng)數(shù)組數(shù)量等于數(shù)組長(zhǎng)度時(shí),表示數(shù)組已滿,則調(diào)用notFull.await(),當(dāng)前線程隨之釋放鎖并進(jìn)入等待狀態(tài)。如果數(shù)組數(shù)量不等于數(shù)組長(zhǎng)度,表示數(shù)組未滿,則添加元素到數(shù)組中,同時(shí)通知等待在notEmpty上的線程,數(shù)組中已經(jīng)有新元素可以獲取。

在添加和刪除方法中使用while循環(huán)而非if判斷,目的是防止過(guò)早或意外的通知,只有條件符合才能夠退出循環(huán)?;叵胫疤岬降牡却?通知的經(jīng)典范式,二者是非常類似的

Condition原理分析

ConditionObject是同步器AbstractQueuedSynchronizer的內(nèi)部類,因?yàn)镃ondition的操作需要獲取相關(guān)聯(lián)的鎖,所以作為同步器的內(nèi)部類也較為合理。每個(gè)Condition對(duì)象都包含著一個(gè)隊(duì)列,該隊(duì)列是Condition對(duì)象實(shí)現(xiàn)等待/通知功能的關(guān)鍵。下面將分析Condition的實(shí)現(xiàn),主要包括:等待隊(duì)列、等待和通知

等待隊(duì)列

等待隊(duì)列是一個(gè)FIFO的隊(duì)列,在隊(duì)列中的每個(gè)節(jié)點(diǎn)都包含了一個(gè)線程引用,該線程就是在Condition對(duì)象上等待的線程,如果一個(gè)線程調(diào)用了Condition.await()方法,那么該線程將會(huì)釋放鎖、構(gòu)造成節(jié)點(diǎn)加入等待隊(duì)列并進(jìn)入等待狀態(tài)

一個(gè)Condition包含一個(gè)等待隊(duì)列,Condition擁有首節(jié)點(diǎn)(firstWaiter)和尾節(jié)點(diǎn)(lastWaiter)。當(dāng)前線程調(diào)用Condition.await()方法,將會(huì)以當(dāng)前線程構(gòu)造節(jié)點(diǎn),并將節(jié)點(diǎn)從尾部加入等待隊(duì)列,等待隊(duì)列的基本結(jié)構(gòu)如下圖所示

如圖所示,Condition擁有首尾節(jié)點(diǎn)的引用,而新增節(jié)點(diǎn)只需要將原有的尾節(jié)點(diǎn)nextWaiter指向它,并且更新尾節(jié)點(diǎn)即可。上述節(jié)點(diǎn)引用更新的過(guò)程并沒(méi)有使用CAS保證,原因在于調(diào)用await()方法的線程必定是獲取了鎖的線程,也就是說(shuō)該過(guò)程是由鎖來(lái)保證線程安全的。在Object的監(jiān)視器模型上,一個(gè)對(duì)象擁有一個(gè)同步隊(duì)列和等待隊(duì)列,而并發(fā)包中的Lock(更確切地說(shuō)是同步器)擁有一個(gè)同步隊(duì)列和多個(gè)等待隊(duì)列,其對(duì)應(yīng)關(guān)系如下圖所示

等待

調(diào)用Condition的await()方法(或者以await開頭的方法),會(huì)使當(dāng)前線程進(jìn)入等待隊(duì)列并釋放鎖,同時(shí)線程狀態(tài)變?yōu)榈却隣顟B(tài)。當(dāng)從await()方法返回時(shí),當(dāng)前線程一定獲取了Condition相關(guān)聯(lián)的鎖。

如果從隊(duì)列(同步隊(duì)列和等待隊(duì)列)的角度看await()方法,當(dāng)調(diào)用await()方法時(shí),相當(dāng)于同步隊(duì)列的首節(jié)點(diǎn)(獲取了鎖的節(jié)點(diǎn))移動(dòng)到Condition的等待隊(duì)列中

public final void await() throws InterruptedException {
  if (Thread.interrupted())
   throw new InterruptedException();
  // 當(dāng)前線程加入等待隊(duì)列
  Node node = addConditionWaiter();
  // 釋放同步狀態(tài),也就是釋放鎖
  int savedState = fullyRelease(node);
  int interruptMode = 0;
  while (!isOnSyncQueue(node)) {
   LockSupport.park(this);
   if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
    break;
  }
  if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
   interruptMode = REINTERRUPT;
  if (node.nextWaiter != null)
   unlinkCancelledWaiters();
  if (interruptMode != 0)
   reportInterruptAfterWait(interruptMode);
 }

調(diào)用該方法的線程成功獲取了鎖的線程,也就是同步隊(duì)列中的首節(jié)點(diǎn),該方法會(huì)將當(dāng)前線程構(gòu)造成節(jié)點(diǎn)并加入等待隊(duì)列中,然后釋放同步狀態(tài),喚醒同步隊(duì)列中的后繼節(jié)點(diǎn),然后當(dāng)前線程會(huì)進(jìn)入等待狀態(tài)。當(dāng)?shù)却?duì)列中的節(jié)點(diǎn)被喚醒,則喚醒節(jié)點(diǎn)的線程開始嘗試獲取同步狀態(tài)。如果不是通過(guò)其他線程調(diào)用Condition.signal()方法喚醒,而是對(duì)等待線程進(jìn)行中斷,則會(huì)拋出InterruptedException

通知

調(diào)用Condition的signal()方法,將會(huì)喚醒在等待隊(duì)列中等待時(shí)間最長(zhǎng)的節(jié)點(diǎn)(首節(jié)點(diǎn)),在喚醒節(jié)點(diǎn)之前,會(huì)將節(jié)點(diǎn)移到同步隊(duì)列中

public final void signal() {
  if (!isHeldExclusively())
   throw new IllegalMonitorStateException();
  Node first = firstWaiter;
  if (first != null)
   doSignal(first);
 }

調(diào)用該方法的前置條件是當(dāng)前線程必須獲取了鎖,可以看到signal()方法進(jìn)行了isHeldExclusively()檢查,也就是當(dāng)前線程必須是獲取了鎖的線程。接著獲取等待隊(duì)列的首節(jié)點(diǎn),將其移動(dòng)到同步隊(duì)列并使用LockSupport喚醒節(jié)點(diǎn)中的線程

節(jié)點(diǎn)從等待隊(duì)列移動(dòng)到同步隊(duì)列的過(guò)程如下圖所示

通過(guò)調(diào)用同步器的enq(Node node)方法,等待隊(duì)列中的頭節(jié)點(diǎn)線程安全地移動(dòng)到同步隊(duì)列。當(dāng)節(jié)點(diǎn)移動(dòng)到同步隊(duì)列后,當(dāng)前線程再使用LockSupport喚醒該節(jié)點(diǎn)的線程。

被喚醒后的線程,將從await()方法中的while循環(huán)中退出(isOnSyncQueue(Node node)方法返回true,節(jié)點(diǎn)已經(jīng)在同步隊(duì)列中),進(jìn)而調(diào)用同步器的acquireQueued()方法加入到獲取同步狀態(tài)的競(jìng)爭(zhēng)中。

成功獲取同步狀態(tài)(或者說(shuō)鎖)之后,被喚醒的線程將從先前調(diào)用的await()方法返回,此時(shí)該線程已經(jīng)成功地獲取了鎖。

Condition的signalAll()方法,相當(dāng)于對(duì)等待隊(duì)列中的每個(gè)節(jié)點(diǎn)均執(zhí)行一次signal()方法,效果就是將等待隊(duì)列中所有節(jié)點(diǎn)全部移動(dòng)到同步隊(duì)列中,并喚醒每個(gè)節(jié)點(diǎn)的線程。

以上這篇Java多線程Condition接口原理介紹就是小編分享給大家的全部?jī)?nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • Java中的NoSuchMethodException異常原因以及解決方案詳解

    Java中的NoSuchMethodException異常原因以及解決方案詳解

    這篇文章主要介紹了Java中的NoSuchMethodException異常原因以及解決方案詳解,NoSuchMethodException是Java反射機(jī)制中的異常,在嘗試通過(guò)反射獲取方法時(shí),找不到指定的方法,通常發(fā)生在調(diào)用?Class?對(duì)象的方法時(shí),當(dāng)方法名或方法參數(shù)不匹配時(shí)拋出該異常,需要的朋友可以參考下
    2024-02-02
  • JAVA讀取二進(jìn)制文件以及畫圖教程

    JAVA讀取二進(jìn)制文件以及畫圖教程

    由于項(xiàng)目需要,需要對(duì)二進(jìn)制文件進(jìn)行讀取,所以這篇文章主要給大家介紹了關(guān)于JAVA讀取二進(jìn)制文件以及畫圖的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-07-07
  • IntelliJ?IDEA?2022.2.3最新激活圖文教程(親測(cè)有用永久激活)

    IntelliJ?IDEA?2022.2.3最新激活圖文教程(親測(cè)有用永久激活)

    今天給大家分享一個(gè)?IDEA?2022.2.3?的激活破解教程,全文通過(guò)文字+圖片的方式講解,手把手教你如何激活破解?IDEA,?只需要幾分鐘即可搞定,對(duì)idea2022.2.3激活碼感興趣的朋友跟隨小編一起看看吧
    2022-11-11
  • 使用redisTemplate從redis獲取所有數(shù)據(jù)

    使用redisTemplate從redis獲取所有數(shù)據(jù)

    這篇文章主要介紹了使用redisTemplate從redis獲取所有數(shù)據(jù),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-06-06
  • 解決SecureRandom.getInstanceStrong()引發(fā)的線程阻塞問(wèn)題

    解決SecureRandom.getInstanceStrong()引發(fā)的線程阻塞問(wèn)題

    這篇文章主要介紹了解決SecureRandom.getInstanceStrong()引發(fā)的線程阻塞問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • Java后臺(tái)生成圖片的完整步驟

    Java后臺(tái)生成圖片的完整步驟

    在一些詳情頁(yè)面中,可能需要對(duì)上傳到服務(wù)器中的圖片生成以縮略圖的形式展示,這篇文章主要給大家介紹了關(guān)于Java后臺(tái)生成圖片的相關(guān)資料,需要的朋友可以參考下
    2021-08-08
  • Mybatis-plus在項(xiàng)目中的簡(jiǎn)單應(yīng)用

    Mybatis-plus在項(xiàng)目中的簡(jiǎn)單應(yīng)用

    Mybatis-plus是Spring框架中OOM的一大利器,其簡(jiǎn)單易用參考官網(wǎng)文檔即可很快上手,本文主要介紹了邏輯刪除,自動(dòng)填充,分頁(yè)插件等的簡(jiǎn)單使用,感興趣的可以了解一下
    2021-07-07
  • Java代碼中如何設(shè)置輸出字符集為UTF-8

    Java代碼中如何設(shè)置輸出字符集為UTF-8

    這篇文章主要介紹了Java代碼中設(shè)置輸出字符集為UTF-8,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-05-05
  • Java集合框架之LinkedHashSet類解讀

    Java集合框架之LinkedHashSet類解讀

    這篇文章主要介紹了Java集合框架之LinkedHashSet類解讀,LinkedHashSet是HashSet的有序版本,它跨所有元素維護(hù)一個(gè)雙向鏈接的List,當(dāng)需要維護(hù)迭代順序時(shí),就使用這個(gè)類,當(dāng)遍歷HashSet時(shí),順序是不可預(yù)測(cè)的,需要的朋友可以參考下
    2023-09-09
  • Java TreeSet類的簡(jiǎn)單理解和使用

    Java TreeSet類的簡(jiǎn)單理解和使用

    這篇文章主要介紹了Java TreeSet類的簡(jiǎn)單理解和使用,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-02-02

最新評(píng)論