一、阻塞队列

当阻塞队列是空,从队列中获取元素的操作会被阻塞

当阻塞队列是满,往队列中添加元素的操作会被阻塞

二、为什么用,有什么好处?

我们不需要关心什么时候需要阻塞线程,什么时候需要唤醒线程,因为这一切阻塞队列都包办了。

三、常见的阻塞队列

ArrayBlockingQueue由数组构成的有界阻塞队列.

LinkedBlockingQueue由链表构成的有界阻塞队列(默认值为Integer.MAX_VALUE)

  1. public class BlockingQueueDemo {
  2.  
  3. public static void main(String[] args) throws InterruptedException {
  4. BlockingQueue<String> blockingQueue = new ArrayBlockingQueue<String>(3);
  5. /**
  6. * 1、抛出异常 add()/remove()
  7. */
  8. // System.out.println(blockingQueue.add("a"));
  9. // System.out.println(blockingQueue.add("b"));
  10. // System.out.println(blockingQueue.add("c"));
  11. // System.out.println(blockingQueue.add("d"));
  12.  
  13. // System.out.println(blockingQueue.element()); //检查队首元素
  14.  
  15. // System.out.println(blockingQueue.remove());
  16. // System.out.println(blockingQueue.remove());
  17. // System.out.println(blockingQueue.remove());
  18. // System.out.println(blockingQueue.remove());
  19.  
  20. /**
  21. * 2、返回布尔类型 offer()/pull()
  22. */
  23. // System.out.println(blockingQueue.offer("a"));
  24. // System.out.println(blockingQueue.offer("b"));
  25. // System.out.println(blockingQueue.offer("c"));
  26. // System.out.println(blockingQueue.offer("d"));
  27. //
  28. // System.out.println(blockingQueue.peek()); //检查队首元素
  29. //
  30. // System.out.println(blockingQueue.poll());
  31. // System.out.println(blockingQueue.poll());
  32. // System.out.println(blockingQueue.poll());
  33. // System.out.println(blockingQueue.poll());
  34.  
  35. /**
  36. * 3、阻塞 put()/take()
  37. */
  38. // blockingQueue.put("a");
  39. // blockingQueue.put("b");
  40. // blockingQueue.put("c");
  41. // System.out.println("############");
  42. // blockingQueue.put("d");
  43. //
  44. // System.out.println(blockingQueue.take());
  45. // System.out.println(blockingQueue.take());
  46. // System.out.println(blockingQueue.take());
  47. // System.out.println(blockingQueue.take());
  48.  
  49. /**
  50. *4、超时
  51. */
  52.  
  53. System.out.println(blockingQueue.offer("a",2L, TimeUnit.SECONDS));
  54. System.out.println(blockingQueue.offer("b",2L, TimeUnit.SECONDS));
  55. System.out.println(blockingQueue.offer("c",2L, TimeUnit.SECONDS));
  56. System.out.println(blockingQueue.offer("d",2L, TimeUnit.SECONDS));
  57. }
  58. }

SynchronousQueue是一个不存储元素的阻塞队列,也即单个元素的队列

  1. public class SynchronousQueueDemo {
  2. public static void main(String[] args) {
  3. BlockingQueue<String> blockingQueue = new SynchronousQueue<>();
  4.  
  5. new Thread(() -> {
  6. try {
  7. System.out.println(Thread.currentThread().getName() + " put 1");
  8. blockingQueue.put("1");
  9.  
  10. System.out.println(Thread.currentThread().getName() + " put 2");
  11. blockingQueue.put("2");
  12.  
  13. System.out.println(Thread.currentThread().getName() + " put 3");
  14. blockingQueue.put("3");
  15. } catch (InterruptedException e) {
  16. e.printStackTrace();
  17. }
  18. }, "AAA").start();
  19.  
  20. new Thread(() -> {
  21. try {
  22.  
  23. TimeUnit.SECONDS.sleep(2);
  24. System.out.println(Thread.currentThread().getName() + " take " + blockingQueue.take());
  25.  
  26. TimeUnit.SECONDS.sleep(2);
  27. System.out.println(Thread.currentThread().getName() + " take " + blockingQueue.take());
  28.  
  29. TimeUnit.SECONDS.sleep(2);
  30. System.out.println(Thread.currentThread().getName() + " take " + blockingQueue.take());
  31.  
  32. } catch (InterruptedException e) {
  33. e.printStackTrace();
  34. }
  35. }, "BBB").start();
  36. }
  37. }  

