携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第4天,点击查看活动详情
阻塞队列是支持阻塞的插入和移除的队列,即在队列满时,阻塞插入元素的线程直到队列不满,在队列空时,阻塞获取元素的线程直到队列非空。Java中有7种阻塞队列
有界队列
数组组成的有界队列:ArrayBlockingQueue
底层是数组的严格按照先进先出逻辑的阻塞队列,其构造方法包含两个参数
ArrayBlockingQueue<Integer> queue = new ArrayBlockingQueue<Integer>(100, true);
第一个参数为capacity
,即队列的容量,必填;第二个参数为是否保证线程公平,即先阻塞的线程一定在满足条件时一定先执行操作,默认为false
。
链表组成的有界队列:LinkedBlockingQueue
底层是链表的严格按照先进先出逻辑的阻塞队列
LinkedBlockingQueue queue = new LinkedBlockingQueue<Integer>();
由于底层是链表,无需像 ArrayBlockingQueue 一样传入capacity
初始化底层数组,因而容量不是必填的,默认为Integer.MAX_VALUE。
链表组成的双向队列:LinkedBlockingDeque
底层是链表的双向队列
无界队列
无界队列是能够自动扩容的队列
支持优先级排序的无界队列:PriorityBlockingQueue
默认情况下根据元素的 compareTo() 方法来指定排序规则,或者在初始化时传入自定义的Comparator来进行排,它的底层数据结构也同样为数组,默认大小为Integer.MAX_VALUE。
PriorityBlockingQueue<Integer> queue = new PriorityBlockingQueue<>(100, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
//
}
});
使用优先级队列实现的支持延时获取的无界队列:DelayQueue
ScheduleThreadPoolExecutor 就是使用了 DelayQueue 实现的定时调度线程池,线程任务都被包装为 ScheduledFutureTask
,参考 ScheduledFutureTask
的实现就可知道如何使用 DelayQueue
,即入队的元素必须实现 Delayed 接口实现 getDelay() 方法,该方法指定延时,推荐使用纳秒(),延时结束后才能线程获取元素,否则会阻塞。另外还需要实现 compareTo() 方法来决定元素在队列中的优先级。
public class DelayElement implements Delayed {
private final long time;
public DelayElement(long time) {
this.time = time;
}
@Override
public long getDelay(TimeUnit unit) {
return unit.convert(time - System.currentTimeMillis(), TimeUnit.NANOSECONDS);
}
@Override
public int compareTo(Delayed o) {
return 0;
}
}
public class Main {
public static void main(String[] args) throws InterruptedException {
DelayQueue<DelayElement> queue = new DelayQueue<>();
queue.put(new DelayElement(DateTime.now().plusHours(1).getMillis()));
DelayElement take = queue.take(); // 方法阻塞直到一小时后到了为止
}
}
链表组成的支持transfer的无界队列:LinkedTransferQueue
LinkedTransferQueue
和其他队列的不同点是增加了 transfer()方法和 tryTransfer() 方法,用于是跟踪元素被消费的情况。调用transfer方法时,如果有消费者正在等待消费,那么元素直接transfer给消费者,反之放到队尾,直到元素被消费了,该方法才会返回。tryTransfer() 方法是立即返回,如果元素理解被消费返回true,否则返回false,另外可以自定义 tryTransfer() 方法的超时时间。
queue.tryTransfer(1L, 10, TimeUnit.MILLISECONDS);
不存储元素的队列
不存储元素的队列:SynchronousQueue
一个不存储元素的阻塞队列,即每一个put操作都必须等待一个take操作,队列本身不做任何的存储,只有在生产者和消费者都有请求时,起到一个传递的作用。