最近找实习,发现各大公司对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即可。