一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - Java并發之Condition案例詳解

Java并發之Condition案例詳解

2021-12-13 14:35數月亮 Java教程

這篇文章主要介紹了Java并發之Condition案例詳解,本篇文章通過簡要的案例,講解了該項技術的了解與使用,以下就是詳細內容,需要的朋友可以參考下

在使用Lock之前,我們使用的最多的同步方式應該是synchronized關鍵字來實現同步方式了。配合Object的wait()、notify()系列方法可以實現等待/通知模式。Condition接口也提供了類似Object的監視器方法,與Lock配合可以實現等待/通知模式,但是這兩者在使用方式以及功能特性上還是有差別的。Object和Condition接口的一些對比。摘自《Java并發編程的藝術》

Java并發之Condition案例詳解

 

一、Condition接口介紹和示例

首先我們需要明白condition對象是依賴于lock對象的,意思就是說condition對象需要通過lock對象進行創建出來(調用Lock對象的newCondition()方法)。consition的使用方式非常的簡單。但是需要注意在調用方法前獲取鎖。

package com.ydl.test.juc;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class ConditionUseCase {

  public Lock lock = new ReentrantLock();
  public Condition condition = lock.newCondition();

  public static void main(String[] args)  {
      ConditionUseCase useCase = new ConditionUseCase();
      ExecutorService executorService = Executors.newFixedThreadPool (2);
      executorService.execute(new Runnable() {
          @Override
          public void run() {
              useCase.conditionWait();
          }
      });
      executorService.execute(new Runnable() {
          @Override
          public void run() {
              useCase.conditionSignal();
          }
      });
  }

  public void conditionWait()  {
      lock.lock();
      try {
          System.out.println(Thread.currentThread().getName() + "拿到鎖了");
          System.out.println(Thread.currentThread().getName() + "等待信號");
          condition.await();
          System.out.println(Thread.currentThread().getName() + "拿到信號");
      }catch (Exception e){

      }finally {
          lock.unlock();
      }
  }
  public void conditionSignal() {
      lock.lock();
      try {
          Thread.sleep(5000);
          System.out.println(Thread.currentThread().getName() + "拿到鎖了");
          condition.signal();
          System.out.println(Thread.currentThread().getName() + "發出信號");
      }catch (Exception e){

      }finally {
          lock.unlock();
      }
  }

}

1 pool-1-thread-1拿到鎖了

2 pool-1-thread-1等待信號
3 pool-1-thread-2拿到鎖了
4 pool-1-thread-2發出信號

如示例所示,一般都會將Condition對象作為成員變量。當調用await()方法后,當前線程會釋放鎖并在此等待,而其他線程調用Condition對象的signal()方法,通知當前線程后,當前線程才從await()方法返回,并且在返回前已經獲取了鎖。

 

二、Condition接口常用方法

condition可以通俗的理解為條件隊列。當一個線程在調用了await方法以后,直到線程等待的某個條件為真的時候才會被喚醒。這種方式為線程提供了更加簡單的等待/通知模式。Condition必須要配合鎖一起使用,因為對共享狀態變量的訪問發生在多線程環境下。一個Condition的實例必須與一個Lock綁定,因此Condition一般都是作為Lock的內部實現。

  1. await() :造成當前線程在接到信號或被中斷之前一直處于等待狀態。
  2. await(long time, TimeUnit unit) :造成當前線程在接到信號、被中斷或到達指定等待時間之前一直處于等待狀態。
  3. awaitNanos(long nanosTimeout) :造成當前線程在接到信號、被中斷或到達指定等待時間之前一直處于等待狀態。返回值表示剩余時間,如果在nanosTimesout之前喚醒,那么返回值 = nanosTimeout - 消耗時間,如果返回值 <= 0 ,則可以認定它已經超時了。
  4. awaitUninterruptibly() :造成當前線程在接到信號之前一直處于等待狀態。【注意:該方法對中斷不敏感】。
  5. awaitUntil(Date deadline) :造成當前線程在接到信號、被中斷或到達指定最后期限之前一直處于等待狀態。如果沒有到指定時間就被通知,則返回true,否則表示到了指定時間,返回返回false。
  6. signal() :喚醒一個等待線程。該線程從等待方法返回前必須獲得與Condition相關的鎖。
  7. signal()All :喚醒所有等待線程。能夠從等待方法返回的線程必須獲得與Condition相關的鎖。

 

