最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java多線程Queue、BlockingQueue和使用BlockingQueue實現(xiàn)生產消費者模型方法解析

 更新時間:2017年11月14日 15:59:02   投稿:mengwei  
這篇文章主要介紹了Java多線程Queue、BlockingQueue和使用BlockingQueue實現(xiàn)生產消費者模型方法解析,涉及queue,BlockingQueue等有關內容,具有一定參考價值,需要的朋友可以參考。

Queue是什么

隊列,是一種數(shù)據(jù)結構。除了優(yōu)先級隊列和LIFO隊列外,隊列都是以FIFO(先進先出)的方式對各個元素進行排序的。無論使用哪種排序方式,隊列的頭都是調用remove()或poll()移除元素的。在FIFO隊列中,所有新元素都插入隊列的末尾。

Queue中的方法

Queue中的方法不難理解,6個,每2對是一個也就是總共3對??匆幌翵DKAPI就知道了:

注意一點就好,Queue通常不允許插入Null,盡管某些實現(xiàn)(比如LinkedList)是允許的,但是也不建議。

BlockingQueue

1、BlockingQueue概述

BlockingQueue也是java.util.concurrent下的主要用來控制線程同步的工具。

BlockingQueue有四個具體的實現(xiàn)類,根據(jù)不同需求,選擇不同的實現(xiàn)類

1、ArrayBlockingQueue:一個由數(shù)組支持的有界阻塞隊列,規(guī)定大小的BlockingQueue,其構造函數(shù)必須帶一個int參數(shù)來指明其大小.其所含的對象是以FIFO(先入先出)順序排序的。

2、LinkedBlockingQueue:大小不定的BlockingQueue,若其構造函數(shù)帶一個規(guī)定大小的參數(shù),生成的BlockingQueue有大小限制,若不帶大小參數(shù),所生成的BlockingQueue的大小由Integer.MAX_VALUE來決定.其所含的對象是以FIFO(先入先出)順序排序的。

3、PriorityBlockingQueue:類似于LinkedBlockQueue,但其所含對象的排序不是FIFO,而是依據(jù)對象的自然排序順序或者是構造函數(shù)的Comparator決定的順序。

4、SynchronousQueue:特殊的BlockingQueue,對其的操作必須是放和取交替完成的。

LinkedBlockingQueue可以指定容量,也可以不指定,不指定的話,默認最大是Integer.MAX_VALUE,其中主要用到put和take方法,put方法在隊列滿的時候會阻塞直到有隊列成員被消費,take方法在隊列空的時候會阻塞,直到有隊列成員被放進來。

講BlockingQueue,因為BlockingQueue是Queue中的一個重點,并且通過BlockingQueue我們再次加深對于生產者/消費者模型的理解。其他的Queue都不難,通過查看JDKAPI和簡單閱讀源碼完全可以理解他們的作用。

BlockingQueue,顧名思義,阻塞隊列。BlockingQueue是在java.util.concurrent下的,因此不難理解,BlockingQueue是為了解決多線程中數(shù)據(jù)高效安全傳輸而提出的。

多線程中,很多場景都可以使用隊列實現(xiàn),比如經典的生產者/消費者模型,通過隊列可以便利地實現(xiàn)兩者之間數(shù)據(jù)的共享,定義一個生產者線程,定義一個消費者線程,通過隊列共享數(shù)據(jù)就可以了。

當然現(xiàn)實不可能都是理想的,比如消費者消費速度比生產者生產的速度要快,那么消費者消費到一定程度上的時候,必須要暫停等待一下了(使消費者線程處于WAITING狀態(tài))。BlockingQueue的提出,就是為了解決這個問題的,他不用程序員去控制這些細節(jié),同時還要兼顧效率和線程安全。

阻塞隊列所謂的"阻塞",指的是某些情況下線程會掛起(即阻塞),一旦條件滿足,被掛起的線程又會自動喚醒。使用BlockingQueue,不需要關心什么時候需要阻塞線程,什么時候需要喚醒線程,這些內容BlockingQueue都已經做好了

2、BlockingQueue中的方法

BlockingQueue既然是Queue的子接口,必然有Queue中的方法,上面已經列了。看一下BlockingQueue中特有的方法:

(1)voidput(Ee)throwsInterruptedException

把e添加進BlockingQueue中,如果BlockingQueue中沒有空間,則調用線程被阻塞,進入等待狀態(tài),直到BlockingQueue中有空間再繼續(xù)

(2)voidtake()throwsInterruptedException

取走BlockingQueue里面排在首位的對象,如果BlockingQueue為空,則調用線程被阻塞,進入等待狀態(tài),直到BlockingQueue有新的數(shù)據(jù)被加入

(3)intdrainTo(Collection<?superE>c,intmaxElements)

一次性取走BlockingQueue中的數(shù)據(jù)到c中,可以指定取的個數(shù)。通過該方法可以提升獲取數(shù)據(jù)效率,不需要多次分批加鎖或釋放鎖

