Java中的阻塞队列基础
阻塞队列可以用于线程之间的通信,实现线程与线程之间的解耦。可用于简单的单服务中生成者消费者模式。
使用案例
模拟场景
发布重要通知后,需要进行钉钉消息通知
但实际上,这样会带来一些问题
- 正常发布通知接口只需要1s,添加发送钉钉消息逻辑后,变成了2s,效率下降。
- 强耦合,正常发布新闻通知,发送钉钉消息不是必须的过程,发送钉钉消息失败会导致发布通知失败。
原代码
public class NewsController {
public News push(String content){
News news = new News();
news.setTitle("content");
news.setContent("content");
System.out.println("发布新闻:" + content);
ddMsg(content);
return news;
}
public void ddMsg(String msg){
System.out.println("发送钉钉消息:" + msg);
}
public static void main(String[] args) {
NewsController newsController = new NewsController();
newsController.push("新闻1");
}
}
改造后先将消息推送到阻塞队列中,在从阻塞队列中获取到数据后,进行钉钉消息的发送,实现发布通知和发送钉钉消息的解耦。
改造后代码
public class NewsController {
private static ArrayBlockingQueue<String> blockingQueue = new ArrayBlockingQueue<String>(10);
private static boolean isRunning = true;
public News push(String content) throws InterruptedException {
News news = new News();
news.setTitle("content");
news.setContent("content");
System.out.println("发布新闻:" + content);
blockingQueue.put(content);
return news;
}
public void ddMsg(String msg){
System.out.println("发送钉钉消息:" + msg);
}
public static void main(String[] args) throws InterruptedException {
NewsController newsController = new NewsController();
new Thread(()->{
while (isRunning){
try {
newsController.ddMsg(blockingQueue.take());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
for (int i = 0; i < 11; i++) {
newsController.push("新闻" + i);
Thread.sleep(2000);
}
}
}
JUC中的阻塞队列
队列 | 作用 |
---|---|
ArrayBlockingQueue | 数组实现的阻塞队列,按照FIFO原则对元素进行排序 |
LinkedBlockingQueue | 链表实现的有界阻塞队列,默认和最大长度都为Integer.MAX_VALUE。此队列按照FIFO排序 |
PriorityBlockingQueue | 支持优先级排序,也可以自定义类实现CompareTo()方法指定排序规则 |
DelayQueue | 优先级队列实现的无界阻塞队列 |
SynchronousQueue | 不存储元素的阻塞队列,每一个put都必须等待有个take操作 |
LinkedTransferQueue | 链表实现的无界阻塞队列 |
LinkedBlockingDeque | 链表实现的双向阻塞队列 |
阻塞队列的基本操作方法
插入操作
- add 添加元素到队列,队列满了,继续插入抛异常
- offer 添加元素到队列,返回添加状态
- put 当队列满了后继续添加,生产者线程会被阻塞一定的时间,如果超时,则线程直接退出
移除操作
- remove 队列为空返回false ,移除成功返回true
- poll 队列中存在元素,则取出一个元素,为空则返回false,可设置等待时间
- take 基于阻塞的方式返回队列中的元素,如果队列为空,则take方法会一直阻塞,直到队列中有新数据可以消费