Queue 接口
Queue接口是Java集合框架中定义的一个接口,它代表了一个先进先出(FIFO)的队列。Queue接口继承自Collection接口,它定义了一组方法来操作队列中的元素。
public interface Queue<E> extends Collection<E> {
/**
* 如果可以,在不违反容量限制的情况下立即将指定元素插入此队列,成功时返回true,如果当前没有可用空间则抛出 * IllegalStateException。
* 参数: E -要添加的元素 返回: true(由Collection.add指定)
* 抛出: IllegalStateException — 如果由于容量限制,此时不能添加元素
* ClassCastException — 如果指定元素的类阻止它被添加到这个队列
* NullPointerException -如果指定的元素是空的,这个队列不允许空元素
* IllegalArgumentException - 如果这个元素的某些属性阻止它被添加到这个队列
*/
boolean add(E e);
/**
* 如果可以在不违反容量限制的情况下立即将指定元素插入此队列。当使用有容量限制的队列时,此方法通常优于add方法,因为add方法只 * 能通过抛出异常而无法插入元素。
* E -要添加的元素 返回: 如果元素被添加到队列中,则为True,否则为false
* 抛出: ClassCastException——如果指定元素的类阻止它被添加到这个队列
* NullPointerException -如果指定的元素是空的,这个队列不允许空元素
* IllegalArgumentException -如果这个元素的某些属性阻止它被添加到这个队列
*/
boolean offer(E e);
/**
* 检索并删除此队列的头部。此方法与poll的唯一不同之处在于,如果此队列为空,它将抛出异常。
* 返回: 这个队列的头 抛出: NoSuchElementException -如果此队列为空
*/
E remove();
/**
* 检索并删除此队列的头部,如果此队列为空,则返回null。
* 返回: 此队列的头部,如果此队列为空,则为null
*/
E poll();
/**
* 检索但不删除此队列的头部。此方法与peek的唯一不同之处在于,如果此队列为空,它将抛出异常。
* 返回: 这个队列的头 抛出: NoSuchElementException -如果此队列为空
*/
E element();
/**
* 检索但不删除此队列的头部,如果此队列为空则返回null。
* 返回: 此队列的头部,如果此队列为空,则为null
*/
E peek();
}
queue接口还有一些继承的Collection接口的方法如 : size() , clear()等
总结 :
- 添加元素:
boolean add(E element) : 将指定的元素添加到队列的末尾,如果成功则返回true,如果队列已满则抛出异常。
boolean offer(E element) : 将指定的元素添加到队列的末尾,如果成功则返回true,如果队列已满则返回false。
- 移除元素:
E remove() : 移除并返回队列头部的元素,如果队列为空则抛出异常。
E poll() : 移除并返回队列头部的元素,如果队列为空则返回null。
- 获取头部元素:
E element() : 获取队列头部的元素,但不移除它,如果队列为空则抛出异常。
E peek() : 获取队列头部的元素,但不移除它,如果队列为空则返回null。
- 队列大小:
int size(): 返回队列中的元素个数。
boolean isEmpty(): 判断队列是否为空。
Java Queue接口使用示例:
当使用Java中的Queue接口时,我们需要选择具体的实现类来创建一个队列对象。下面是一个使用Queue接口的示例,以LinkedList实现类为例:
import java.util.Queue;
import java.util.LinkedList;
public class QueueExample {
public static void main(String[] args) {
// 创建一个Queue对象
Queue<String> queue = new LinkedList<>();
// 添加元素到队列
queue.add("Apple");
queue.add("Banana");
queue.add("Orange");
// 获取队列头部元素
String head = queue.peek();
System.out.println("头部元素:" + head);
// 遍历队列并输出元素
System.out.println("队列元素:");
for (String element : queue) {
System.out.println(element);
}
// 移除队列头部元素
String removedElement = queue.remove();
System.out.println("移除的元素:" + removedElement);
// 队列大小
int size = queue.size();
System.out.println("队列大小:" + size);
// 判断队列是否为空
boolean isEmpty = queue.isEmpty();
System.out.println("队列是否为空:" + isEmpty);
}
}
BlockingQueue
什么是阻塞队列
- 线程1往阻塞队列中添加元素,而线程2从阻塞队列中移除元素
- 当阻塞队列是空是,从队列中获取元素的操作会被阻塞
- 当阻塞队列是满时,从队列中添加元素的操作会被阻塞
- 试图从空的阻塞队列中获取元素的线程将会被阻塞,直到其他的线程往空的队列插入新的元素
- 试图从已满的阻塞队列中添加新元素的线程同样会被阻塞,直到其他的线程从列中移除一个或者多个元素或者完全清空队列后使队列重新变得空闲起来并后续新增
阻塞队列常用于生产者和消费者的场景,生产者是向队列里添加元素的线程,消费者是从队列里取元素的线程。阻塞队列就是生产者用来存放元素、消费者用来获取元素的容器。
阻塞队列种类
- ArrayBlockingQueue:由数据结构组成的有界阻塞队列
- LinkedBlockingQueue:由链表结构组成的有界(但大小默认值为 Integer.MAX_VALUE )阻塞队列
- PriorityBlockingQueue : 支持优先级排序的无界阻塞队列
- DelayQueue : 使用优先级队列实现的延迟无界阻塞队列
- SynchronousQueue : 不存储元素的阻塞队列,也即单个元素的队列
- LinkedTransferQueue : 由链表结构组成的无界阻塞队列
- LinkedBlockingDeque : 由历览表结构组成的双向阻塞队列
PS:重点掌握ArrayBlockingQueue、LinkedBlockingQueue、SychronousQueue三种
BlockingQueue的核心方法
方法类型 | 抛出异常 | 特殊值 | 一直阻塞 | 超时退出 |
---|---|---|---|---|
插入 | add(e) | offer(e) | put(e) | offer(e,time,unit) |
移除 | remove() | poll() | take() | poll(time,unit) |
检查 | element() | peek() | 不可用 | 不可用 |
说明:
方法类型 | 情况 |
---|---|
抛出异常 | 当阻塞队列满时,再往队列中add会抛 IllegalStateException: Queue full; 当阻塞队列空时,再从队列里remove会抛 NoSuchElementException |
特殊值 | offer(e)插入方法,成功true失败false poll() 移除方法,成功返回出队列的元素,队列里没有就返回null |
一直阻塞 | 当阻塞队列满时,生产者线程继续往队列里put元素,队列会一直阻塞线程直到take数据或响应中断退出 当阻塞队列空时,消费者线程试图从队列take元素,队列会一直阻塞消费者线程直到队列可用 |
超时退出 | 当阻塞队列满时,队列会阻塞生产者线程一定时间,超过限时后生产者线程会退出 |
示例代码
使用SychronousQueue队列
package com.changjunkai.juc.demo.mediacloud;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.TimeUnit;
/*
* 阻塞队列SynchronousQueue演示
* */
public class SynchronousQueueDemo {
public static void main(String[] args) {
BlockingQueue<String> blockingQueue = new SynchronousQueue<>();
new Thread(() -> {
try {
System.out.println(Thread.currentThread().getName() + "\t put 1");
blockingQueue.put("1");
System.out.println(Thread.currentThread().getName() + "\t put 2");
blockingQueue.put("2");
System.out.println(Thread.currentThread().getName() + "\t put 3");
blockingQueue.put("3");
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "AAA").start();
new Thread(() -> {
try {
TimeUnit.SECONDS.sleep(2);
System.out.println(Thread.currentThread().getName() + "\t take" + blockingQueue.take());
TimeUnit.SECONDS.sleep(2);
System.out.println(Thread.currentThread().getName() + "\t take" + blockingQueue.take());
TimeUnit.SECONDS.sleep(2);
System.out.println(Thread.currentThread().getName() + "\t take" + blockingQueue.take());
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "BBB").start();
}
}
Deque 接口
Deque接口是Java集合框架中定义的一个接口,它代表了一个**双端队列**(Double Ended Queue)。Deque是"双端队列"的缩写。Deque接口继承自Queue接口,并在其基础上提供了在队列两端进行添加、删除和检索元素的操作。Deque可以在队列的头部和尾部同时进行元素的插入和删除,因此可以作为队列、栈或双向队列使用。
public interface Deque<E> extends Queue<E> {
void addFirst(E e);
void addLast(E e);
boolean offerFirst(E e);
boolean offerLast(E e);
E removeFirst();
E removeLast();
E pollFirst();
E pollLast();
E getFirst();
E getLast();
E peekFirst();
E peekLast();
boolean removeFirstOccurrence(Object o);
boolean removeLastOccurrence(Object o);
// *** Queue methods ***
boolean add(E e);
boolean offer(E e);
E remove();
E poll();
E element();
E peek();
// *** Stack methods ***
void push(E e);
E pop();
// *** Collection methods ***
boolean remove(Object o);
boolean contains(Object o);
public int size();
Iterator<E> iterator();
Iterator<E> descendingIterator();
}
Deque接口定义了以下主要方法和特性:
- 添加元素:
void addFirst(E element): 将指定元素添加到双端队列的头部。
void addLast(E element): 将指定元素添加到双端队列的尾部。
boolean offerFirst(E element): 将指定元素添加到双端队列的头部,如果成功则返回true,如果队列已满则返回false。
boolean offerLast(E element): 将指定元素添加到双端队列的尾部,如果成功则返回true,如果队列已满则返回false。
- 移除元素:
E removeFirst(): 移除并返回双端队列的头部元素,如果队列为空则抛出异常。
E removeLast(): 移除并返回双端队列的尾部元素,如果队列为空则抛出异常。
E pollFirst(): 移除并返回双端队列的头部元素,如果队列为空则返回null。
E pollLast(): 移除并返回双端队列的尾部元素,如果队列为空则返回null。
- 获取头部和尾部元素:
E getFirst(): 获取双端队列的头部元素,但不移除它,如果队列为空则抛出异常。
E getLast(): 获取双端队列的尾部元素,但不移除它,如果队列为空则抛出异常。
E peekFirst(): 获取双端队列的头部元素,但不移除它,如果队列为空则返回null。
E peekLast(): 获取双端队列的尾部元素,但不移除它,如果队列为空则返回null。