什么是阻塞队列?
当阻塞队列为空时,从队列中获取元素被阻塞;
当阻塞队列为满时,从队列中添加元素被阻塞;
阻塞队列的优点
不需要关心线程安全问题
如线程安全的生产者消费者模型中,
多线程:(叫卖)
生产者线程与消费者线程需要不断的使用wait()/notify() 来保证线程安全问题。
阻塞队列:(商店)
产者生产产品放入商店(对应:线程将元素放入阻塞队列),消费者在商店中消费产品(对应:线程从阻塞队列中获取元素);当商店中的产品消费空了,消费者无法再在商店中消费产品(对应:阻塞队列为空时,线程无法从阻塞队列中获取元素);当商店装满了铲平时,生产者无法在放入产品(对应:阻塞队列满时,线程无法再添加元素)。
阻塞队列的种类
-
ArrayBlockingQueue:由数组结构构成的有界阻塞队列。
-
LinkedBlockingQueue:由链表构成的有界(默认大小值为Integer.MAX_VALUE)阻塞队列。
-
PriorityBlockingQueue:支持优先级排序的无界阻塞队列。
-
DelayQueue:使用优先级队列实现的延迟无界阻塞队列。
-
SynchronousQueue:不存储元素的阻塞队列,即单元素阻塞队列。
-
LinkedTransferQueue:由链表结构组成的无界阻塞队列。
-
LinkedBlockingDeque:由链表结果组成的双向阻塞队列。
阻塞队列核心方法
抛出异常组:
添加add()
,移除remove()
,检查element()
add()
,remove()
方法有boolean型返回值,添加移除成功返回true,否则抛出异常
element()
方法有Object返回值,返回队列头元素,若队列空抛出异常。
代码演示add()
方法:
import java.util.concurrent.*;
public class BlockingQueueDemo {
public static void main(String[] args){
BlockingQueue<Integer> bq = new ArrayBlockingQueue<>(3); //大小为3
System.out.println(bq.add(1));
System.out.println(bq.add(2));
System.out.println(bq.add(3));
System.out.println(bq.add(4));
}
}
代码输出:
true
true
true
Exception in thread "main" java.lang.IllegalStateException: Queue full
返回布尔组:
添加offer()
,移除poll()
,检查peek()
添加、移除成功返回true,失败返回false
检查成功返回队列头元素,否则返回空
不多说,直接上演示代码:
import java.util.concurrent.*;
public class BlockingQueueDemo {
public static void main(String[] args){
BlockingQueue<Integer> bq = new ArrayBlockingQueue<>(3);
System.out.println(bq.peek());
System.out.println(bq.offer(1));
System.out.println(bq.offer(2));
System.out.println(bq.offer(3));
System.out.println(bq.offer(4));
System.out.println(bq.peek());
System.out.println(bq.poll());
System.out.println(bq.poll());
System.out.println(bq.poll());
System.out.println(bq.poll());
}
}
代码输出:
null
true
true
true
false
1
1
2
3
null
Process finished with exit code 0
阻塞组:
添加put()
,移除take()
当阻塞队列已满,继续调用put 方法,队列会阻塞线程直到可以有其他线程获取元素;
当阻塞队列为空,继续调用take方法,队列会阻塞线程直到可以有其他线程添加元素。
代码演示put()
方法:
import java.util.concurrent.*;
public class BlockingQueueDemo {
public static void main(String[] args) throws InterruptedException {
BlockingQueue<Integer> bq = new ArrayBlockingQueue<>(3);
bq.put(1);
bq.put(2);
bq.put(3);
System.out.println("A");
bq.put(4);
System.out.println("B");
}
}
代码输出:
A
没错,只有一个A,没有B,也没有Process finished with exit code 0
,因为当前线程正在等待其他线程从阻塞队列中取走一个元素。
超时控制组:
添加offer()
,移除poll()
顾名思义,超时控制是阻塞的升级版,阻塞一定时间后会自动结束。
如下图:offer提供了两种参数的调用方法,第二种可以设置阻塞时间。
代码演示offer方法:
public class BlockingQueueDemo {
public static void main(String[] args) throws InterruptedException {
BlockingQueue<Integer> bq = new ArrayBlockingQueue<>(3);
System.out.println(bq.offer(1, 2L, TimeUnit.SECONDS));
System.out.println(bq.offer(1, 2L, TimeUnit.SECONDS));
System.out.println(bq.offer(1, 2L, TimeUnit.SECONDS));
System.out.println(bq.offer(1, 2L, TimeUnit.SECONDS));
}
}
代码输出:
true
true
true
false
Process finished with exit code 0
程序首先输出三个true,停顿2秒后输出false,小伙伴们可以复制代码自己尝试一下。
个人学习总结,如果疏漏、错误之处,欢迎指出。