PriorityBlockingQueue:支持优先级排序的无界阻塞队列

DelayQueue:使用优先级队列实现的延迟无界阻塞队列

LinkedTransferQueue:由链表构成的无界阻塞队列

LinkedBlockingDeque:由链表构成的双向阻塞队列

四、BlockQueue的核心方法

add()/remove()/element():抛出异常

offer()/pull():返回布尔类型/支持超时

put()/take():阻塞

peek() 检查队列首元素

五、使用场景

1、生产者-消费者模式

问题: 一个初始值为零的变量,两个线程对其交替操作,一个加1一个减1,来5轮

1)传统版的生产者-消费者模式

  1. /**
  2. * Created by wujuhong on 2019/7/3.
  3. * 传统版的生产者消费者模式
  4. */
  5. public class ProductConsumer_TraditionDemo {
  6.  
  7. public static void main(String[] args) {
  8. ShareData shareData = new ShareData();
  9. new Thread(() -> {
  10. for (int i = 0; i < 5; i++) {
  11. try {
  12. shareData.increment();
  13. } catch (InterruptedException e) {
  14. e.printStackTrace();
  15. }
  16. }
  17. }, "AA").start();
  18.  
  19. new Thread(() -> {
  20. for (int i = 0; i < 5; i++) {
  21. try {
  22. shareData.decrement();
  23. } catch (InterruptedException e) {
  24. e.printStackTrace();
  25. }
  26. }
  27. }, "BB").start();
  28. }
  29. }
  30.  
  31. class ShareData {
  32. private int number = 0;
  33. private Lock lock = new ReentrantLock();
  34. private Condition condition = lock.newCondition();
  35.  
  36. public void increment() throws InterruptedException {
  37. lock.lock();
  38. try {
  39. //1、判断
  40. while (number != 0) {
  41. //等待,不能生产
  42. condition.await();
  43. }
  44. //2、干活
  45. number++;
  46. System.out.println(Thread.currentThread().getName() + " " + number);
  47. //3、通知唤醒
  48. condition.signalAll();
  49.  
  50. } finally {
  51. lock.unlock();
  52. }
  53. }
  54.  
  55. public void decrement() throws InterruptedException {
  56. lock.lock();
  57. try {
  58. //1、判断
  59. while (number == 0) {
  60. //等待,不能生产
  61. condition.await();
  62. }
  63. //2、干活
  64. number--;
  65. System.out.println(Thread.currentThread().getName() + " " + number);
  66. //3、通知唤醒
  67. condition.signalAll();
  68.  
  69. } finally {
  70. lock.unlock();
  71. }
  72. }
  73. }

  2)阻塞队列的生产者-消费者模式

  1. class MyResource {
  2. private volatile boolean FLAG = true; //默认生产,进行生产+消费
  3. private AtomicInteger atomicInteger = new AtomicInteger();
  4. BlockingQueue<String> blockingQueue = null;
  5.  
  6. public MyResource(BlockingQueue<String> blockingQueue) {
  7. this.blockingQueue = blockingQueue;
  8. System.out.println(blockingQueue.getClass().getName());
  9. }
  10.  
  11. public void myProduct() throws InterruptedException {
  12. String data = "";
  13. boolean returnValue;
  14. while (FLAG) {
  15. data = atomicInteger.incrementAndGet() + "";
  16. returnValue = blockingQueue.offer(data, 2, TimeUnit.SECONDS);
  17. if (returnValue) {
  18. System.out.println(Thread.currentThread().getName() + " 插入队列" + data + "成功");
  19. } else {
  20. System.out.println(Thread.currentThread().getName() + " 插入队列" + data + "失败");
  21.  
  22. }
  23. TimeUnit.SECONDS.sleep(1);
  24. }
  25. System.out.println(Thread.currentThread().getName() + " 生产动作结束,FLAG = false");
  26. }
  27.  
  28. public void myConsume() throws InterruptedException {
  29. String result = "";
  30. while (FLAG) {
  31. result = blockingQueue.poll(2, TimeUnit.SECONDS);
  32. if (null == result || result.equalsIgnoreCase("")) {
  33. FLAG = false;
  34. System.out.println(Thread.currentThread().getName() + " 超过2s钟没有取到蛋糕,消费队列退出");
  35. return;
  36.  
  37. }
  38. System.out.println(Thread.currentThread().getName() + " 消费队列" + result + "成功");
  39.  
  40. TimeUnit.SECONDS.sleep(1);
  41. }
  42. System.out.println(Thread.currentThread().getName() + " 消费动作结束,FLAG = false");
  43. }
  44.  
  45. public void stop() {
  46. this.FLAG = false;
  47. }
  48. }
  49.  
  50. public class ProductConsumer_BlockQueueDemo {
  51. public static void main(String[] args) throws InterruptedException {
  52. MyResource myResource = new MyResource(new ArrayBlockingQueue<String>(10));
  53. new Thread(() -> {
  54. System.out.println(Thread.currentThread().getName() + " 生产线程启动");
  55. try {
  56. myResource.myProduct();
  57. } catch (InterruptedException e) {
  58. e.printStackTrace();
  59. }
  60. }, "product").start();
  61.  
  62. new Thread(() -> {
  63. System.out.println(Thread.currentThread().getName() + " 消费线程启动");
  64. try {
  65. myResource.myConsume();
  66. } catch (InterruptedException e) {
  67. e.printStackTrace();
  68. }
  69. }, "consume").start();
  70.  
  71. TimeUnit.SECONDS.sleep(5);
  72.  
  73. System.out.println("5秒钟时间到,main线程叫停,活动结束");
  74.  
  75. myResource.stop();
  76. }
  77. }  

