Queue集合
1. 概述
Queue用于模拟队列这种数据结构,队列通常是指先进先出的容器。
新元素插入到队列的尾部,访问元素操作会返回队列头部的元素。通常,队列不允许随机访问队列中的元素。
- 基本方法
boolean add(E e);//将指定元素加入此队列的尾部,成功返回true,失败抛出异常
E remove();//获取队列头部的元素,并删除该元素,队列为空时抛出异常NoSuchElementException
Object element();//获取列队头部的元素,但是不删除该元素
boolean offer(E e);//将指定元素加入此队列的尾部,成功返回true,失败返回false
E poll();//获取队列头部的元素,并删除该元素,如果此队列为空,则返回null
Object peek();//获取队列头部的元素,但是不删除该元素,如果此队列为空,则返回null
- 实现类
名称 描述 备注 ArrayBlockingQueue 数组阻塞队列 LinkedBlockingQueue 单向链表阻塞队列,默认大小是Interger最大值 PriorityBlockingQueue 优先阻塞队列 默认容量11 ConcurrentLinkedQueue 链表非阻塞线程安全队列 PriorityQueue 优先队列,非线程安全 默认容量11 DelayQueue 无界阻塞延迟队列 SynchronousQueue 同步阻塞队列 无容量 LinkedTransferQueue 链表无界阻塞队列
2. BlockingQueue接口
阻塞队列接口
- 增加方法
void put(E e) throws InterruptedException;//将指定元素加入此队列的尾部,无空间,阻塞等待
E take() throws InterruptedException;//获取并移除队列头部的元素,无元素时候阻塞等待
boolean offer(E e, long timeout, TimeUnit unit) throws InterruptedException;//将给定元素在给定的时间内设置到队列中,无空间阻塞,如果设置成功返回true, 否则返回false。
E poll(long timeout, TimeUnit unit) throws InterruptedException;//获取并移除队列头部的元素,无元素时候阻塞等待指定时间
3. ArrayBlockingQueue
实现BlockingQueue接口,线程安全的有界队列队列。底层数据结构为数组,由ReentrantLock实现线程安全。
4. LinkedBlockingQueue
实现BlockingQueue接口,线程安全的可有界可无界的队列。底层数据结构为链表,由ReentrantLock实现线程安全。、
5. PriorityBlockingQueue
实现BlockingQueue接口的无界队列,默认容量为11,扩容为之前容量的50%。通过ReenTrantLock实现线程安全。
特点
- 对队列中的元素进行排序,如果未指定比较器,插入队列的元素必须实现Comparable接口。
- 内部基于数组实现的最小二叉堆算法。
- 队列的长度是可扩展的(类似ArrayList),上限为Integer.MAX_VALUE - 8.
例子
/**
* @author kouhao
* @since 2023-06-13
*/
public class PriorityBlockingQueueTest {
/**
* 主方法
*
* @param args 参数
*/
public static void main(String[] args) {
PriorityBlockingQueue<Student> queue = new PriorityBlockingQueue<>(3);
queue.put(new Student("44444"));
queue.put(new Student("22222"));
queue.put(new Student("33333"));
queue.put(new Student("11111"));
while (!queue.isEmpty()) {
Student student = queue.poll();
System.out.println(student.name);
}
}
}
class Student implements Comparable<Student> {
String name;
Student(String name) {
this.name = name;
}
@Override
public int compareTo(Student o) {
return o.name.compareTo(this.name);
}
}
结果
6. ConcurrentLinkedQueue
一个基于链接节点的无界线程安全队列。本队列是非阻塞队列。使用CAS(Compare And Swap)来实现无阻塞、无锁队列。
7. PriorityQueue
特点
PriorityQueue是一个无限制的队列,并且动态增长
默认初始容量为11
不允许NULL对象
添加到PriorityQueue的对象必须具有可比性
默认情况下,优先级队列的对象按自然顺序排序
PriorityQueue 不是线程安全的
数据结构为完全二叉树
例子
import java.util.Comparator;
import java.util.PriorityQueue;
/**
* @author kouhao
*/
public class PriorityQueueTest {
public static void main(String[] args) {
System.out.println("======自然排序=====");
PriorityQueue<Employee> priorityQueue = init(null);
printQueue(priorityQueue);
System.out.println("======比较器排序=====");
Comparator<Employee> nameSorter = Comparator.comparing(Employee::getName);
priorityQueue = init(nameSorter);
printQueue(priorityQueue);
}
private static void printQueue(PriorityQueue<Employee> priorityQueue) {
while (!priorityQueue.isEmpty()) {
Employee e = priorityQueue.poll();
System.out.println(e);
}
}
private static PriorityQueue<Employee> init(Comparator<Employee> nameSorter) {
PriorityQueue<Employee> priorityQueue;
if (nameSorter != null) {
priorityQueue = new PriorityQueue<>(nameSorter);
} else {
priorityQueue = new PriorityQueue<>();
}
priorityQueue.add(new Employee(1L, "AAA"));
priorityQueue.add(new Employee(4L, "CCC"));
priorityQueue.add(new Employee(5L, "BBB"));
priorityQueue.add(new Employee(2L, "FFF"));
priorityQueue.add(new Employee(3L, "DDD"));
priorityQueue.add(new Employee(6L, "EEE"));
return priorityQueue;
}
}
class Employee implements Comparable<Employee> {
private Long id;
private String name;
public Employee(Long id, String name) {
this.id = id;
this.name = name;
}
public String getName() {
return name;
}
@Override
public int compareTo(Employee emp) {
return this.id.compareTo(emp.id);
}
@Override
public String toString() {
return "Employee [id=" + id + ", name=" + name + "]";
}
}
结果

