4 阻塞/非阻塞队列

阻塞队列是具有阻塞功能的队列,通常一端放入生产者数据,另一端供消费者消费数据。阻塞队列是线程安全的。

阻塞队列,我们主要关注阻塞方法(put/take)、是否有界、与线程池关系。

BlockingQueue的三组方法

  1. put,take :会阻塞住
  2. add,remove,element:会抛出异常
  3. offer,poll,peek:会返回boolean值,取值是没有值会返回null

4.1 常见的阻塞队列

1 ArrayBlockingQueue 有界阻塞队列

ArrayBlockingQueue的特点是有界、可以指定容量、能够指定是否需要保证公平。

put方法源码

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();
    }
}

2 LinkedBlockingQueue

特点是无界、默认容量是Integer.MAX_VALUE、内部结构(Node、有两把锁)。

public void put(E e) throws InterruptedException { 
    if (e == null) throw new NullPointerException();
    int c = -1;
    Node<E> node = new Node<E>(e);
    final ReentrantLock putLock = this.putLock;
    final AtomicInteger count = this.count;
    putLock.lockInterruptibly();
    try { 
        while (count.get() == capacity) { 
            notFull.await();
        }
        enqueue(node);
        c = count.getAndIncrement();
        if (c + 1 < capacity)
            notFull.signal();
    } finally { 
        putLock.unlock();
    }
    if (c == 0)
        signalNotEmpty();
}

3 PriorityBlockingQueue:支持优先级、自然顺序、无界队列

4 SynchronousQueue

特点:容量为0,队列不持有元素,直接传递,效率很高。是很好的用来直接传递的并发数据结构。

5 DelayQueue 延迟队列,根据延迟时间排序

4.2 非阻塞队列

并发包中非阻塞队列只有ConcurrentLinkedQueue,以链表作为数据结构,采用CAS思想实现线程安全,适用于对性能要求较高的并发场景。使用较少。源码参考offer方法。

4.3 阻塞队列的选择

选择队列,需要根据实际场景选择。

  1. 首先考虑功能方面,例如需要优先级排序、延迟执行等。
  2. 再就是容量,是容量固定,还是无界,还是不需要容量。ArrayBlockingQueue不能扩容。
  3. 内存结构:例如ArrayBlockingQueue底层是数组,而LinkedBlockingQueue内部用链表实现,会生成很多node。
  4. 吞吐量:LinkedBlockingQueue 由于拥有两把锁,它的操作粒度更细,在并发程度高的时候,相对于只有一把锁的 ArrayBlockingQueue 性能会更好。SynchronousQueue直接传递,性能往往优于其他实现。

本文地址:https://blog.csdn.net/LIZHONGPING00/article/details/114298441