1. 程式人生 > >圖靈學院:Java高併發之BlockingQueue

圖靈學院:Java高併發之BlockingQueue

1:BlockingQueue繼承關係

java.util.concurrent 包裡的 BlockingQueue是一個介面, 繼承Queue介面,Queue介面繼承 Collection

BlockingQueue----->Queue-->Collection

 圖:

佇列的特點是:先進先出(FIFO)

2:BlockingQueue的方法

BlockingQueue 具有 4 組不同的方法用於插入、移除以及對佇列中的元素進行檢查。如果請求的操作不能得到立即執行的話,每個方法的表現也不同。這些方法如下:

丟擲異常特殊值阻塞超時
插入add(e)offer(e)put(e)offer(e, time, unit)
移除remove()poll()take()poll(time, unit)
檢查element()peek()不可用不可用

四組不同的行為方式解釋:

1(異常)

如果試圖的操作無法立即執行,拋一個異常。

2(特定值) 

如果試圖的操作無法立即執行,返回一個特定的值(常常是 true / false)。

3(阻塞) 

如果試圖的操作無法立即執行,該方法呼叫將會發生阻塞,直到能夠執行。

4(超時) 

如果試圖的操作無法立即執行,該方法呼叫將會發生阻塞,直到能夠執行,但等待時間不會超過給定值。返回一個特定值以告知該操作是否成功(典型的是 true / false)。

不能向BlockingQueue插入一個空物件,否則會丟擲NullPointerException,相應的實現類校驗程式碼

private static void checkNotNull(Object v) {
        if (v == null)
            throw new NullPointerException();
    }

BlockingQueue :不接受 null 元素。試圖 addput 或 offer 一個 null 元素時,某些實現會丟擲 NullPointerExceptionnull 被用作指示 poll 操作失敗的警戒值。

BlockingQueue: 可以是限定容量的。它在任意給定時間都可以有一個 remainingCapacity,超出此容量,便無法無阻塞地 

put 附加元素。沒有任何內部容量約束的 BlockingQueue 總是報告Integer.MAX_VALUE 的剩餘容量。

BlockingQueue :實現主要用於生產者-使用者佇列,但它另外還支援 Collection 介面。因此,舉例來說,使用 remove(x) 從佇列中移除任意一個元素是有可能的。然而,這種操作通常 會有效執行,只能有計劃地偶爾使用,比如在取消排隊資訊時。

