java線程池學習(一) —— BlockingQueue

我們都知道線程池有很多好處:

通過重複利用已經創建好的線程,可以減少創建線程時的資源消耗。

如果不限制線程的數量,不僅會大量消耗系統內存,還會照成系統的不穩定。

使用線程池,可以控制線程的數量,還可以對所有線程進行統一的管理,好處不言而喻。

那麼在詳細瞭解線程池之前。我們需要先複習一些概念


一。阻塞隊列(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)

這兩個類型的返回意義如下:

  1. Throws Exception: 
    如果這個操作不能立即執行,那麼拋出異常
  2. 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: 這四各類型的返回意義如下:

  1. 如果這個操作不能立即執行,那麼拋出異常
  2. Special Value: 
    如果這個操作不能立即執行,那麼相應返回(true/false)
  3. Blocks: 
    如果這個操作不能立即執行,那麼操作阻塞等待,直到操作可以執行。
  4. 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概念,在以後線程池的實現中有很大用處


發佈了40 篇原創文章 · 獲贊 32 · 訪問量 11萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章