Java 阻塞队列

BlockingQueue

在阻塞队列中线程阻塞有两种情况:
1、当队列中没有数据的情况下,消费者端的所有线程都会被自动阻塞(挂起),直到有数据放入队列。
2、当队列中填满数据的情况下,生产者端的所有线程都会被自动阻塞(挂起),直到队列中有空的位置,线程被自动唤醒。

阻塞队列对插入、移除、获取元素操作提供了四种不同的方法用于不同的场景中使用:
1、抛出异常;
2、返回特殊值(null 或 false,取决于具体的操作);
3、阻塞等待此操作,直到这个操作成功;
4、阻塞并且给一个超时时间。

Throws exception Special value Blocks Times out
Insert add(e) offer(e) put(e) offer(e,time,unit)
Remove remove() poll() take() poll(time,unit)
Examine element() peek() not applicable not applicable

BlockingQueue 不接受 null 值的插入,否则会抛 NPE 异常。

BlockingQueue 是设计用来实现生产者-消费者队列的,当然也可以将它当作普通的集合来使用,因为它继承了 Collection 接口。
Java 阻塞队列_第1张图片
BlockingQueue 的实现都是线程安全的,但是批量的集合操作如:addAllcontainsAllretainAllremoveAll不一定是原子操作。如 addAll(c) 有可能在添加了一些元素后中途抛出异常,此时 BlockingQueue 中已经添加了部分元素,这个是允许的,取决于具体的实现。

下面是阻塞队列的实现类
Java 阻塞队列_第2张图片

ArrayBlockingQueue(公平、非公平)

用数组实现的有界阻塞队列。此队列按照 FIFO 的原则对元素进行排序;默认情况不保证访问者公平的访问队列,所谓公平访问队列是指阻塞的所有生产者线程或消费者线程,当队列可用时,可以按照阻塞的先后顺序访问队列。通常情况下为了保证公平性会降低吞吐量。
Java 阻塞队列_第3张图片

LinkedBlockingQueue(两个独立锁提高并发)

基于链表的阻塞队列,同 ArrayBlockingQueue 类似,此队列按照 FIFO 的原则对元素进行排序。而 LinkedBlockingQueue 之所以能够高效的处理并发数据,还因为对于生产者和消费者分别采用了独立的锁来控制数据同步,这也意味着高并发的情况下生产者和消费者可以并行地操作队列中的数据,以此来提高整个队列的并发性能。
Java 阻塞队列_第4张图片

SynchronousQueue(不存储数据、可用于传递数据)

是一个不存储元素的阻塞队列。每一个 put 操作必须等待一个 take 操作,否则不能继续添加元素。SynchronousQueue 可以看成是一个传球手,负责把生产者线程处理的数据直接传递给消费者线程。队列本身并不存储任何元素,非常适合于传递性场景,比如在一个线程中使用的数据,传递给另 外 一 个 线 程 使 用 ,SynchronousQueue 的 吞 吐 量 高 于 LinkedBlockingQueue 和 ArrayBlockingQueue。

PriorityBlockingQueuee(compareTo 排序实现优先)

是一个支持优先级的无界阻塞队列。默认情况下元素采取自然顺序升序排列。可以自定义实现 compareTo() 方法来指定元素进行排序规则,或者初始化 PriorityBlockingQueue 时,指定构造参数 Comparator 来对元素进行排序。需要注意的是不能保证同优先级元素的顺序。

/**
 * Lock used for all public operations
 */
private final ReentrantLock lock;

/**
 * Condition for blocking when empty
 */
private final Condition notEmpty;

/**
 * Spinlock for allocation, acquired via CAS.
 * 用于数组扩容
 */
private transient volatile int allocationSpinLock;

你可能感兴趣的:(多线程)