Java多線程——ArrayBlockingQueue的使用

最近找實習,發現各大公司對Java的多線程愛的很深沉,遂決定開扒java.util.concurrent包,防止自己忘了,也給初學者一個參考。以下內容都來自官方的API,例子是我自己造的。


今天的主角是ArrayBlockingQueue。


一 位置

知道它實現了抽象類BlockingQueue即可,和它一樣的小夥伴很多


二 定義

我只截取了第一段,以後都不截圖了,需要的自己下載一個j2se7.chm就行了。

翻譯過來就是:用數組實現的、長度有限的BlockingQueue,元素先進先出,隊頭的元素停留在隊列裏的時間最長,而隊尾的最短,隊尾插入新元素,隊頭進行取元素操作。

試圖插元素到一個滿的隊列會被阻塞,從空隊列裏面取元素也會被阻塞。


三 方法

挑選其中的三個記錄一下。

  • void put(E e):插入元素,如果隊列滿則一直等待。插null會拋出NullPointerException,等待的時候被打斷會拋出InterruptedException
  • boolean offer(E e,long timeout,TimeUnit unit):插入元素,成功返回true,隊列滿則不插入也不等待,返回false。就是說直接放棄了此次操作。後兩個參數不解釋了。
  • E take():拿出對頭的元素,返回該元素,隊列空一直等待,和put對應。


四 怎麼用

我造了兩個消費者和生產者,分別演示put和take的用法,以及offer和take的用法

  • put,這個由生產者調用
package ArrayBlockingQueue;

import java.util.concurrent.BlockingQueue;

/**
 * BlockingQueue的使用
 * 生產者,生產方式:put
 * @author brucexiajun
 *
 */

public class Producer implements Runnable {

	private  BlockingQueue<Integer> blockingQueue;
	private static int element = 0;
	
	public Producer(BlockingQueue<Integer> blockingQueue) {
		this.blockingQueue = blockingQueue;
	}


	public void run() {
		try {
			while(element < 20) {
				System.out.println("將要放進去的元素是:"+element);
				blockingQueue.put(element++);
			}
		} catch (Exception e) {
			System.out.println("生產者在等待空閒空間的時候被打斷了!");
			e.printStackTrace();
		}
		System.out.println("生產者已經終止了生產過程!");
	}
}

生產數字,從0一直到19,然後就停工了,中間如果消費者來不及消費,生產者會自動阻塞。

  • take,消費者調用
package ArrayBlockingQueue;

import java.util.concurrent.BlockingQueue;

public class Consumer implements Runnable {

	private  BlockingQueue<Integer> blockingQueue;
	
	public Consumer(BlockingQueue<Integer> blockingQueue) {
		this.blockingQueue = blockingQueue;
	}


	public void run() {
		try {
			while(true) {
				System.out.println("取出來的元素是:"+blockingQueue.take());
			}
		} catch (Exception e) {
			System.out.println("消費者在等待新產品的時候被打斷了!");
			e.printStackTrace();
		}
	}
}

消費者一直在消費,queue空的時候自動等待,即使生產者停止了生產,消費者也會等待。

  • 主函數所在的類
package ArrayBlockingQueue;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

public class MainClass {

	public static void main(String[] args) {
		
		BlockingQueue<Integer> blockingQueue = new ArrayBlockingQueue<Integer>(3,true);
		Producer producerPut = new Producer(blockingQueue);
		Consumer consumer = new Consumer(blockingQueue);
		ProducerOffer producerOffer = new ProducerOffer(blockingQueue);
		
		new Thread(producerPut).start();
		
		new Thread(consumer).start();
		
		
	}
}

我新建了大小爲3的隊列,把這個隊列傳給生產者和消費者,它們公用這個隊列,滿的時候生產者阻塞,空的時候消費者阻塞,然後開啓生產者和消費者進程。

運行結果如下:(每次不一樣)

