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);
	}
}

结果

image

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 + "]";
	}
}

结果
image

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 + "}";
	}
}
  • 结果
    image

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();
	}
}

结果
image

10. LinkedTransferQueue

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

实现方式后面分析

posted @ 2023-06-13 16:33  弘一  阅读(31)  评论(0)    收藏  举报