最近找實習,發現各大公司對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即可。