队列 : FIFO 遵循先进先出原则
- 写入: 如果队列满了,就必须阻塞等待消费
- 取出: 如果队列是空的,必须阻塞等待生产
阻塞队列 BlockingQueue : 不是新的东西
具体的家族关系:
JDK文档说明
重点使用的实现类:
- ArrayBlockingQueue 数组
- LinkedBlockingQueue 列表
- SynchronousQueue 同步队列
什么情况下会使用阻塞队列?
- 多线程
- 线程池
如何使用队列?
BlockingQueue 有四组API :
- 抛出异常
- 抛出异常
- 阻塞等待
- 超时等待
方法 | 抛出异常 | 有返回值(不抛异常) | 阻塞等待 | 超时等待 |
---|---|---|---|---|
添加 | add() | offer() | put() | offer(e,Long,TimeUnit) |
移除 | remove() | poll() | take() | poll(Long,TimeUnit) |
查找队首元素 | element() | peek() |
/**
* 抛出异常
*/
public static void test1() {
// 队列大小
ArrayBlockingQueue blockingQueue = new ArrayBlockingQueue<>(3);
System.out.println(blockingQueue.add("a"));
System.out.println(blockingQueue.add("b"));
System.out.println(blockingQueue.add("c"));
System.out.println("===============");
// java.lang.IllegalStateException 队列已满 抛出异常
//System.out.println(blockingQueue.add("d"));
System.out.println(blockingQueue.remove());
System.out.println(blockingQueue.remove());
System.out.println(blockingQueue.remove());
// java.util.NoSuchElementException 抛出异常
System.out.println(blockingQueue.remove());
}
/**
* 有返回值(不抛出异常)
*/
public static void test2() {
// 队列大小
ArrayBlockingQueue blockingQueue = new ArrayBlockingQueue<>(3);
System.out.println(blockingQueue.offer("a"));
System.out.println(blockingQueue.offer("b"));
System.out.println(blockingQueue.offer("c"));
System.out.println(blockingQueue.offer("d")); // 返回 false
System.out.println("========================");
System.out.println(blockingQueue.poll());
System.out.println(blockingQueue.poll());
System.out.println(blockingQueue.poll());
System.out.println(blockingQueue.poll()); // 返回null
}
/**
* 阻塞等待
*/
public static void test4() {
// 队列大小
ArrayBlockingQueue blockingQueue = new ArrayBlockingQueue<>(3);
try {
blockingQueue.put("a");
blockingQueue.put("b");
blockingQueue.put("c");
// blockingQueue.put("d"); // 队列没有位置 阻塞 直接卡死
System.out.println("==============");
System.out.println(blockingQueue.take());
System.out.println(blockingQueue.take());
System.out.println(blockingQueue.take());
System.out.println(blockingQueue.take()); // 阻塞
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/**
* 超时等待
*/
public static void test3() throws InterruptedException {
// 队列大小
ArrayBlockingQueue blockingQueue = new ArrayBlockingQueue<>(3);
System.out.println(blockingQueue.offer("a"));
System.out.println(blockingQueue.offer("b"));
System.out.println(blockingQueue.offer("c"));
System.out.println(blockingQueue.offer("d", 2, TimeUnit.SECONDS));
System.out.println("=============");
System.out.println(blockingQueue.poll());
System.out.println(blockingQueue.poll());
System.out.println(blockingQueue.poll());
System.out.println(blockingQueue.poll(2,TimeUnit.SECONDS));
}
SynchronousQueue 同步队列
SynchronousQueue 同步队列并没有容量 默认为 1 !
-
当我们往同步队列放入一个元素,必须等待该元素被取出来之后,才能继续往同步队列里面放元素
-
和阻塞队列BlockingQueue不一样,SynchronousQueue无法存储元素
put() 之后,必须先使用take()将元素取出,否则不能再put()元素进去
package com.liu.bq;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.TimeUnit;
/**
* 同步队列
* put()完元素之后,必须要先取出,才能继续往里面put()
* take()
*/
public class SynchronousQueueTest {
public static void main(String[] args) {
BlockingQueue<String> queue = new SynchronousQueue<>();
// put元素
new Thread(()->{
try {
System.out.println(Thread.currentThread().getName() + " put 1");
queue.put("1");
TimeUnit.SECONDS.sleep(1);
System.out.println(Thread.currentThread().getName() + " put 2");
queue.put("2");
TimeUnit.SECONDS.sleep(1);
System.out.println(Thread.currentThread().getName() + " put 3");
queue.put("3");
} catch (InterruptedException e) {
e.printStackTrace();
}
},"T1").start();
// take元素
new Thread(()->{
try {
TimeUnit.SECONDS.sleep(3);
System.out.println(Thread.currentThread().getName() + " take => " + queue.take());
TimeUnit.SECONDS.sleep(3);
System.out.println(Thread.currentThread().getName() + " take => " + queue.take());
TimeUnit.SECONDS.sleep(3);
System.out.println(Thread.currentThread().getName() + " take => " + queue.take());
} catch (InterruptedException e) {
e.printStackTrace();
}
},"T2").start();
}
}