队列
队列是一种特殊的线性表,限定只能在表的一端进行插入(队尾),而在另一端进行取值(也可以同时删除元素)的操作(对头),特点是“先进后出”。
队列Queue是Collection的子接口,继承了Collection的方法。
队列的分类
-
按功能分类
-
普通队列
普通队列(Queue)是指实现了先进先出的基本队列
常见实现类
ArrayBlockingQueue是用数组实现的普通队列
LinkedBlockingQueue是使用链表实现的普通队列
常用方法
offer():添加元素,如果队列已满直接返回false,队列未满直接插入并返回ture;
poll():删除并返回对头元素,当队列为空返回null;
add():添加元素,此方法是对offer方法的简单封装,如果队列已满,抛出IllegalStateException异常;
remove():直接删除队头元素;
peek():查询队头元素,但不会进行删除;
示例
public class NormalQueue { public static void main(String[] args) { //产生队列 Queue<String> queue = new LinkedBlockingDeque<>(); //添加元素 queue.offer("紫衫龙王"); queue.offer("青翼蝠王"); queue.offer("金毛狮王"); queue.offer("白眉鹰王"); //队列遍历,如果还有元素则继续循坏 while (!queue.isEmpty()) { //取出表头元素,并做删除处理 String str= queue.poll(); System.out.println("取出"+str+"现有"+queue); } } }
-
双端队列
双端队列(Deque)是指队列的头部和尾部都可以同时入队和出队的数据结构。
示例:
public static void main(String[] args) { //创建双端队列对象 ArrayDeque<Integer> deque=new ArrayDeque<>(); //向队列添加元素 deque.offer(1); deque.offer(2); //向队头添加元素 deque.offerFirst(3); //向队尾添加元素 deque.offerLast(4); while (!deque.isEmpty()){ //从队头取出并移除元素 Integer obj= deque.poll(); System.out.println(obj);//结果 3 1 2 4 } }
-
优先队列
优先队列(PriorityQueue)是一种特殊的队列,它并不是先进先出
public class PriorityTest { public static void main(String[] args) { //创建优先队列对象,并通过比较器确定优先级大小 PriorityQueue<Student> priorityQueue = new PriorityQueue(new Comparator<Student>() { @Override public int compare(Student o1, Student o2) { return o2.getGrade()- o1.getGrade(); } }); //向队列加入元素 priorityQueue.offer(new Student(3,"张三",90)); priorityQueue.offer(new Student(1,"李四",96)); priorityQueue.offer(new Student(4,"刘五",54)); priorityQueue.offer(new Student(2,"赵六",76)); while (!priorityQueue.isEmpty()){ //从队列中取出元素 Student s = priorityQueue.poll(); System.out.println(s); } } }
-
-
按大小分类
-
有界队列
是指有固定大小的队列,比如:设定了固定大小的ArrayBlockingQueue,又或者大小为0的SynchronousQueue。
-
无界队列
指的是没有设置固定大小的队列,队列大小随元素多少而增加。比如:ConcurrentLinkedQueue和PriorityQueue
-
-
按是否阻塞分类
-
阻塞队列
阻塞队列(BlockingQueue)提供了可阻塞的put和take方法。如果队列满了put方法会被阻塞等到有空间可用再将元素插入;如果队列是空的,那么take方法也会阻塞,直到有元素可用。
阻塞队列名称中,一般包含BlockingQueue。比如ArrayBlockingQueue、LinkedBlockingQueue。
示例
public static void main(String[] args) { //创建阻塞有界队列,长度为5 ArrayBlockingQueue<Integer> blockingQueue = new ArrayBlockingQueue<>(5); //向队列加入元素 new Thread() { public void run() { for (int i = 0; i < 10; i++) { try { //向队列加入元素,如果队列满,则阻塞 blockingQueue.put(i); // System.out.println(blockingQueue); } catch (InterruptedException e) { e.printStackTrace(); } } } }.start(); new Thread() { public void run() { while (true) { try { Integer x = blockingQueue.poll(); Thread.sleep(1000); System.out.println("取出:" + x + " " + blockingQueue); } catch (InterruptedException e) { e.printStackTrace(); } } } }.start(); }
-
非阻塞队列
非阻塞队列也就是普通队列,它的名字中不会包含BlockingQueue关键字,并且它不会包含put和take方法,当队列满了之后如果还有新元素入列会直接返回错误,并不会阻塞的等待着添加元素。
非阻塞队列的典型代表是ConcurrentLinkedQueue和PriorityQueue
在并发编程中,一般推荐使用阻塞队列,这样实现可以尽量地避免程序出现意外的错误。阻塞队列使用最经典的场景就是scoket客户端数据的读取和解析,读取数据的线程不断将数据放入队列,然后解析线程不断从队列取数据解析。例如:秒杀系统
-