Java学习笔记——集合补充
Iterable接口中除了Colletion以及Map接口之外,还有一个比较常用的接口 —— Deque
Deque接口
public interface Deque<E> extends Queue<E>
Deque —— 双端队列接口继承了Queue接口,同时Stack类也已被声明为过时,官方同样推荐用Deque替代Stack
实现该接口的类/继承该接口的接口包括LinkedList、ArrayQueue、ConcurrentLinkedQueue、以及BlockingQueue接口
常用方法
节选自Deque - Java 11中文版 - API参考文档 (apiref.com)
boolean | offer(E e) | 将指定的元素插入此双端队列表示的队列中(换句话说,在此双端队列的尾部),如果它是立即可行且不会违反容量限制,返回 true 在成功和 false 如果当前没有空间可用。 |
---|---|---|
boolean | offerFirst(E e) | 将指定元素插入此双端队列的前面,除非它违反容量限制。 |
boolean | offerLast(E e) | 在此双端队列的末尾插入指定的元素,除非它违反容量限制。 |
E | peek() | 检索但不移除此双端队列表示的队列的头部(换句话说,此双端队列的第一个元素),如果此双端队列为空,则返回 null 。 |
E | peekFirst() | 检索但不删除此双端队列的第一个元素,如果此双端队列为空,则返回 null 。 |
E | peekLast() | 检索但不删除此双端队列的最后一个元素,如果此双端队列为空,则返回 null 。 |
E | poll() | 检索并删除此双端队列表示的队列的头部(换句话说,此双端队列的第一个元素),如果此双端队列为空,则返回 null 。 |
E | pollFirst() | 检索并删除此双端队列的第一个元素,如果此双端队列为空,则返回 null 。 |
E | pollLast() | 检索并删除此双端队列的最后一个元素,如果此双端队列为空,则返回 null 。 |
E | pop() | 从此双端队列表示的堆栈中弹出一个元素。 |
void | push(E e) | 如果可以在不违反容量限制的情况下立即执行此操作, IllegalStateException 到此双端队列表示的堆栈(换句话说,在此双端队列的头部),如果当前没有可用空间则抛出 IllegalStateException 。 |
offer、peek、poll一组可以作为队列使用
pop、push可以当作栈使用 其中pop等同于peek()操作
Deque<Integer> deque = new LinkedList<>();
deque.offer(1);
deque.offer(2);
deque.offer(3);
System.out.println(deque.peek()); // 1
System.out.println(deque.pop()); // 1
阻塞队列
阻塞队列—— BlockingQueue接口,也是常见的集合接口。其可以理解为支持两个附加操作的队列。(阻塞的插入与阻塞的移除)
方法 | 抛出异常 | 返回特殊值 | 一直阻塞 | 超时退出 |
---|---|---|---|---|
插入 | add(e) | offer(e) | put() | offer(e ,time,unit) |
移除 | remove() | poll() | take() | poll(time , unit) |
检查 | element() | peek() | / | / |
//测试
BlockingQueue<Integer> queue = new ArrayBlockingQueue<>(3);
for (int i = 0; i < 3; i++) {
queue.add(i);
}
// queue.add(4); Exception in thread "main" java.lang.IllegalStateException: Queue full
System.out.println(queue.offer(4)); //false
System.out.println(queue.offer(4,3,TimeUnit.SECONDS)); //3s后 返回false
queue.put(4); //线程被阻塞
java中常见的阻塞队列的实现类
1)ArrayBlockingQueue
构造器
//需要传入一个容量参数 、 默认为不保证线程公平的阻塞队列
public ArrayBlockingQueue(int capacity) {
this(capacity, false);
}
//可以指定参数——线程是否公平
public ArrayBlockingQueue(int capacity, boolean fair) {
if (capacity <= 0)
throw new IllegalArgumentException();
this.items = new Object[capacity];
lock = new ReentrantLock(fair); //通过可重入锁,来实现访问者的公平性
notEmpty = lock.newCondition(); //用于唤醒等待取出元素的线程
notFull = lock.newCondition(); //用于唤醒等待添加元素的线程
}
2)LinkedBlockingQueue
一般用于创建无界的阻塞队列,锁为非公平锁
// 提供了空参构造器 , 默认长度为int最大值
public LinkedBlockingQueue() {
this(Integer.MAX_VALUE);
}
3)PriorityBlokingQueue
支持优先级的无界阻塞队列
//默认按照自然排序升序排列
BlockingQueue<Integer> queue = new PriorityBlockingQueue<>();
queue.put(2);
queue.put(1);
System.out.println(queue.take()); // 1
4)SynchronousQueue
不存储元素的阻塞队列——每一个put 必须等待take操作
// 可以指定线程是否公平(默认非公平)
public SynchronousQueue() {
this(false);
}
应用场景 —— Executors.newCachedThreadPool() Cached线程池中,采用了此种阻塞队列
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
5)DelayQueue
支持延迟获取元素的阻塞队列(元素需实现Delayed接口,在后期关于线程池的文章中再具体解释)
底层通过PriorityBlokingQueue实现(例如,我们可以通过延迟时间进行排序)
6)LinkedTransferQueue
相较于其他阻塞队列,多了transfer方法与tryTransfer方法
前者,如果没有消费者接受,就继续阻塞,后者则立即返回(未接受就返回false)
/**
输出结果:true false 0
*/
public class LinkedTransferQueueDemo {
public static void main(String[] args) {
//创建一个阻塞队列
LinkedTransferQueue<Integer> queue = new LinkedTransferQueue<>();
//线程A用于获取元素
new Thread(() -> {
try {
System.out.println(queue.take());
} catch (InterruptedException e) {
e.printStackTrace();
}
},"A").start();
//线程B添加元素
new Thread(() -> {
for (int i = 0; i < 2; i++) {
System.out.println(queue.tryTransfer(i));
}
},"B").start();
}
}
7)LinkedBlockingDeque
与2类似,但为双端队列