將要放進去的元素是:0
將要放進去的元素是:1
將要放進去的元素是:2
取出來的元素是:0
將要放進去的元素是:3
取出來的元素是:1
將要放進去的元素是:4
取出來的元素是:2
將要放進去的元素是:5
取出來的元素是:3
將要放進去的元素是:6
取出來的元素是:4
將要放進去的元素是:7
取出來的元素是:5
將要放進去的元素是:8
將要放進去的元素是:9
取出來的元素是:6
將要放進去的元素是:10
取出來的元素是:7
將要放進去的元素是:11
取出來的元素是:8
將要放進去的元素是:12
將要放進去的元素是:13
取出來的元素是:9
取出來的元素是:10
將要放進去的元素是:14
取出來的元素是:11
將要放進去的元素是:15
取出來的元素是:12
將要放進去的元素是:16
取出來的元素是:13
將要放進去的元素是:17
取出來的元素是:14
將要放進去的元素是:18
取出來的元素是:15
將要放進去的元素是:19
取出來的元素是:16
取出來的元素是:17
生產者已經終止了生產過程!
取出來的元素是:18
取出來的元素是:19

生產者最多連續生產3次,然後隊列滿了,要等待消費者消費,消費者同理

  • offer,生產者調用,把生產者的生產方式改成offer(用下面的類替換Producer類),如下
package ArrayBlockingQueue;

import java.util.concurrent.BlockingQueue;

/**
 * BlockingQueue的使用
 * 生產者,生產方式:offer
 * @author brucexiajun
 *
 */

public class ProducerOffer implements Runnable {

	private  BlockingQueue<Integer> blockingQueue;
	private static int element = 0;
	
	
	public ProducerOffer(BlockingQueue<Integer> blockingQueue) {
		this.blockingQueue = blockingQueue;
	}


	public void run() {
		try {
			while(element < 20) {
				System.out.println("將要放進去的元素是:"+element);
				blockingQueue.offer(element++);
			}
		} catch (Exception e) {
			System.out.println("生產者在等待空閒空間的時候被打斷了!");
			e.printStackTrace();
		}
		System.out.println("生產者已經終止了生產過程!");
	}
}

主類修改爲

package ArrayBlockingQueue;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

public class MainClass {

	public static void main(String[] args) {
		
		BlockingQueue<Integer> blockingQueue = new ArrayBlockingQueue<Integer>(3,true);
		Producer producerPut = new Producer(blockingQueue);
		Consumer consumer = new Consumer(blockingQueue);
		ProducerOffer producerOffer = new ProducerOffer(blockingQueue);
	
		
		new Thread(producerOffer).start();
		for(int i=0;i<10000;i++) {
			int a = i*2312/234*12;
		}
		new Thread(consumer).start();
		
		
	}
}

再次運行,結果爲

將要放進去的元素是:0
將要放進去的元素是:1
將要放進去的元素是:2
將要放進去的元素是:3
將要放進去的元素是:4
將要放進去的元素是:5
將要放進去的元素是:6
將要放進去的元素是:7
將要放進去的元素是:8
取出來的元素是:0
將要放進去的元素是:9
將要放進去的元素是:10
取出來的元素是:1
將要放進去的元素是:11
取出來的元素是:2
將要放進去的元素是:12
取出來的元素是:8
將要放進去的元素是:13
取出來的元素是:9
將要放進去的元素是:14
取出來的元素是:11
將要放進去的元素是:15
取出來的元素是:12
將要放進去的元素是:16
取出來的元素是:13
將要放進去的元素是:17
取出來的元素是:14
將要放進去的元素是:18
取出來的元素是:15
將要放進去的元素是:19
取出來的元素是:16
生產者已經終止了生產過程!
取出來的元素是:17
取出來的元素是:18
取出來的元素是:19

取出來的元素0,1,2,然後直接是8,因爲3-7根本沒有放到隊列裏面,offer不會自己阻塞,會直接跳過這個插入的過程。

這個和put不一樣,put會一直等待,就是說程序會一直停留在blockingQueue.put那一句,offer會跳過blockingQueue.offer那一句,而進入下一個while循環,這樣實際插入隊列的數字就會不連續了。

主函數裏面的for循環是爲了讓生產者和消費者隔開一段時間,以展示offer的效果。

ArrayBlockingQueue的方法很多,參考API即可。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章