美文网首页
Java并发-22.阻塞队列

Java并发-22.阻塞队列

作者: 悠扬前奏 | 来源:发表于2019-06-01 23:11 被阅读0次

阻塞队列(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实现:
    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阻塞当前线程

相关文章

网友评论

      本文标题:Java并发-22.阻塞队列

      本文链接:https://www.haomeiwen.com/subject/oaqvzqtx.html