2、线程池

3、消息中间件

阻塞队列有没有好的一面?

不得不阻塞,你如何管理?

java面试-阻塞队列的更多相关文章

  1. Java多线程 阻塞队列和并发集合

    转载:大关的博客 Java多线程 阻塞队列和并发集合 本章主要探讨在多线程程序中与集合相关的内容.在多线程程序中,如果使用普通集合往往会造成数据错误,甚至造成程序崩溃.Java为多线程专门提供了特有的 ...

  2. Java集合--阻塞队列及各种实现的解析

    阻塞队列(Blocking Queue) 一.队列的定义 说的阻塞队列,就先了解下什么是队列,队列也是一种特殊的线性表结构,在线性表的基础上加了一条限制:那就是一端入队列,一端出队列,且需要遵循FIF ...

  3. Java:阻塞队列

    Java:阻塞队列 本笔记是根据bilibili上 尚硅谷 的课程 Java大厂面试题第二季 而做的笔记 1. 概述 概念 队列 队列就可以想成是一个数组,从一头进入,一头出去,排队买饭 阻塞队列 B ...

  4. JAVA可阻塞队列-ArrayBlockingQueue

    在前面的的文章,写了一个带有缓冲区的队列,是用JAVA的Lock下的Condition实现的,但是JAVA类中提供了这项功能,就是ArrayBlockingQueue, ArrayBlockingQu ...

  5. java 可伸缩阻塞队列实现

    最近一年多写的最虐心的代码.必须好好复习java并发了.搞了一晚上终于测试都跑通过了,特此纪念,以资鼓励! import java.util.ArrayList; import java.util.L ...

  6. java 多线程阻塞队列 与 阻塞方法与和非阻塞方法

    Queue是什么 队列,是一种数据结构.除了优先级队列和LIFO队列外,队列都是以FIFO(先进先出)的方式对各个元素进行排序的.无论使用哪种排序方式,队列的头都是调用remove()或poll()移 ...

  7. Java -- 使用阻塞队列(BlockingQueue)控制线程通信

    BlockingQueeu接口是Queue的子接口,但是它的主要作用并不是作为容器,而是作为线程同步的工具. 特征: 当生产者线程试图向BlockingQueue中放入元素时,如果该队列已满,则该线程 ...

  8. Java并发--阻塞队列

    在前面几篇文章中,我们讨论了同步容器(Hashtable.Vector),也讨论了并发容器(ConcurrentHashMap.CopyOnWriteArrayList),这些工具都为我们编写多线程程 ...

  9. Java中阻塞队列的使用

    http://blog.csdn.net/qq_35101189/article/details/56008342 在新增的Concurrent包中,BlockingQueue很好的解决了多线程中,如 ...

