我們都知道線程池有很多好處:
通過重複利用已經創建好的線程,可以減少創建線程時的資源消耗。
如果不限制線程的數量,不僅會大量消耗系統內存,還會照成系統的不穩定。
使用線程池,可以控制線程的數量,還可以對所有線程進行統一的管理,好處不言而喻。
那麼在詳細瞭解線程池之前。我們需要先複習一些概念
一。阻塞隊列(BlockingQueue)
先看一下阻塞隊列的代碼關係:interface BlockingQueue<E> extends Queue<E>
我們發現這是一個繼承了Queue的接口。BlockingQueue有什麼特性呢?我們做以下功課:
二。我們先看看最原始接口Queue Interface的方法:
java源碼註釋已經幫我們分類好了:
最原始的Queue Interface有兩種類型的插入,刪除,和獲取元素方法,歸類如下:
Throws Exception | Special Value | |
插入類 | add(o) | offer(o) |
刪除類 | remove(o) | poll(o) |
獲取類 | element(o) | peek(o) |
這兩個類型的返回意義如下:
- Throws Exception:
如果這個操作不能立即執行,那麼拋出異常 - Special Value:
如果這個操作不能立即執行,那麼相應返回(true/false)
三。我們再看看BlockingQueue Interface的方法
java 源碼註釋裏面已經很清楚幫我們分類好了
BlockingQueue有四種類型的插入,刪除,和獲取元素方法,歸類如下:
Throws Exception | Special Value | Blocks | Times Out | |
插入類 | add(o) | offer(o) | put(o) | offer(o, timeout, timeunit) |
刪除類 | remove(o) | poll(o) | take(o) | poll(timeout, timeunit) |
獲取類 | element(o) | peek(o) |
Throws Exception: 這四各類型的返回意義如下:
- 如果這個操作不能立即執行,那麼拋出異常
- Special Value:
如果這個操作不能立即執行,那麼相應返回(true/false) - Blocks:
如果這個操作不能立即執行,那麼操作阻塞等待,直到操作可以執行。 - Times Out:
如果這個操作不能立即執行,那麼操作阻塞等待,直到操作可以執行,但是有限定時間,如果超過時間還沒有完成,就會返回錯誤信息(false)
我們可以很明顯的看到BlockingQueue加入了阻塞等待的操作,可以理解成如果隊列滿了,插入任務就在門口等着,不拋出錯誤信息,直到有元素從隊列中取出,隊列有空位了,再進行插入操作,相應的你還可以加入等待超時機制,如果過時了,就不等了。
我們寫個例子看看:
package test;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
public class BlockingQueueTest {
public static void main(String[] args) {
//初始化隊列長度只有3的隊列
final BlockingQueue<String> blockingque = new ArrayBlockingQueue<String>(3);
Thread Putter = new Thread(new Runnable(){
@Override
public void run() {
for(int i=1;i<10;i++){
try {
blockingque.put("貨物"+i);
System.out.println("成功往隊列中放入貨物"+i);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
Putter.start();
Thread taker = new Thread(new Runnable(){
@Override
public void run() {
while(true){
try {
//取得時間延長,模擬取得時間遠大於放入時間
Thread.sleep(3000);
String cargo = blockingque.take();
System.out.println("取出貨物: "+cargo);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
taker.start();
}
}
輸出結果爲:
成功往隊列中放入貨物1
成功往隊列中放入貨物2
成功往隊列中放入貨物3
取出貨物: 貨物1
成功往隊列中放入貨物4
取出貨物: 貨物2
成功往隊列中放入貨物5
取出貨物: 貨物3
成功往隊列中放入貨物6
取出貨物: 貨物4
成功往隊列中放入貨物7
取出貨物: 貨物5
成功往隊列中放入貨物8
取出貨物: 貨物6
成功往隊列中放入貨物9
取出貨物: 貨物7
取出貨物: 貨物8
取出貨物: 貨物9
我們可以看到隊列長度爲3,隊列放滿3個後,put()方法就處於blocking的狀態等待隊列有位子
過了3秒後,getter開始從隊列中取貨物,一有空位,put()方法就得以繼續執行。
二。interface BlockingQueue的實現
由於BlockingQueue只是一個接口,需要類實現,java已經有了以下的幾個類實現BlockingQueue(java 6)
- ArrayBlockingQueue
- DelayQueue
- LinkedBlockingQueue
- PriorityBlockingQueue
- SynchronousQueue
最主要的,還是BlockingQue的Blocking概念,在以後線程池的實現中有很大用處