BlockingQueue :實現是執行緒安全的。所有排隊方法都可以使用內部鎖或其他形式的併發控制來自動達到它們的目的。然而,大量的 Collection 操作(addAllcontainsAllretainAll 和removeAll沒有 必要自動執行,除非在實現中特別說明。因此,舉例來說,在只添加了 c 中的一些元素後,addAll(c) 有可能失敗(丟擲一個異常)。

BlockingQueue 實質上 支援使用任何一種“close”或“shutdown”操作來指示不再新增任何項。這種功能的需求和使用有依賴於實現的傾向。例如,一種常用的策略是:對於生產者,插入特殊的 end-of-stream 或 poison 物件,並根據使用者獲取這些物件的時間來對它們進行解釋。

3:BlockingQueue實現類和繼承介面

   ArrayBlockingQueue

    DelayQueue

    LinkedBlockingQueue

    PriorityBlockingQueue

    SynchronousQueue

繼承他的介面:

public interface BlockingDeque extends BlockingQueue, Deque 1.6新增

   public interface TransferQueue extends BlockingQueue           1.7新增

4:BlockingQueue用法

BlockingQueue 通常用於一個執行緒生產物件,而另外一個執行緒消費這些物件的場景。下圖是對這個原理的闡述:

 一個執行緒往裡邊放,另外一個執行緒從裡邊取的一個 BlockingQueue。

 一個執行緒將會持續生產新物件並將其插入到佇列之中,直到佇列達到它所能容納的臨界點。也就是說,它是有限的。如果該阻塞佇列到達了其臨界點,負責生產的執行緒將會在往裡邊插入新物件時發生阻塞。它會一直處於阻塞之中,直到負責消費的執行緒從佇列中拿走一個物件。

 負責消費的執行緒將會一直從該阻塞佇列中拿出物件。如果消費執行緒嘗試去從一個空的佇列中提取物件的話,這個消費執行緒將會處於阻塞之中,直到一個生產執行緒把一個物件丟進佇列。

5:BlockingQueue Example

public class BlockingQueueExample {

    public static void main(String[] args) throws Exception {

        BlockingQueue queue = new ArrayBlockingQueue(1024);

        Producer producer = new Producer(queue);
        Consumer consumer = new Consumer(queue);

        new Thread(producer).start();
        new Thread(consumer).start();

        Thread.sleep(4000);
    }
}
public class Producer implements Runnable{

    protected BlockingQueue queue = null;

    public Producer(BlockingQueue queue) {
        this.queue = queue;
    }

    public void run() {
        try {
            queue.put("1");
            Thread.sleep(1000);
            queue.put("2");
            Thread.sleep(1000);
            queue.put("3");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
public class Consumer implements Runnable{

    protected BlockingQueue queue = null;

    public Consumer(BlockingQueue queue) {
        this.queue = queue;
    }

    public void run() {
        try {
            System.out.println(queue.take());
            System.out.println(queue.take());
            System.out.println(queue.take());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

6:BlockingQueue實現類詳解

1  陣列阻塞佇列 ArrayBlockingQueue

一個由陣列支援的有界阻塞佇列。此佇列按 FIFO(先進先出)原則對元素進行排序。佇列的頭部 是在佇列中存在時間最長的元素。佇列的尾部 是在佇列中存在時間最短的元素。新元素插入到佇列的尾部,佇列獲取操作則是從佇列頭部開始獲得元素。

這是一個典型的“有界快取區”,固定大小的陣列在其中保持生產者插入的元素和使用者提取的元素。一旦建立了這樣的快取區,就不能再增加其容量。試圖向已滿佇列中放入元素會導致操作受阻塞;試圖從空佇列中提取元素將導致類似阻塞。

此類支援對等待的生產者執行緒和使用者執行緒進行排序的可選公平策略。預設情況下,不保證是這種排序。然而,通過將公平性 (fairness) 設定為 true 而構造的佇列允許按照 FIFO 順序訪問執行緒。公平性通常會降低吞吐量,但也減少了可變性和避免了“不平衡性”

BlockingQueue queue = new ArrayBlockingQueue(1024);
queue.put("1");String string = queue.take();

2:延遲佇列DelayQueue

Delayed 元素的一個無界阻塞佇列,只有在延遲期滿時才能從中提取元素。該佇列的頭部 是延遲期滿後儲存時間最長的 Delayed 元素。如果延遲都還沒有期滿,則佇列沒有頭部,並且 poll 將返回 null。當一個元素的 getDelay(TimeUnit.NANOSECONDS) 方法返回一個小於等於 0 的值時,將發生到期。即使無法使用 take 或 poll 移除未到期的元素,也不會將這些元素作為正常元素對待。例如,size 方法同時返回到期和未到期元素的計數。此佇列不允許使用 null 元素

3. 鏈阻塞佇列 LinkedBlockingQueue

LinkedBlockingQueue 類實現了 BlockingQueue 介面。

LinkedBlockingQueue 內部以一個鏈式結構(連結節點)對其元素進行儲存。如果需要的話,這一鏈式結構可以選擇一個上限。如果沒有定義上限,將使用 Integer.MAX_VALUE 作為上限。

LinkedBlockingQueue 內部以 FIFO(先進先出)的順序對元素進行儲存。佇列中的頭元素在所有元素之中是放入時間最久的那個,而尾元素則是最短的那個。

BlockingQueue unbounded = new LinkedBlockingQueue();
BlockingQueue bounded   = new LinkedBlockingQueue(1024);bounded.put("Value");
String value = bounded.take();
System.out.println(value);
System.out.println(unbounded.remainingCapacity()==Integer.MAX_VALUE);//true

4. 具有優先順序的阻塞佇列 PriorityBlockingQueue

PriorityBlockingQueue 類實現了 BlockingQueue 介面。

一個無界阻塞佇列,它使用與類 PriorityQueue 相同的順序規則,並且提供了阻塞獲取操作。雖然此佇列邏輯上是無界的,但是資源被耗盡時試圖執行 add 操作也將失敗(導致OutOfMemoryError)。此類不允許使用 null 元素。依賴自然順序的優先順序佇列也不允許插入不可比較的物件(這樣做會導致丟擲 ClassCastException)。

此類及其迭代器可以實現 Collection 和 Iterator 介面的所有可選 方法。iterator() 方法中提供的迭代器並不 保證以特定的順序遍歷 PriorityBlockingQueue 的元素。如果需要有序地進行遍歷,則應考慮使用 Arrays.sort(pq.toArray())。此外,可以使用方法 drainTo 按優先順序順序移除 全部或部分元素,並將它們放在另一個 collection 中。

在此類上進行的操作不保證具有同等優先順序的元素的順序。如果需要實施某一排序,那麼可以定義自定義類或者比較器,比較器可使用修改鍵斷開主優先順序值之間的聯絡。例如,以下是應用先進先出 (first-in-first-out) 規則斷開可比較元素之間聯絡的一個類。要使用該類,則需要插入一個新的 FIFOEntry(anEntry) 來替換普通的條目物件。


5. 同步佇列 SynchronousQueue

SynchronousQueue 類實現了 BlockingQueue 介面。

SynchronousQueue 是一個特殊的佇列,它的內部同時只能夠容納單個元素。如果該佇列已有一元素的話,試圖向佇列中插入一個新元素的執行緒將會阻塞,直到另一個執行緒將該元素從佇列中抽走。同樣,如果該佇列為空,試圖向佇列中抽取一個元素的執行緒將會阻塞,直到另一個執行緒向佇列中插入了一條新的元素。

據此,把這個類稱作一個佇列顯然是誇大其詞了。它更多像是一個匯合點。


6. 阻塞雙端佇列 BlockingDeque

java.util.concurrent 包裡的 BlockingDeque 介面表示一個執行緒安放入和提取例項的雙端佇列。本小節我將給你演示如何使用 BlockingDeque。

BlockingDeque 類是一個雙端佇列,在不能夠插入元素時,它將阻塞住試圖插入元素的執行緒;在不能夠抽取元素時,它將阻塞住試圖抽取的執行緒。

deque(雙端佇列) 是 "Double Ended Queue" 的縮寫。因此,雙端佇列是一個你可以從任意一端插入或者抽取元素的佇列。

7. 鏈阻塞雙端佇列 LinkedBlockingDeque

 一個基於已連結節點的、任選範圍的阻塞雙端佇列。

 可選的容量範圍構造方法引數是一種防止過度膨脹的方式。如果未指定容量,那麼容量將等於 Integer.MAX_VALUE。只要插入元素不會使雙端佇列超出容量,每次插入後都將動態地建立連結節點。

 大多數操作都以固定時間執行(不計阻塞消耗的時間)。異常包括 remove、removeFirstOccurrence、removeLastOccurrence、contains、iterator.remove() 以及批量操作,它們均以線性時間執行。

相關推薦

學院Java併發BlockingQueue

1:BlockingQueue繼承關係 java.util.concurrent 包裡的 BlockingQueue是一個介面, 繼承Queue介面,Queue介面繼承 CollectionBlockingQueue----->Queue-->Collection

學院【微服務架構】SpringCloudRibbon(四)

SpringCloud Ribbon​    一:Ribbon是什麼? Ribbon是Netflix釋出的開源專案,主要功能是提供客戶端的軟體負載均衡演算法,將Netflix的中間層服務連線在一起。Ribbon客戶端元件提供一系列完善的配置項如連線超時,重試等。簡單的說,就是

學院【微服務架構】SpringCloudEureka(服務註冊和服務發現基礎篇)(二)

一:Eureka簡介   Eureka是Spring Cloud Netflix的一個子模組,也是核心模組之一。用於雲端服務發現,一個基於REST的服務,用於定位服務,以實現雲端中間層服務發現和故障轉移。服務註冊與發現對於微服務系統來說非常重要。有了服務發現與註冊,你就不需要

java併發hook例項(防止重複啟動程式)

package com.test.testThread; import java.io.File; import java.io.IOException; import java.nio.file.Path; import java.nio.file.Paths; import java.util

**標題Java併發問題**

標題:Java高併發問題 在Java中出現高併發的原因一般有: 前端:web執行緒連線數不足 後臺:伺服器網路頻寬不足 資料庫:資料庫連線查詢速度跟不上 針對這三方面的問題的優化方案: 前端:實現負載均衡,配置前置代理伺服器,如Apache,NGINX等。 後臺

JAVA併發鎖的優化及原始碼解讀

在現代系統多核的時代,使用多執行緒明顯了地提高了系統的效能,但是在高併發的環境中,激烈的鎖競爭對系統的效能帶來的嚴重的影響,因為對於多執行緒來說,它不僅要維持每一個執行緒本身的元資料,還要負責執行緒之間的切換,不斷的掛起,喚醒,浪費了大量的時間,因此,有必要探討

Java併發同步非同步

1、概念理解: 2、同步的解決方案: 1).基於程式碼 synchronized 關鍵字  修飾普通方法:作用於當前例項加鎖,進入同步程式碼前要獲得當前例項的鎖。  修飾靜態方法:作用於當前類物件加鎖,進入同步程式碼前要獲得當前類物件的鎖。     修飾程式碼塊:指定加鎖物

學院Java架構師要掌握哪些技能?你所不知的十五條秘密

ODB 知識 java 對象 java架構師 ESS 多線程同步 工具 創建 苦苦工作累積經驗,卻還是奮戰在一線的“菜鳥”碼農,不知道成為Java架構師要掌握哪些技能?熬不完的夜,想要升職加薪?看了很多書還是寫不出最高效的代碼,花了很多錢學習網課還是不見成效?遇到我圖靈學院

學院15】極致優化-性能網絡編程BIO與NIO區別

ice redis let bject 模型 vao 傳輸 示例 ava 一、Java IO概念 1. 一個http請求節點   數據傳輸 1)網絡傳輸   TCP、UDP 2)通信模型   BIO、NIO、AIO   數據處理 3)應用協議   HTTP、RMI、WEB

java併發程式設計總結三JDK併發包ReentrantLock重入鎖

為了更好的支援併發程式,jdk內部提供了大量實用的API和框架,重入鎖就是一種對同步的擴充套件 ReentrantLock起源 在1.5的時候,synchronized關鍵的效能不是很好,這也是concurrent併發包出現的一種潛在原因,而新出

怎麽成為java級架構師?學院總結的java架構師學習路線

分布式系統 對象池 速度 體驗 本質 你會 決定 層次 java工程師 怎麽成為一個java高級架構師呢?相信這是很多java從業者,又或者說是coder/碼農們比較感興趣的問題,要回答這個問題,首先需要明白的是java架構師是什麽?簡單點說,架構師的主要任務不是從事具體的

SpringBoot實現Java併發秒殺系統併發優化

秒殺系統架構的設計和優化分析,以我一個小菜雞,目前是說不出來的o(╥﹏╥)o。 因此呢,我這裡僅從本專案已經實現的優化來介紹一下: 本專案中做到了以下優化: 秒殺介面採用md5加密方式防刷。 訂單表使用聯合主鍵方式,限制一個使用者只能購買該商品一次。 配合Spring事務

Java併發程式設計synchronized關鍵字(二)

上一篇文章講了synchronized的部分關鍵要點,詳見:Java高併發程式設計之synchronized關鍵字(一) 本篇文章接著講synchronized的其他關鍵點。 在使用synchronized關鍵字的時候,不要以字串常量作為鎖定物件。看下面的例子: public class

Java併發程式設計synchronized關鍵字(一)

首先看一段簡單的程式碼: public class T001 { private int count = 0; private Object o = new Object(); public void m() { //任何執行緒要執行下面這段程式碼

Java併發解決方案非同步處理

(() -> { // 請求1 CompletableFuture<List<Integer>> completionStage1 = CompletableFuture.supplyAsync(() -> { //

Java 併發程式設計詳解多執行緒與架構設計

內容簡介 本書主要包含四個部分: 部分主要闡述 Thread 的基礎知識,詳細介紹執行緒的 API 使用、執行緒安全、執行緒間資料通訊,以及如何保護共享資源等內容,它是深入學習多執行緒內容的基礎。 第二部分引入了 ClassLoader,這是因為 ClassLoader 與執行緒不無關係

頂級架構師學習——第二階段實戰Java併發程式設計

1、什麼是並行? 並行處理(ParallelProcessing)是計算機系統中能同時執行兩個或更多個處理機的一種計算方法。處理機可同時工作於同一程式的不同方面。並行處理的主要目的是節省大型和複雜問題的解決時間。 2、為什麼需要並行? 平行計算只有在  影象處理  和 

實戰java併發程式設計CountDownLatch原始碼分析

首先看第一個! CountDownLatch 使用場景 CountDownLatch類是常見的併發同步控制類,適用於某一執行緒的執行在其他多個執行緒執行完成之後,比如火箭發射前需要各項指標檢查,只有當各項指標檢查完才能發射,再比如解析多個excel文件,只有當

SpringBoot實現Java併發秒殺系統Web層開發(三)

接著上一篇文章:SpringBoot實現Java高併發之Service層開發,今天我們開始講SpringBoot實現Java高併發秒殺系統之Web層開發。 Web層即Controller層,當然我們所說的都是在基於Spring框架的系統上而言的,傳統的SSH專案

SpringBoot實現Java併發秒殺系統Service層開發(二)

繼上一篇文章:SpringBoot實現Java高併發秒殺系統之DAO層開發 我們建立了SpringBoot專案並熟悉了秒殺系統的表設計,下面我們將講解一下秒殺系統的核心部分:Service業務層的開發。 Service層又稱為業務層,在Spring階段主要是由@