随机推荐

  1. how to change svg polygon size by update it's points in js

    how to change svg polygon size by update it's points in js matrixTransform https://stackoverflow.com ...

  2. PAUL ADAMS ARCHITECT:薪资追不上房价美一半家庭难买房

    尽管上一年度美国经济遭受重创,但美国房价依旧持续蹿扬,据最新调查显示,美国大部分地区的房价已经到了一般家庭无法负担的水准. 美国房价上涨持续强劲,主要受益美国人居家办公需求(受大环境影响,目前美国有7 ...

  3. 人物传记Kyle Tedford:数据环境生变,银行大数据风控怎么办?

    数据是金融业务的基石,监管集中清查大数据公司,很多东西在发生根本性改变,资金方做"甩手掌柜"的好日子不会重现.那些缺乏自主风控能力的金融机构,在未来的行业竞争中,恐无以立足了.近日 ...

  4. Windows Server2012 r2 nginx反向代理图片服务器

    1.下载nginx  http://nginx.org/en/download.html,本人下载的1.18.0版本 2.下载 Windows Service Wrapper(winsw.exe) v ...

  5. 内核栈与thread_info结构详解

    本文转载自内核栈与thread_info结构详解 什么是进程的内核栈? 在内核态(比如应用进程执行系统调用)时,进程运行需要自己的堆栈信息(不是原用户空间中的栈),而是使用内核空间中的栈,这个栈就是进 ...

  6. Redis 日志篇:系统高可用的杀手锏

    特立独行是对的,融入圈子也是对的,重点是要想清楚自己向往怎样的生活,为此愿意付出怎样的代价. 我们通常将 Redis 作为缓存使用,提高读取响应性能,一旦 Redis 宕机,内存中的数据全部丢失,假如 ...

  7. 换人!golang面试官:连怎么避免内存逃逸都不知道?

    问题 怎么避免内存逃逸? 怎么答 在runtime/stubs.go:133有个函数叫noescape.noescape可以在逃逸分析中隐藏一个指针.让这个指针在逃逸分析中不会被检测为逃逸. // n ...

  8. hive复杂数据类型的用法

    目录 1.简单描述 2.测试 1.简单描述 arrays: ARRAY<data_type> maps: MAP<primitive_type, data_type> stru ...

  9. redis.conf 配置说明

    redis.conf 配置项说明如下: 1. Redis默认不是以守护进程的方式运行,可以通过该配置项修改,使用yes启用守护进程 daemonize no 2. 当Redis以守护进程方式运行时,R ...

  10. Element 文档中的 Markdown 解析

    Element 的文档站是讲Markdown解析成vue组件在页面中渲染出来,转换过程如下图所示: 红框部分势必要对 Markdown 进行特殊的订制,订制过的 Markdown 像下面这样. ::: ...