3、ArrayBlockingQueue

基于數(shù)組的阻塞隊列,必須指定隊列大小。比較簡單。ArrayBlockingQueue中只有一個ReentrantLock對象,這意味著生產者和消費者無法并行運行(見下面的代碼)。另外,創(chuàng)建ArrayBlockingQueue時,可以指定ReentrantLock是否為公平鎖,默認采用非公平鎖。

/** Main lock guarding all access */
private final ReentrantLock lock;
/** Condition for waiting takes */
private final Condition notEmpty;
/** Condition for waiting puts */
private final Condition notFull;

4、LinkedBlockingQueue

基于鏈表的阻塞隊列,和ArrayBlockingQueue差不多。不過LinkedBlockingQueue如果不指定隊列容量大小,會默認一個類似無限大小的容量,之所以說是類似是因為這個無限大小是Integer.MAX_VALUE,這么說就好理解ArrayBlockingQueue為什么必須要制定大小了,如果ArrayBlockingQueue不指定大小的話就用Integer.MAX_VALUE,那將造成大量的空間浪費,但是基于鏈表實現(xiàn)就不一樣的,一個一個節(jié)點連起來而已。另外,LinkedBlockingQueue生產者和消費者都有自己的鎖(見下面的代碼),這意味著生產者和消費者可以"同時"運行。

/** Lock held by take, poll, etc */
private final ReentrantLock takeLock = new ReentrantLock();
/** Wait queue for waiting takes */
private final Condition notEmpty = takeLock.newCondition();
/** Lock held by put, offer, etc */
private final ReentrantLock putLock = new ReentrantLock();
/** Wait queue for waiting puts */
private final Condition notFull = putLock.newCondition();

5、SynchronousQueue

比較特殊,一種沒有緩沖的等待隊列。什么叫做沒有緩沖區(qū),ArrayBlocking中有:

/** The queued items */
private final E[] items;

數(shù)組用以存儲隊列。LinkedBlockingQueue中有:

/**
 * Linked list node class
 */
static class Node<E> {
  /** The item, volatile to ensure barrier separating write and read */
  volatile E item;
  Node<E> next;
  Node(E x) { item = x; }
}

將隊列以鏈表形式連接。

生產者/消費者操作數(shù)據(jù)實際上都是通過這兩個"中介"來操作數(shù)據(jù)的,但是SynchronousQueue則是生產者直接把數(shù)據(jù)給消費者(消費者直接從生產者這里拿數(shù)據(jù)),好像又回到了沒有生產者/消費者模型的老辦法了。換句話說,每一個插入操作必須等待一個線程對應的移除操作。SynchronousQueue又有兩種模式:

1、公平模式

采用公平鎖,并配合一個FIFO隊列(Queue)來管理多余的生產者和消費者

2、非公平模式

采用非公平鎖,并配合一個LIFO棧(Stack)來管理多余的生產者和消費者,這也是SynchronousQueue默認的模式

利用BlockingQueue實現(xiàn)生產者消費者模型

上一篇我們寫的生產者消費者模型有局限,局限體現(xiàn)在:

緩沖區(qū)內只能存放一個數(shù)據(jù),實際生產者/消費者模型中的緩沖區(qū)內可以存放大量生產者生產出來的數(shù)據(jù)
生產者和消費者處理數(shù)據(jù)的速度幾乎一樣
OK,我們就用BlockingQueue來簡單寫一個例子,并且讓生產者、消費者處理數(shù)據(jù)速度不同。子類選擇的是ArrayBlockingQueue,大小定為10:

public static void main(String[] args)
{
  final BlockingQueue<String> bq = new ArrayBlockingQueue<String>(10);
  Runnable producerRunnable = new Runnable()
  {
    int i = 0;
    public void run()
    {
      while (true)
      {
        try
        {
          System.out.println("我生產了一個" + i++);
          bq.put(i + "");
          Thread.sleep(1000);
        } 
        catch (InterruptedException e)
        {
          e.printStackTrace();
        }
      }
    }
  };
  Runnable customerRunnable = new Runnable()
  {
    public void run()
    {
      while (true)
      {
        try
        {
          System.out.println("我消費了一個" + bq.take());
          Thread.sleep(3000);
        } 
        catch (InterruptedException e)
        {
          e.printStackTrace();
        }
      }
    }
  };
  Thread producerThread = new Thread(producerRunnable);
  Thread customerThread = new Thread(customerRunnable);
  producerThread.start();
  customerThread.start();
}

代碼的做法是讓生產者生產速度快于消費者消費速度的,看一下運行結果:

我生產了一個0
我消費了一個1
我生產了一個1
我生產了一個2
我消費了一個2
我生產了一個3
我生產了一個4
我生產了一個5
我消費了一個3
我生產了一個6
我生產了一個7
我生產了一個8
我消費了一個4
我生產了一個9
我生產了一個10
我生產了一個11
我消費了一個5
我生產了一個12
我生產了一個13
我生產了一個14
我消費了一個6
我生產了一個15
我生產了一個16
我消費了一個7
我生產了一個17
我消費了一個8
我生產了一個18

