Java併發工具包使用指南(全)
1. java.util.concurrent - Java 併發工具包
Java 5 添加了一個新的包到 Java 平臺,java.util.concurrent 包。這個包包含有一系列能夠讓 Java 的併發程式設計變得更加簡單輕鬆的類。在這個包被新增以前,你需要自己去動手實現自己的相關工具類。本文我將帶你一一認識 java.util.concurrent 包裡的這些類,然後你可以嘗試著如何在專案中使用它們。本文中我將使用 Java 6 版本,我不確定這和 Java 5 版本里的是否有一些差異。
我不會去解釋關於 Java 併發的核心問題 - 其背後的原理,也就是說,如果你對那些東西感興趣,參考《
半成品
本文很大程度上還是個 "半成品",所以當你發現一些被漏掉的類或介面時,請耐心等待。在我空閒的時候會把它們加進來的。
2. 阻塞佇列 BlockingQueue
java.util.concurrent 包裡的 BlockingQueue 介面表示一個執行緒安放入和提取例項的佇列。本小節我將給你演示如何使用這個 BlockingQueue。本節不會討論如何在 Java 中實現一個你自己的 BlockingQueue。如果你對那個感興趣,參考《Java 併發指南》
BlockingQueue 用法
BlockingQueue 通常用於一個執行緒生產物件,而另外一個執行緒消費這些物件的場景。下圖是對這個原理的闡述:一個執行緒往裡邊放,另外一個執行緒從裡邊取的一個 BlockingQueue。
一個執行緒將會持續生產新物件並將其插入到佇列之中,直到佇列達到它所能容納的臨界點。也就是說,它是有限的。如果該阻塞佇列到達了其臨界點,負責生產的執行緒將會在往裡邊插入新物件時發生阻塞。它會一直處於阻塞之中,直到負責消費的執行緒從佇列中拿走一個物件。
負責消費的執行緒將會一直從該阻塞佇列中拿出物件。如果消費執行緒嘗試去從一個空的佇列中提取物件的話,這個消費執行緒將會處於阻塞之中,直到一個生產執行緒把一個物件丟進佇列。
BlockingQueue 的方法
BlockingQueue 具有 4 組不同的方法用於插入、移除以及對佇列中的元素進行檢查。如果請求的操作不能得到立即執行的話,每個方法的表現也不同。這些方法如下:拋異常 | 特定值 | 阻塞 | 超時 | |
---|---|---|---|---|
插入 | add(o) | offer(o) | put(o) | offer(o, timeout, timeunit) |
移除 | remove(o) | poll(o) | take(o) | poll(timeout, timeunit) |
檢查 | element(o) | peek(o) |
四組不同的行為方式解釋:
- 拋異常:如果試圖的操作無法立即執行,拋一個異常。
- 特定值:如果試圖的操作無法立即執行,返回一個特定的值(常常是 true / false)。
- 阻塞:如果試圖的操作無法立即執行,該方法呼叫將會發生阻塞,直到能夠執行。
- 超時:如果試圖的操作無法立即執行,該方法呼叫將會發生阻塞,直到能夠執行,但等待時間不會超過給定值。返回一個特定值以告知該操作是否成功(典型的是 true / false)。
可以訪問到 BlockingQueue 中的所有元素,而不僅僅是開始和結束的元素。比如說,你將一個物件放入佇列之中以等待處理,但你的應用想要將其取消掉。那麼你可以呼叫諸如 remove(o) 方法來將佇列之中的特定物件進行移除。但是這麼幹效率並不高(譯者注:基於佇列的資料結構,獲取除開始或結束位置的其他物件的效率不會太高),因此你儘量不要用這一類的方法,除非你確實不得不那麼做。
BlockingQueue 的實現
BlockingQueue 是個介面,你需要使用它的實現之一來使用 BlockingQueue。java.util.concurrent 具有以下 BlockingQueue 介面的實現(Java 6):Java 中使用 BlockingQueue 的例子
這裡是一個 Java 中使用 BlockingQueue 的示例。本示例使用的是 BlockingQueue 介面的 ArrayBlockingQueue 實現。首先,BlockingQueueExample 類分別在兩個獨立的執行緒中啟動了一個 Producer 和 一個 Consumer。Producer 向一個共享的 BlockingQueue 中注入字串,而 Consumer 則會從中把它們拿出來。
[java] view plain copy print?
- publicclass BlockingQueueExample {
- publicstaticvoid 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);
- }
- }
以下是 Producer 類。注意它在每次 put() 呼叫時是如何休眠一秒鐘的。這將導致 Consumer 在等待佇列中物件的時候發生阻塞。
[java] view plain copy print?
- publicclass Producer implements Runnable{
- protected BlockingQueue queue = null;
- public Producer(BlockingQueue queue) {
- this.queue = queue;
- }
- publicvoid run() {
- try {
- queue.put("1");
- Thread.sleep(1000);
- queue.put("2");
- Thread.sleep(1000);
- queue.put("3");
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- }
以下是 Consumer 類。它只是把物件從佇列中抽取出來,然後將它們列印到 System.out。
[java] view plain copy print?
- publicclass Consumer implements Runnable{
- protected BlockingQueue queue = null;
- public Consumer(BlockingQueue queue) {
- this.queue = queue;
- }
- publicvoid run() {
- try {
- System.out.println(queue.take());
- System.out.println(queue.take());
- System.out.println(queue.take());
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- }
3. 陣列阻塞佇列 ArrayBlockingQueue
ArrayBlockingQueue 類實現了 BlockingQueue 介面。ArrayBlockingQueue 是一個有界的阻塞佇列,其內部實現是將物件放到一個數組裡。有界也就意味著,它不能夠儲存無限多數量的元素。它有一個同一時間能夠儲存元素數量的上限。你可以在對其初始化的時候設定這個上限,但之後就無法對這個上限進行修改了(譯者注:因為它是基於陣列實現的,也就具有陣列的特性:一旦初始化,大小就無法修改)。
ArrayBlockingQueue 內部以 FIFO(先進先出)的順序對元素進行儲存。佇列中的頭元素在所有元素之中是放入時間最久的那個,而尾元素則是最短的那個。
以下是在使用 ArrayBlockingQueue 的時候對其初始化的一個示例:
[java] view plain copy print?
- BlockingQueue queue = new ArrayBlockingQueue(1024);
- queue.put("1");
- Object object = queue.take();
以下是使用了 Java 泛型的一個 BlockingQueue 示例。注意其中是如何對 String 元素放入和提取的:
[java] view plain copy print?
- BlockingQueue<String> queue = new ArrayBlockingQueue<String>(1024);
- queue.put("1");
- String string = queue.take();
4. 延遲佇列 DelayQueue
DelayQueue 實現了 BlockingQueue 介面。DelayQueue 對元素進行持有直到一個特定的延遲到期。注入其中的元素必須實現 java.util.concurrent.Delayed 介面,該介面定義:
[java] view plain copy print?
- publicinterface Delayed extends Comparable<Delayed< {
- publiclong getDelay(TimeUnit timeUnit);
- }
DelayQueue 將會在每個元素的 getDelay() 方法返回的值的時間段之後才釋放掉該元素。如果返回的是 0 或者負值,延遲將被認為過期,該元素將會在 DelayQueue 的下一次 take 被呼叫的時候被釋放掉。
傳遞給 getDelay 方法的 getDelay 例項是一個列舉型別,它表明了將要延遲的時間段。TimeUnit 列舉將會取以下值:
[java] view plain
相關推薦
Java併發工具包使用指南(全)
1. java.util.concurrent - Java 併發工具包 Java 5 添加了一個新的包到 Java 平臺,java.util.concurrent 包。這個包包含有一系列能夠讓 Java 的併發程式設計變得更加簡單輕鬆的類。在這個包被新增以前,
Java 併發工具包 java.util.concurrent 使用者指南
譯序 1. java.util.concurrent - Java 併發工具包 Java 5 添加了一個新的包到 Java 平臺,java.util.concurrent 包。這個包包含有一系列能夠讓 Java 的併發程式設計變得更加簡單輕鬆的類。在這個包被新
Java併發工具包java.util.concurrent使用者指南
拋異常 特定值 阻塞 超時 插入 add(o) offer(o) put(o) offer(o, timeout, timeunit) 移除 remove(o) poll(o) take(o) poll(timeout, timeuni
理解Java併發工具包執行緒池的設計
為什麼需要執行緒池? 答:主要原因是因為建立一個執行緒開銷太大,尤其是對大量的小任務需要執行這種場景。 在Java裡面建立一個執行緒,需要包含的東西: (1)它為一個執行緒堆疊分配記憶體,該堆疊為每個執行緒方法呼叫儲存一個幀 (2)每個幀由區域性變數陣列,返回值,運算
Java多執行緒(二)Java併發工具包concurrent例項簡述
傳統的多執行緒並沒有提供高階特性,例如:訊號量、執行緒池和執行管理器等,而這些特性恰恰有助於建立強大的併發程式。新的Fork/Join框架針對當前的多核系統,也提供了並行程式設計的可能。這塊的內容是java多執行緒資訊量最大的一部分內容,本篇部落格循序漸進的,首
Java 併發工具包-java.util.concurrent-原始碼jdk1.7全面解析
先來看看類圖: 其實從類圖我們能發現concurrent包(除去java.util.concurrent.atomic 和 java.util.concurrent.locks)中的內容並沒有特別多,大概分為四類:BlockingQueue阻塞佇列體系、Executor
Java併發程式設計-併發工具包java.util.concurrent使用指南
譯序 1. java.util.concurrent - Java併發工具包 Java 5 添加了一個新的包到 Java 平臺,java.util.concurrent 包。這個包包含有一系列能夠讓 Java 的併發程式設計變得更加簡單輕鬆的類。在這
java.util.concurrent 併發工具包(二)
一、ThreadPoolExecutor 執行緒池執行者 初始化執行緒池的引數 corePoolSize 核心執行緒大小 maximumPoolSize 最大執行緒大小 keepAliveTime 空餘的多餘執行緒保持時間 unit 時間
java 反射工具包reflections
分享圖片 class ref logs annotate .get pan can sys reflections 中包含很多的Scanner ,也就是掃描器,調用對應的方法時需要有配置對應的掃描器,不然程序會拋出異常. 掃描器結構: 使用時,我們主要使用Reflecti
Apache commons(Java常用工具包)簡介
機制 encode 解析 help IT PE tom base cit Apache Commons是一個非常有用的工具包,解決各種實際的通用問題,下面是一個簡述表,詳細信息訪問http://jakarta.apache.org/commons/index.html Be
Java神奇工具——Lombok[最全]
最近剛接觸,結果官網訪問速度很慢,網上部落格又沒有介紹全,打算自己做個詳細的,以防後面複習使用。 目錄 Lombok 如何用Lombok——兩種方法 有哪些註解可以使用呢[1.16.18版本一共18個註解,有一個註解不推薦使用] @AllArg
Java併發工具類詳解
在JDK的併發包裡提供了幾個非常有用的併發工具類。CountDownLatch、CyclicBarrier和Semaphore工具類提供了一種併發流程控制的手段,Exchanger工具類則提供了線上程間交換資料的一種手段。本章會配合一些應用場景來介紹如何使用這些工具類。 等待多執行緒完成的Cou
什麼是JDK?關於JDK(Java Development Kit)Java開發工具包的介紹
什麼是JDK?關於JDK(Java Development Kit)Java開發工具包的介紹 JDK是構建Java應用程式的關鍵平臺部分,JDK的核心是Java編譯器。 JDK是Java程式設計三個核心技術包之一,另外兩個是JVM(Java Virtual Machine)Java虛擬機器和
Java併發工具類——AtomicInteger
基本型別int的遞增等操作並不是執行緒安全的,加上synchronized又會影響效能,因此在併發情況下我們應該使用AtomicInteger,下面通過一個例子驗證一哈。 public class TestAtomicInteger { public static void mai
Java原始碼分析——java.util工具包解析(五)——UUID、Base64、內建觀察者模式Observer介面、EventListener、RandomAccess
UUID 關於UUID,我們需要知道它最重要的一點,就是它會生成全地球唯一的一個id,它可以作為資料庫的主鍵存在,標識各個元組。 UUID保證對在同一時空中的所有機器都是唯一的,利用機器的當前日期和時間、時鐘序列、全域性唯一的IEEE機
Java原始碼分析——java.util工具包解析(四)——四大引用型別以及WeakHashMap類解析
WeakHashMap是Map的一種很獨特的實現,從它的名字可以看出,它是存貯弱引用的對映的,先來複習一下Java中的四大引用型別: 強引用:我們使用的大部分引用實際上都是強引用,這是使用最普遍的引用。強引用的物件垃圾回收器絕不
Java原始碼分析——java.util工具包解析(三)——HashMap、TreeMap、LinkedHashMap、Hashtable類解析
Map,中文名字對映,它儲存了鍵-值對的一對一的關係形式,並用雜湊值來作為存貯的索引依據,在查詢、插入以及刪除時的時間複雜度都為O(1),是一種在程式中用的最多的幾種資料結構。Java在java.util工具包中實現了Map介面,來作為各大
Java原始碼分析——java.util工具包解析(二)——HashSet、TreeSet、LinkedHashSet類解析
Set,即集合,與數學上的定義一樣,集合具有三個特點: 無序性:一個集合中,每個元素的地位都是相同的,元素之間是無序的。 互異性:一個集合中,任何兩個元素都認為是不相同的,即每個元素只能出現一次。 確定性:給定一個集
Java原始碼分析——java.util工具包解析(一)——ArrayList、LinkedList、Vector類解析
Java中,List列表類與Set集合類的共同源頭是Collection介面,而Collection的父介面是Iterable介面,在Collection介面下又實現了三個常用的介面以及一個抽象方法,分別為Queue介面、List介面、Se
淺析Java併發工具類Semaphore
淺析Java併發工具類Semaphore 1. 概述 2. 原始碼分析 3. 一個例子 4. 總結 1. 概述 Semaphore類表示訊號量。Semaphore內部主要通