8. DelayQueue
DelayQueue是一个无界的BlockingQueue,用于放置实现了Delayed接口的对象,其中的对象只能在其到期时才能从队列中取走。这种队列是有序的,即队头对象的延迟到期时间最长。
实现BlockingQueue接口的无界队列,线程安全的队列。
数据结构依赖PriorityQueue。
注意:不能将null元素放置到这种队列中。
例子
import java.util.concurrent.DelayQueue;
import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;
/**
* @author kouhao
*/
public class DelayQueueTest {
public static void main(String[] args) throws InterruptedException {
DelayStudent item1 = new DelayStudent("item1", 5000);
DelayStudent item2 = new DelayStudent("item2", 15000);
DelayStudent item3 = new DelayStudent("item3", 25000);
DelayQueue<DelayStudent> queue = new DelayQueue<>();
queue.put(item1);
queue.put(item2);
queue.put(item3);
System.out.println("begin time:" + System.currentTimeMillis());
while (!queue.isEmpty()) {
DelayStudent take = queue.take();
System.out.println(take);
}
}
}
class DelayStudent implements Delayed {
String name;
long time;
long currentTime;
DelayStudent(String name, long time) {
this.name = name;
this.time = time > 0 ? time : 0;
this.currentTime = System.currentTimeMillis();
}
@Override
public long getDelay(TimeUnit unit) {
return unit.convert((currentTime + time) - System.currentTimeMillis(), TimeUnit.MILLISECONDS);
}
@Override
public int compareTo(Delayed o) {
DelayStudent student = (DelayStudent) o;
return this.name.compareTo(student.name);
}
@Override
public String toString() {
return "DelayStudent{" + "time=" + time + ", name='" + name + "}";
}
}
- 结果

9. SynchronousQueue
实现BlockingQueue接口,无容量大小,线程安全的队列。
SynchronousQueue是BlockingQueue的一种特殊类型,其中每个插入操作必须等待另一个线程进行相应的删除操作。
- 公平队列
使用TransferQueue的内部队列,使用链表数据结构
队尾匹配队头出队,先进先出,体现公平原则 - 非公平队列
底层的实现使用的是TransferStack
例子
import java.util.concurrent.SynchronousQueue;
/**
* @author kouhao
*/
public class SynchronousQueueTest {
public static void main(String args[]) {
final SynchronousQueue<String> queue = new SynchronousQueue<>();
Thread producer = new Thread("PRODUCER") {
@Override
public void run() {
String base = "FOUR";
for (int i = 0; i < 5; i++) {
try {
String event = base + i;
queue.put(event);
System.out.printf("[%s] published event : %s %n", Thread.currentThread().getName(), event);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
producer.start();
Thread consumer = new Thread("CONSUMER") {
@Override
public void run() {
for (int i = 0; i < 5; i++) {
try {
String event = queue.take();
System.out.printf("[%s] consumed event : %s %n", Thread.currentThread().getName(), event);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
consumer.start();
}
}
结果

10. LinkedTransferQueue
队列也是基于链表的,对于所有给定的生产者都是先入先出的。
链表无界阻塞队列,通过CAS实现线程安全
可以看作LinkedBolckingQueue 和 SynchronousQueue 的合体
实现方式后面分析


浙公网安备 33010602011771号