Java并发-BlockingQueue


  • BlockingQueue和JDK集合包中的Queue接口兼容,同时在其基础上增加了阻塞功能
    • offer(E e):如果队列没满,返回true,如果队列已满,返回false(不阻塞)
    • offer(E e, long timeout, TimeUnit unit):可以设置阻塞时间,如果队列已满,则进行阻塞。超过阻塞时间,则返回false
    • put(E e):队列没满的时候是正常的插入,如果队列已满,则阻塞,直至队列空出位置
    • poll():如果有数据,出队,如果没有数据,返回null   (不阻塞)
    • poll(long timeout, TimeUnit unit):可以设置阻塞时间,如果没有数据,则阻塞,超过阻塞时间,则返回null
    • take():队列里有数据会正常取出数据并删除;但是如果队列里无数据,则阻塞,直到队列里有数据
  • ArrayBlockingQueue 基于数组的有界阻塞队列
    • 利用 ReentrantLock 实现线程安全(只能有一个线程可以进行入队或者出队操作)
    • 利用了Lock锁的Condition通知机制进行阻塞控制(notEmpty、notFull)
  • LinkedBlockingQueue 基于单链表的无界阻塞队列
    • 读写分离(只能从head取元素,从tail添加元素):采用两把锁(putLock、takeLock)的锁分离技术实现入队出队互不阻塞
  • SynchronousQueue 没有数据缓冲(容量为0)的 BlockingQueue :它所做的就是直接传递
    • 每次取数据都要先阻塞,直到有数据被放入
    • 每次放数据的时候也会阻塞,直到有消费者来取
  • PriorityBlockingQueue 基于数组(二叉堆)的无界优先级阻塞队列(默认长度是11,虽然指定了数组的长度,但是可以无限的扩充)
    • 每次出队都返回优先级别最高的或者最低的元素(不能保证同优先级元素的顺序)
    • 默认情况下元素采用自然顺序升序排序(也可以通过构造函数来指定Comparator来对元素进行排序)
  • DelayQueue 基于优先队列 PriorityQueue 的支持延时获取元素的无界队阻塞队列
    • 元素必须实现 Delayed 接口( Delayed 接口又继承了 Comparable 接口)
    • 在创建元素时可以指定多久才可以从队列中获取当前元素,只有在延迟期满时才能从队列中提取元素
    • 按照延迟时间的长短来排序,下一个即将执行的任务会排到队列的最前面
    • 获取元素,先获取到锁对象,然后获取最早过期的元素(但是并不从队列中弹出元素)
      • 判断最早过期元素是否为空(如果为空则直接让当前线程无限期等待状态,并且让出当前锁对象)
      • 如果不为空:获取最早过期元素的剩余过期时间(如果已经过期则直接返回当前元素)
      • 如果没有过期(剩余时间还存在),则先获取Leader对象,如果Leader已经有线程在处理,则当前线程进行无限期等待,如果Leader为空,则首先将Leader设置为当前线程,并且让当前线程等待剩余时间
      • 最后将Leader线程设置为空,并且队列有内容则唤醒一个等待的队列
  • 线程池对于阻塞队列的选择
    • FixedThreadPool(SingleThreadExecutor 同理)选取的是 LinkedBlockingQueue
    • CachedThreadPool 选取的是 SynchronousQueue
    • ScheduledThreadPool(SingleThreadScheduledExecutor同理)选取的是延迟队列
  • 选择策略:
    • 功能 PriorityBlockingQueue 优先级;DelayQueue 延时
    • 容量:SynchronousQueue 容量是0;DelayQueue 容量是Integer.MAX_VALUE
    • 能否扩容:ArrayBlockingQueue 不能扩容;PriorityBlockingQueue 可以动态扩容
    • 内存结构:ArrayBlockingQueue 数组的空间利用率更高
    • 性能:LinkedBlockingQueue 读写分离;SynchronousQueue 直接传递

文章作者: 钱不寒
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 钱不寒 !
  目录