阻塞队列的关系图
ArrayBlockingQueue特点:FIFO(先进先出)
阻塞队列的概念:当队列值满后,队列处于等待状态
队列的概念:
写入:如果队列满了,就必须阻塞等待。
取出:如果队列值是空的,必须阻塞等待生产。
解决阻塞队列的四种方案
1.抛出异常
2.不抛异常处理
3.阻塞等待
4.超时等待
阻塞队列的add和poll方法使用
方式 | 抛出异常 | 有返回值,不抛异常 | 阻塞等 |
---|---|---|---|
添加 | add | offer | put |
移除 | remove | poll() | take() |
检测队列首次元素 | elemet | peek |
1. 抛出异常: and 和 remove方法
队列未满时,正常情况下代码案例
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.TimeUnit;
/**
* 队列的概念:
* 写入:如果队列满了,就必须阻塞等待
* 取出:如果队列值是空的,必须阻塞等待生产
*学会使用对象的添加,取出方法
*四种解决阻塞Api
* 1.抛出异常
*队列排列元素FIFO(先进先出)。
*/
public class ArrayBlockingQueueTest {
public static void main(String[] args) throws Exception {
test1();
}
/**
* 1.抛出异常队列
* 描述:如果队列数量超出队列指定数量,添加和取出都出现异常
*/
public static void test1(){
ArrayBlockingQueue queue = new ArrayBlockingQueue<>(4);
// ArrayBlockingQueue queue = new ArrayBlockingQueue<>(4,true);
// //加入队列
System.out.println(queue.add("a"));
System.out.println(queue.add("b"));
System.out.println(queue.add("c"));
System.out.println(queue.add("d"));
System.out.println(queue.add("e"));//Queue full 抛出异常
// //取出队列
System.out.println(queue.remove());
System.out.println(queue.remove());
System.out.println(queue.remove());
System.out.println(queue.remove());
}
}
输出结果:
true
true
true
true
a
b
c
d
阻塞队列已满时, 抛出异常 Queue full
public class ArrayBlockingQueueTest {
public static void main(String[] args) throws Exception {
test1();
}
/**
* 1.抛出异常队列
* 描述:如果队列数量超出队列指定数量,添加和取出都出现异常
*/
public static void test1(){
// 4表示工作队列的长度
ArrayBlockingQueue queue = new ArrayBlockingQueue<>(4);
//加入队列
System.out.println(queue.add("a"));
System.out.println(queue.add("b"));
System.out.println(queue.add("c"));
System.out.println(queue.add("d"));
System.out.println(queue.add("e"));//Queue full 抛出异常
//取出队列
System.out.println(queue.remove());
System.out.println(queue.remove());
System.out.println(queue.remove());
System.out.println(queue.remove());
}
}
输出结果:
Exception in thread "main" true
true
true
true
java.lang.IllegalStateException: Queue full
at java.util.AbstractQueue.add(AbstractQueue.java:98)
at java.util.concurrent.ArrayBlockingQueue.add(ArrayBlockingQueue.java:312)
at com.urun.example.myqueue.ArrayBlockingQueueTest.test1(ArrayBlockingQueueTest.java:53)
at com.urun.example.myqueue.ArrayBlockingQueueTest.main(ArrayBlockingQueueTest.java:22)
2.阻塞队列已满时,不抛异常处理
public class ArrayBlockingQueueTest {
public static void main(String[] args) throws Exception {
test2();
}
/**
* 2.不抛出异常,
* 添加 :超出指定队列值返回:false
* 取出 :超出指定队列值返回:null
*/
public static void test2(){
ArrayBlockingQueue queue = new ArrayBlockingQueue<>(4);
//添加队列
System.out.println(queue.offer("a"));
System.out.println(queue.offer("b"));
System.out.println(queue.offer("c"));
System.out.println(queue.offer("d"));
System.out.println(queue.offer("e"));//不抛出异常 ,返回false
System.out.println("-----------------------");
//取出队列
System.out.println(queue.poll());
System.out.println(queue.poll());
System.out.println(queue.poll());
System.out.println(queue.poll());
System.out.println(queue.poll());//不抛出异常 ,返回null
}
}
输出结果:
true
true
true
true
false
-----------------------
a
b
c
d
null
3.等待,阻塞 (一直等待)
public class ArrayBlockingQueueTest {
public static void main(String[] args) throws Exception {
test3();
}
/**
* 等待,阻塞 (一直等待)
* @throws InterruptedException
* 添加 :未超出指定队列值时,正常执行,如果超出一直处于等待状态。
*/
public static void test3() throws InterruptedException{
ArrayBlockingQueue queue = new ArrayBlockingQueue<>(4);
queue.put("a");
queue.put("b");
queue.put("c");
queue.put("d");
// queue.put("e"); // 队列位置已满,一直阻塞
System.out.println(queue.take());
System.out.println(queue.take());
System.out.println(queue.take());
System.out.println(queue.take());
System.out.println(queue.take());//没有这个元素
}
}
输出结果:
4.等待,阻塞(等待超时)
public class ArrayBlockingQueueTest {
public static void main(String[] args) throws Exception {
test4();
}
/**
* 等待,阻塞(等待超时)
* 添加元素超过指定元素值时,等待3秒后执行后退,不会添加多余的元素
* 取出元素超过指定元素值时,等待3秒后执行后退,不会添加多余的元素
*/
public static void test4() throws InterruptedException{
ArrayBlockingQueue queue = new ArrayBlockingQueue<>(4);
//添加
queue.offer("a");
queue.offer("b");
queue.offer("c");
queue.offer("d");
queue.offer("e",3 ,TimeUnit.SECONDS);//等待超过3秒就退出
System.out.println(queue);
//取出
System.out.println(queue.poll());
System.out.println(queue.poll());
System.out.println(queue.poll());
System.out.println(queue.poll());
System.out.println(queue.poll(3,TimeUnit.SECONDS));//等待超过3秒就退出
}
}
输出结果:
[a, b, c, d]
a
b
c
d
null
对比LinkedBlockingQueue和ArrayBlockingQueue区别
相同点:
1、LinkedBlockingQueue和ArrayBlockingQueue都实现了BlockingQueue接口;
2、LinkedBlockingQueue和ArrayBlockingQueue都是可阻塞的队列内部
3、都是使用ReentrantLock和Condition来保证生产和消费的同步;
4、当队列为空,消费者线程被阻塞;当队列装满,生产者线程被阻塞;
5、使用Condition的方法来同步和通信:await()和signal();
不同点:
1、LinkedBlockingQueue中的锁是分离的,生产者的锁PutLock,消费者的锁takeLock,而ArrayBlockingQueue生产者和消费者使用的是同一把锁;
2、他们的底层实现机制也不同LinkedBlockingQueue内部维护的是一个链表结构,在生产和消费的时候,需要创建Node对象进行插入或移除,大批量数据的系统中,其对于GC的压力会比较大而ArrayBlockingQueue内部维护了一个数组;
3、在生产和消费的时候,是直接将枚举对象插入或移除的,不会产生或销毁任何额外的对象实例
4、构造时候的区别LinkedBlockingQueue有默认的容量大小为:Integer.MAX_VALUE,当然也可以传入指定的容量大小
ArrayBlockingQueue在初始化的时候,必须传入一个容量大小的值,看其提供的构造方法就能知道
5、执行clear()方法
LinkedBlockingQueue执行clear方法时,会加上两把锁
6、统计元素的个数
LinkedBlockingQueue中使用了一个AtomicInteger对象来统计元素的个数,ArrayBlockingQueue则使用int类型来统计元素