前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java并发-22.阻塞队列

Java并发-22.阻塞队列

作者头像
悠扬前奏
发布2019-06-02 15:04:13
3630
发布2019-06-02 15:04:13
举报

阻塞队列(BlockingQueue)是一种支持两个附加操作的队列:

  • 支持阻塞的插入:队列满时,队列阻塞插入元素的线程,直到队列不满
  • 支持阻塞的溢出:队列空时,获取元素的线程等待队列变为非空 常见于生产者和消费者场景
  • 阻塞队列不可用后,有四种处理方式:

处理方式

抛出异常

返回特殊值

一直阻塞

超时退出

插入方法

add(e)

offer(e)

put(e)

offer(e, time,unit)

移除方法

remoe(e)

poll()

take()

poll(time, unit)

检查方法

element()

peek()

不可用

不可用

  • 抛出异常:插入抛出IllegalStateException(); 获取抛出NoSuchElementException
  • 返回特殊值,插入成功返回true;移除,有就取出,没有返回null
  • 一直阻塞
  • 超时退出

无界阻塞队列永远不满,put和offer方法永远不阻塞,offer永远返回true

1、 Java中的阻塞队列

Java中有7中阻塞队列:

  • ArrayBlockingQueue:数组结构的有界阻塞队列
    • FIFO排序
    • 默认不保证公平访问
    • 设置公平访问用可重入锁实现的,会降低吞吐量
  • LinkedBlockingQueue:链表结构的有界阻塞队列
    • 默认和最大长度为Integer.MAX_VALUE
    • FIFO排序
  • PriorityBlockingQueue:支持优先级排序的无界阻塞队列
    • 默认自然排序,可自定义compareTo()方法,或初始化时指定构造餐宿Comparator指定排序,
    • 不能保证同优先级元素的顺序
  • DelayQueue:使用优先级队列实现的无界阻塞队列
    • 支持延时获取元素
    • 用PriorityQueue实现
    • 队列中元素必须实现Delay接口
      • 创建对象时初始化基本数据
      • 实现getDelay方法,返回元素还需要延长多长时间,单位纳秒
      • 实现compareTo方法指定元素顺序
    • 创建元素时可以指定多久才能获取当前元素
      • 元素没有达到延时时间就阻塞当前线程
  • SynchronousQueue:不存储元素的阻塞队列
    • 一个put操作必须等待一个take操作,否则不能添加元素
    • 默认非公平
    • 支持公平访问
    • 吞吐量高于ArrayBlockingQueue和LinkedBlockingQueue
  • LinkedTransferQueue:链表结构的无界阻塞队列
    • 多了transfer方法:如果有消费者等待,把生产者传入的元素直接传输过去;如果没有等待,把元素存放在tail节点,直到被消费才返回
    • 多了tryTransfer方法:试探能否直接传给消费者,如果没有消费者等待,返回false。默认立即返回,可以调用重构的方法,超时等待。
  • LinkedBlockingDeque:链表结构的双向阻塞队列 -多了addLast,offerFirst,offerLast,peekFirst,peekLast等双向队列特有的方法。

2、 阻塞队列实现原理

  • 通知模式:ArrayBlockingQueue用了Condition实现:
代码语言:javascript
复制
    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();
    }
    public void put(E e) throws InterruptedException {
        checkNotNull(e);
        final ReentrantLock lock = this.lock;
        lock.lockInterruptibly();
        try {
            while (count == items.length)
                notFull.await();
            enqueue(e);
        } finally {
            lock.unlock();
        }
    }
    public E take() throws InterruptedException {
        final ReentrantLock lock = this.lock;
        lock.lockInterruptibly();
        try {
            while (count == 0)
                notEmpty.await();
            return dequeue();
        } finally {
            lock.unlock();
        }
    }
  • 往队列插入元素,队列不可用,通过LockSupport.park(this)来阻塞生产者
  • 调用setBlocker前先保存将要阻塞的线程,然后unsafe.park阻塞当前线程
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019.06.01 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1、 Java中的阻塞队列
  • 2、 阻塞队列实现原理
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档