分兩部分來看輸出結果:

1、第1行~第23行。這塊BlockingQueue未滿,所以生產者隨便生產,消費者隨便消費,基本上都是生產3個消費1個,消費者消費速度慢

2、第24行~第27行,從前面我們可以看出,生產到16,消費到6,說明到了ArrayBlockingQueue的極限10了,這時候沒辦法,生產者生產一個ArrayBlockingQueue就滿了,所以不能繼續(xù)生產了,只有等到消費者消費完才可以繼續(xù)生產。所以之后的打印內容一定是一個生產者、一個消費者

這就是前面一章開頭說的"通過平衡生產者和消費者的處理能力來提高整體處理數(shù)據(jù)的速度",這給例子應該體現(xiàn)得很明顯。另外,也不要擔心非單一生產者/消費者場景下的系統(tǒng)假死問題,緩沖區(qū)空、緩沖區(qū)滿的場景BlockingQueue都是定義了不同的Condition,所以不會喚醒自己的同類。

總結

以上就是本文關于Java多線程Queue、BlockingQueue和使用BlockingQueue實現(xiàn)生產消費者模型方法解析的全部內容,希望對大家有所幫助。感興趣的朋友可以參閱本站:

淺談Java多線程的優(yōu)點及代碼示例

淺談Java多線程處理中Future的妙用(附源碼)

Java利用future及時獲取多線程運行結果

如有不足之處,歡迎留言指出。

相關文章

  • 淺談MyBatis 事務管理

    淺談MyBatis 事務管理

    這篇文章主要介紹了淺談MyBatis 事務管理,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-10-10
  • SpringBoot中的異常處理與參數(shù)校驗的方法實現(xiàn)

    SpringBoot中的異常處理與參數(shù)校驗的方法實現(xiàn)

    這篇文章主要介紹了SpringBoot中的異常處理與參數(shù)校驗的方法實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-04-04
  • MybatisPlus如何調用count函數(shù)

    MybatisPlus如何調用count函數(shù)

    這篇文章主要介紹了MybatisPlus如何調用count函數(shù)問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-08-08
  • SpringBoot實現(xiàn)分庫分表

    SpringBoot實現(xiàn)分庫分表

    這篇文章主要介紹了SpringBoot實現(xiàn)分庫分表,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-02-02
  • spring mvc中@PathVariable / 帶斜杠方式獲取

    spring mvc中@PathVariable / 帶斜杠方式獲取

    這篇文章主要介紹了spring mvc中@PathVariable / 帶斜杠方式獲取,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-08-08
  • java.lang.UnsupportedOperationException的問題解決

    java.lang.UnsupportedOperationException的問題解決

    本文主要介紹了java.lang.UnsupportedOperationException的問題解決,該錯誤表示調用的方法不被支持或不可用,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2024-07-07
  • GSON實現(xiàn)Java對象的JSON序列化與反序列化的實例教程

    GSON實現(xiàn)Java對象的JSON序列化與反序列化的實例教程

    GSON是Google開發(fā)并開源的一個Java的JSON轉換庫,這里我們將來講解GSON實現(xiàn)Java對象的JSON序列化與反序列化的實例教程,需要的朋友可以參考下
    2016-06-06
  • Java設計模式之命令模式CommandPattern詳解

    Java設計模式之命令模式CommandPattern詳解

    這篇文章主要介紹了Java設計模式之命令模式CommandPattern詳解,命令模式是把一個請求封裝為一個對象,從而使你可用不同的請求對客戶進行參數(shù)化;對請求排隊或記錄請求日志,以及支持可撤銷的操作,需要的朋友可以參考下
    2023-10-10
  • Redis監(jiān)聽過期的key實現(xiàn)流程詳解

    Redis監(jiān)聽過期的key實現(xiàn)流程詳解

    本文主要介紹了Redis監(jiān)聽key的過期時間,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-02-02
  • Java利用自定義注解、反射實現(xiàn)簡單BaseDao實例

    Java利用自定義注解、反射實現(xiàn)簡單BaseDao實例

    下面小編就為大家?guī)硪黄狫ava利用自定義注解、反射實現(xiàn)簡單BaseDao實例。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-08-08

最新評論

永顺县| 台北县| 凯里市| 久治县| 阳谷县| 昂仁县| 洛浦县| 永吉县| 太湖县| 同江市| 宝清县| 深泽县| 龙江县| 阳原县| 宾阳县| 晋江市| 延安市| 来凤县| 文安县| 仪陇县| 和田市| 尚志市| 洛川县| 观塘区| 扎鲁特旗| 高邑县| 西丰县| 凤凰县| 电白县| 江华| 扎兰屯市| 自治县| 蒙城县| 贵溪市| 鹿邑县| 濮阳县| 湖南省| 土默特右旗| 锡林郭勒盟| 阿拉尔市| 灵丘县|