三、Condition接口原理簡單解析

Condition是AQS的內部類。每個Condition對象都包含一個隊列(等待隊列)。等待隊列是一個FIFO的隊列,在隊列中的每個節點都包含了一個線程引用,該線程就是在Condition對象上等待的線程,如果一個線程調用了Condition.await()方法,那么該線程將會釋放鎖、構造成節點加入等待隊列并進入等待狀態。等待隊列的基本結構如下所示。

Java并發之Condition案例詳解

等待分為首節點和尾節點。當一個線程調用Condition.await()方法,將會以當前線程構造節點,并將節點從尾部加入等待隊列。新增節點就是將尾部節點指向新增的節點。節點引用更新本來就是在獲取鎖以后的操作,所以不需要CAS保證。同時也是線程安全的操作。

3.1、等待

當線程調用了await方法以后。線程就作為隊列中的一個節點被加入到等待隊列中去了。同時會釋放鎖的擁有。當從await方法返回的時候。一定會獲取condition相關聯的鎖。當等待隊列中的節點被喚醒的時候,則喚醒節點的線程開始嘗試獲取同步狀態。如果不是通過 其他線程調用Condition.signal()方法喚醒,而是對等待線程進行中斷,則會拋出InterruptedException異常信息。

3.2、通知

調用Condition的signal()方法,將會喚醒在等待隊列中等待最長時間的節點(條件隊列里的首節點),在喚醒節點前,會將節點移到同步隊列中。當前線程加入到等待隊列中如圖所示:

Java并發之Condition案例詳解

在調用signal()方法之前必須先判斷是否獲取到了鎖。接著獲取等待隊列的首節點,將其移動到同步隊列并且利用LockSupport喚醒節點中的線程。節點從等待隊列移動到同步隊列如下圖所示:

Java并發之Condition案例詳解

被喚醒的線程將從await方法中的while循環中退出。隨后加入到同步狀態的競爭當中去。成功獲取到競爭的線程則會返回到await方法之前的狀態。

 

四、總結

調用await方法后,將當前線程加入Condition等待隊列中。當前線程釋放鎖。否則別的線程就無法拿到鎖而發生死鎖。自旋(while)掛起,不斷檢測節點是否在同步隊列中了,如果是則嘗試獲取鎖,否則掛起。當線程被signal方法喚醒,被喚醒的線程將從await()方法中的while循環中退出來,然后調用acquireQueued()方法競爭同步狀態。

 

五、利用Condition實現生產者消費者模式

import java.util.LinkedList;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class BoundedQueue {

  private LinkedList<Object> buffer;    //生產者容器
  private int maxSize ;           //容器最大值是多少
  private Lock lock;
  private Condition fullCondition;
  private Condition notFullCondition;
  BoundedQueue(int maxSize){
      this.maxSize = maxSize;
      buffer = new LinkedList<Object>();
      lock = new ReentrantLock();
      fullCondition = lock.newCondition();
      notFullCondition = lock.newCondition();
  }

  /**
   * 生產者
   * @param obj
   * @throws InterruptedException
   */
  public void put(Object obj) throws InterruptedException {
      lock.lock();    //獲取鎖
      try {
          while (maxSize == buffer.size()){
              notFullCondition.await();       //滿了,添加的線程進入等待狀態
          }
          buffer.add(obj);
          fullCondition.signal(); //通知
      } finally {
          lock.unlock();
      }
  }

  /**
   * 消費者
   * @return
   * @throws InterruptedException
   */
  public Object get() throws InterruptedException {
      Object obj;
      lock.lock();
      try {
          while (buffer.size() == 0){ //隊列中沒有數據了 線程進入等待狀態
              fullCondition.await();
          }
          obj = buffer.poll();
          notFullCondition.signal(); //通知
      } finally {
          lock.unlock();
      }
      return obj;
  }

}

到此這篇關于Java并發之Condition案例詳解的文章就介紹到這了,更多相關Java并發之Condition案例內容請搜索服務器之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持服務器之家!

原文鏈接:https://www.cnblogs.com/gemine/p/9039012.html

延伸 · 閱讀

精彩推薦
  • Java教程20個非常實用的Java程序代碼片段

    20個非常實用的Java程序代碼片段

    這篇文章主要為大家分享了20個非常實用的Java程序片段,對java開發項目有所幫助,感興趣的小伙伴們可以參考一下 ...

    lijiao5352020-04-06
  • Java教程Java BufferWriter寫文件寫不進去或缺失數據的解決

    Java BufferWriter寫文件寫不進去或缺失數據的解決

    這篇文章主要介紹了Java BufferWriter寫文件寫不進去或缺失數據的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望...

    spcoder14552021-10-18
  • Java教程Java8中Stream使用的一個注意事項

    Java8中Stream使用的一個注意事項

    最近在工作中發現了對于集合操作轉換的神器,java8新特性 stream,但在使用中遇到了一個非常重要的注意點,所以這篇文章主要給大家介紹了關于Java8中S...

    阿杜7482021-02-04
  • Java教程Java使用SAX解析xml的示例

    Java使用SAX解析xml的示例

    這篇文章主要介紹了Java使用SAX解析xml的示例,幫助大家更好的理解和學習使用Java,感興趣的朋友可以了解下...

    大行者10067412021-08-30
  • Java教程小米推送Java代碼

    小米推送Java代碼

    今天小編就為大家分享一篇關于小米推送Java代碼,小編覺得內容挺不錯的,現在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧...

    富貴穩中求8032021-07-12
  • Java教程xml與Java對象的轉換詳解

    xml與Java對象的轉換詳解

    這篇文章主要介紹了xml與Java對象的轉換詳解的相關資料,需要的朋友可以參考下...

    Java教程網2942020-09-17
  • Java教程升級IDEA后Lombok不能使用的解決方法

    升級IDEA后Lombok不能使用的解決方法

    最近看到提示IDEA提示升級,尋思已經有好久沒有升過級了。升級完畢重啟之后,突然發現好多錯誤,本文就來介紹一下如何解決,感興趣的可以了解一下...

    程序猿DD9332021-10-08
  • Java教程Java實現搶紅包功能

    Java實現搶紅包功能

    這篇文章主要為大家詳細介紹了Java實現搶紅包功能,采用多線程模擬多人同時搶紅包,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙...

    littleschemer13532021-05-16
主站蜘蛛池模板: 国产精品嫩草影院在线看 | 24adc年龄18岁欢迎大驾光临 | 欧美伦乱 | 久久视频这里只精品99热在线观看 | 2021最新国产成人精品免费 | 国产麻豆剧果冻传媒观看免费视频 | 男人天堂影院 | 精品无码人妻一区二区免费AV | 我的漂亮朋友在线观看全集免费 | 羞羞一区二区三区四区片 | 香蕉国产人午夜视频在线观看 | 成年女人毛片免费观看97 | 小柔的性放荡羞辱日记动漫 | 久久伊人电影 | 成熟女人50岁一级毛片不卡 | bl放荡受np双性 | 日本精品欧洲www | 精品在线一区 | 国产-第1页-草草影院 | 亚洲 欧美 日本 国产 高清 | 脱jk裙的美女露小内内无遮挡 | 成人资源在线观看 | 四虎1515hh.com| 免费国产成人高清视频网站 | 2021国产麻豆剧传媒剧情动漫 | 校园春色偷拍自拍 | 日韩手机在线观看 | 国产精品久久久久久网站 | 精品久久成人 | 97精品久久天干天天蜜 | 国产精品99久久免费观看 | 成年性香蕉漫画在线观看 | 欧美伊人久久久久久久久影院 | 精品一产品大全 | 精品国产91久久久久久久 | 国产成人精品视频午夜 | 国内精品麻豆 | 污黄漫| 国产精品久久久久久久久 | 免费毛片 | 国产成人综合手机在线播放 |