Source: source code analysis BlockingQueue implementation class

ThreadPoolExecutor use in the implementation of the BlockingQueue as a work queue, and today we learn about the relevant source code, look at the focus ArrayBlockingQueue, LinkedBlockingQueue achieve these two queues. This article largely from these two articles are interested can directly see the original: LinkedBlockingQueue source code analysis and ArrayBlockingQueue source code analysis . First look at the main BlockingQueue inheritance, as shown below:

Address look-standard reference.

First of all, the most basic terms, BlockingQueue is a FIFO queue (Queue), why is blocked (Blocking) it? Because BlockingQueue get support when elements of the queue but the queue is empty, it will block waiting queue has elements back; then put the time also supports adding an element, if the queue is full, it can be placed in a queue until a new element when. BlockingQueue is an interface, inherited from the Queue, so its implementation class can also be used as an implementation of the Queue, and Queue also inherited from the Collection interface.

BlockingQueue not accept the insertion of a null value, a corresponding method in the face of the inserted null a NullPointerException is thrown. null value as used herein generally special value (third column in the table), that failures poll. So, if you insert a null value is allowed, then when it is retrieved, it is not well used to determine in the end is null for failure, or a null value is the value obtained.

A BlockingQueue may be bounded, if inserted, it finds the queue is full, put the operation will be blocked. In general, we are talking about here is not to say unbounded queue truly unbounded, but its capacity is Integer.MAX_VALUE (21 Yi much).

BlockingQueue is designed to achieve producer - consumer queue, of course, you can also use it as a normal Collection to use, said earlier that implements java.util.Collection interface. For example, we can remove (x) to remove any element, however, this type of operation is usually not efficient, so try to use only a few occasions, such a message has been into the team, but needs to be done to cancel the operation time.

BlockingQueue achieve are thread-safe, but the bulk of the collection operations as addAll, containsAll, retainAll and removeAll are not necessarily atomic operation. The addAll (c) it is possible to add some elements after the middle of an exception is thrown, then BlockingQueue some elements have been added, this is permissible, depending on the particular implementation.

BlockingQueue not support close or shutdown shut down operations because developers may wish to not have new elements added to it, this feature depends on your implementation, not to enforce the constraint.

Finally, BlockingQueue the producer - consumer scenario, is a multi-multi producers and consumers, in fact, say the thread-safety issues.

ArrayBlockingQueue分析

1. Core Properties

// 底层维护队列元素的数组(注意是循环数组)
final Object[] items;

// 当读取元素时数组的下标(这里称为读下标)
int takeIndex;

// 添加元素时数组的下标 (这里称为写小标)
int putIndex;

// 队列中的元素个数
int count;

// 用于并发控制的重入锁(获取元素、添加元素全局使用同一把锁)
final ReentrantLock lock;

// 控制take操作时是否让线程等待的条件(队列非空)
private final Condition notEmpty;

// 控制put操作时是否让线程等待的条件(队列非满)
private final Condition notFull;


2. Constructor

public ArrayBlockingQueue(int capacity) { // 指定容量,采用默认的非公平锁
    this(capacity, false);
}

// 指定容量,指定使用公平锁或非公平锁
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 ArrayBlockingQueue(int capacity, boolean fair, Collection<? extends E> c) {
    this(capacity, fair); // 调用第二个构造函数,先初始化

    final ReentrantLock lock = this.lock;
    lock.lock(); // Lock only for visibility, not mutual exclusion 获得锁
    try {
        int i = 0;
        try {
            for (E e : c) {
                checkNotNull(e);
                items[i++] = e; // 集合c的元素入队列
            }
        } catch (ArrayIndexOutOfBoundsException ex) {
            throw new IllegalArgumentException();
        }
        count = i; // 更新count
        putIndex = (i == capacity) ? 0 : i; // 更新putIndex
    } finally {
        lock.unlock(); // 释放锁
    }
}


Method (enqueue, add / offer / put) 3. additive element
(1) add (e) / offer (e) - nonblocking
add (e) method is invoked method offer the bottom (non-blocking).

// 添加成功返回true,失败(队列已满)抛出IllegalStateException异常
public boolean add(E e) {
    return super.add(e); // 调用父类AbstractQueue.add(E)方法
}

// 父类AbstractQueue.add(E)
public boolean add(E e) {
    if (offer(e)) // 调用子类ArrayBlockingQueue的offer(e)方法,成功返回true
        return true;
    else // 添加失败(队列已满),抛出异常
        throw new IllegalStateException("Queue full");
}

// ArrayBlockingQueue.offer(e) 添加成功返回true,若队列已满导致添加失败,返回false
public boolean offer(E e) {
    checkNotNull(e); // 元素不能为null
    final ReentrantLock lock = this.lock;
    lock.lock(); // 获取锁
    try {
        if (count == items.length) // 队列已满,添加失败,返回false
            return false;
        else {
            enqueue(e); // 执行入队操作
            return true; // 添加成功
        }
    } finally {
        lock.unlock(); // 释放锁
    }
}
入队操作enqueue(e)方法如下:

// 入队操作必须在获得锁的前提下进行
private void enqueue(E x) {
    // assert lock.getHoldCount() == 1;
    // assert items[putIndex] == null;
    final Object[] items = this.items; // 获取底层数组引用
    items[putIndex] = x; // x放入数组
      // putIndex递增,若putIndex == items.length,表示putIndex已达到数组末尾。由于是循环数组,
      // putIndex置0,后续添加操作从index=0开始
    if (++putIndex == items.length) 
        putIndex = 0;
    count++; // 元素个数+1
    notEmpty.signal(); // 由于有元素入队,则通知可能在阻塞等待获取元素的线程
}


(2) offer (e, timeout , unit) - blocking
This method is blocking limit version offer (e) to add elements. If the elements are added, the queue is full, the thread is blocked waiting for up to a given time. If the queue is blocked waiting for a given time or no space, false failure returns.

public boolean offer(E e, long timeout, TimeUnit unit) // 等待最多timeout时间
    throws InterruptedException {

    checkNotNull(e); // 元素不能为null
    long nanos = unit.toNanos(timeout); // 转换为纳秒
    final ReentrantLock lock = this.lock;
    lock.lockInterruptibly(); // 获取锁,并且阻塞时可中断
    try {
        while (count == items.length) { // 检测队列是否已满。这里用循环,防止可能的假醒现象。
            if (nanos <= 0) // 队列已满且剩余的等待时间为0,返回添加失败
                return false;
              // 队列已满且剩余时间>0,执行等待。awaitNanos在返回后,返回剩余可以继续等待的时间。
            nanos = notFull.awaitNanos(nanos); 
        }
        enqueue(e); // 入队列操作
        return true; // 添加成功
    } finally {
        lock.unlock();
    }
}


(3) put (e) - obstructive

// 添加元素,若队列已满,则阻塞等待,直到被唤醒且有空间可以添加元素。
public void put(E e) throws InterruptedException {
    checkNotNull(e); // 元素不能为null
    final ReentrantLock lock = this.lock;
    lock.lockInterruptibly(); // 获取锁,并且阻塞时可中断
    try {
        while (count == items.length) // 检测队列是否已满。这里用循环,防止可能的假醒现象。
            notFull.await(); // 队列已满,阻塞等待。
        enqueue(e); // 入队列
    } finally {
        lock.unlock();
    }
}

4. The method of obtaining the element (dequeued, Remove / poll / Take)
(. 1) remove () / poll () - nonblocking
remove () methods defined in the parent class AbstractQueue, as shown below, is a low-level calls to poll ()method:

// AbstractQueue.remove() 
public E remove() {
    E x = poll(); // 调用poll()获取元素
    if (x != null) // 队列不为空,获取到元素后返回
        return x;
    else // 否则抛出异常
        throw new NoSuchElementException();
}
// ArrayBlockingQueue.poll() 队列中无元素,返回null;否则返回队列头部元素
public E poll() {
    final ReentrantLock lock = this.lock;
    lock.lock(); // 获取锁
    try {
        return (count == 0) ? null : dequeue(); // 存在元素时,调用dequeue()方法
    } finally {
        lock.unlock();
    }
}
// ArrayBlockingQueue.dequeue() 出队操作是在获得锁的前提下进行的
private E dequeue() {
    // assert lock.getHoldCount() == 1;
    // assert items[takeIndex] != null;
    final Object[] items = this.items; // 获取底层数组的引用
    @SuppressWarnings("unchecked")
    E x = (E) items[takeIndex]; // 获取出队元素
    items[takeIndex] = null; // 已出队元素位置置null
    if (++takeIndex == items.length) // takeIndex+1,达到尾部,则takeIndex置0(循环数组)
        takeIndex = 0;
    count--; // 总数-1
    if (itrs != null)
        itrs.elementDequeued(); // 元素出队,更新迭代器状态
    notFull.signal(); // 通知可能阻塞等待添加元素的线程(可能因为之前队列满了)
    return x;
}


(2) poll (timeout, unit ) - obstruction
of this method is the poll () blocking for a limited time get elements. If the element at the time of acquisition, the queue is empty, the thread is blocked waiting for up to a given time. If the block waiting for the queue after a given time or is empty, null is returned.

public E poll(long timeout, TimeUnit unit) throws InterruptedException { // 限时获取元素
    long nanos = unit.toNanos(timeout); // 转换为纳秒
    final ReentrantLock lock = this.lock;
    lock.lockInterruptibly(); // 获取锁,并且阻塞时可中断
    try {
        while (count == 0) { // 判断队列是否为空。这里用循环,防止可能的假醒现象。
            if (nanos <= 0) // 队列为空且剩余的等待时间为0,返回null
                return null;
              // 队列为空且剩余时间>0,执行等待。awaitNanos在返回后,返回剩余可以继续等待的时间。
            nanos = notEmpty.awaitNanos(nanos);
        }
        return dequeue(); // 出队操作
    } finally {
        lock.unlock();
    }
}


(3) take () - obstruction

// 获取元素,若队列为空,则阻塞等待,直到被唤醒且队列非空可以获取元素。
public E take() throws InterruptedException {
    final ReentrantLock lock = this.lock;
    lock.lockInterruptibly(); // 获取锁,并且阻塞时可中断
    try {
        while (count == 0) // 检测队列是否为空。这里用循环,防止可能的假醒现象。
            notEmpty.await(); // 为空则等待
        return dequeue(); // 出队列
    } finally {
        lock.unlock();
    }
}

LinkedBlockingQueue analysis

1. Core attributes
LinkedBlockingQueue is a blocking queue based on linked list, first look at the core attributes:

// 所有的元素都通过Node这个静态内部类来进行存储,这与LinkedList的处理方式完全一样
static class Node<E> {
    E item; // 使用item来保存元素本身

      // 存在三种情况:
      // 1.真正存在的后继节点 2.指向当前节点本身,说明该节点已经出队 
      // 3.null,表示无后继节点,该节点是最后的节点
    Node<E> next; // 保存当前节点的后继节点

    Node(E x) { item = x; }
}
// 阻塞队列所能存储的最大容量,用户可以在创建时手动指定最大容量,
// 如果用户没有指定最大容量,那么默认的最大容量为Integer.MAX_VALUE。
private final int capacity;

// 队列中当前元素个数,使用AtomicInteger来保证并发修改的安全性。因为队列中可能同时存在存、取操作。
private final AtomicInteger count = new AtomicInteger();

// 链表头结点,head.item == null。说明真正存储数据的头节点是head.next
transient Node<E> head;

// 链表尾节点,last.next == null
private transient Node<E> last;

// 当执行take、poll等操作时线程需要获取的锁
private final ReentrantLock takeLock = new ReentrantLock();

// 当队列为空时,通过该Condition让从队列中获取元素的线程处于等待状态
private final Condition notEmpty = takeLock.newCondition();

// 当执行add、put、offer等操作时线程需要获取锁
private final ReentrantLock putLock = new ReentrantLock();

// 当队列的元素已经达到capactiy,通过该Condition让元素入队列的线程处于等待状态
private final Condition notFull = putLock.newCondition();


Through the above analysis it can be found in use when the element LinkedBlockingQueue queues and the queue is not the same Lock, which means that they do not exist between the operation of mutual exclusivity. In the case of more than one CPU, they can be truly consumer both at the same time, and production can be done in parallel. 2. Constructor

public LinkedBlockingQueue() { // 如果用户没有显式指定capacity的值,默认使用Integer的最大值
    this(Integer.MAX_VALUE);
}

// 显式指定capacity的值。
// 当队列中没有任何元素的时候,此时队列的头部就等于队列的尾部, 指向的是同一个节点,并且元素的内容为null
public LinkedBlockingQueue(int capacity) {
    if (capacity <= 0) throw new IllegalArgumentException();
    this.capacity = capacity;
    last = head = new Node<E>(null);
}

// 指定LinkedBlockingQueue初始化时入队列的集合
public LinkedBlockingQueue(Collection<? extends E> c) {
    this(Integer.MAX_VALUE); // 容量为最大值
    final ReentrantLock putLock = this.putLock;
    putLock.lock(); // Never contended, but necessary for visibility 获取putLock
    try {
        int n = 0;
        for (E e : c) {
            if (e == null)
                throw new NullPointerException(); // 元素不能为null
            if (n == capacity)
                throw new IllegalStateException("Queue full");
            enqueue(new Node<E>(e)); // 入队列
            ++n;
        }
        count.set(n); // 更新count值
    } finally {
        putLock.unlock();
    }
}
// 元素入队列(前提是线程持有putLock)
private void enqueue(Node<E> node) {
    // assert putLock.isHeldByCurrentThread();
    // assert last.next == null;
      // 1.插入节点到尾部 2.更新last变量为刚插入的节点
    last = last.next = node;
}


3. The method enqueue (put / the offer)
(. 1) put (E) - blocked
queue is full if the put operation, the blocked queue enqueue operation only becomes non-full.

public void put(E e) throws InterruptedException {
    if (e == null) throw new NullPointerException(); // 入队元素不能为null
    // Note: convention in all put/take/etc is to preset local var
    // holding count negative to indicate failure unless set.
      // 约定入队、出队操作时预设置局部变量c为-1,表示操作是否成功。负值表示操作失败,>=0表示成功。
    int c = -1;
    Node<E> node = new Node<E>(e); // 新建节点
    final ReentrantLock putLock = this.putLock; // putLock
    final AtomicInteger count = this.count;
    putLock.lockInterruptibly(); // 可中断的获取锁
    try {
        // 当队列的容量到底最大容量时,此时线程将处于等待状态,直到队列有空闲的位置才继续执行。
          // 使用while判断是为了防止线程被"伪唤醒”,即当线程被唤醒而队列的大小依旧等于
          // capacity时,线程应该继续等待。
        while (count.get() == capacity) {
            notFull.await(); // 阻塞等待
        }
        enqueue(node); // 入队队列尾部
        c = count.getAndIncrement(); // count值+1,返回原count值
          // c+1得到的结果是新元素入队列之后队列元素的总和。当前队列中的总元素个数小于最大容量时,此时唤醒其他
          // 执行入队列的线程让它们可以放入元素,如果新加入元素之后,队列的大小等于capacity,那么就意味着此时
          // 队列已经满了,也就没有必要唤醒其他正在等待入队列的线程,因为唤醒它们之后,它们也还是继续等待。
        if (c + 1 < capacity)
            notFull.signal(); // 通知入队列线程
    } finally {
        putLock.unlock(); // 释放putLock
    }
      // 当c=0时,意味着之前的队列是空队列,出队列的线程都处于等待状态,现在新添加了一个元素,即队列不再为空,
      // 因此它会唤醒正在等待获取元素的线程。
    if (c == 0)
        signalNotEmpty();
}
// 唤醒正在等待获取元素的线程,告诉它们现在队列中有元素了
private void signalNotEmpty() {
    final ReentrantLock takeLock = this.takeLock;
    takeLock.lock();
    try {
        notEmpty.signal(); // 通过notEmpty条件唤醒获取元素的线程
    } finally {
        takeLock.unlock();
    }
}


(2) offer (e) - nonblocking
offer (e) the previous put (e) different queue is full, the process directly returns false if the operation is performed, the thread is not blocked.

public boolean offer(E e) {
    if (e == null) throw new NullPointerException(); // 元素不能为null
    final AtomicInteger count = this.count;
    if (count.get() == capacity) // 队列已满,直接返回false
        return false;
    int c = -1;
    Node<E> node = new Node<E>(e);
    final ReentrantLock putLock = this.putLock;
    putLock.lock(); // 获取putLock
    try {
          // 当获取到锁时,需要进行二次的检查,因为可能当队列的大小为capacity-1时,两个线程同时去抢占锁,
          // 而只有一个线程抢占成功,那么此时当线程将元素入队列后,释放锁,后面的线程抢占锁之后,此时队列
          // 大小已经达到capacity,所以它将无法让元素入队列。下面的其余操作和put都一样,此处不再详述。
        if (count.get() < capacity) {
            enqueue(node); // 只有第二次检查,count小于容量时才入队
            c = count.getAndIncrement();
            if (c + 1 < capacity)
                notFull.signal();
        }
    } finally {
        putLock.unlock();
    }
    if (c == 0)
        signalNotEmpty();
    return c >= 0; // c >=0 表示offer操作元素入队成功
}


(3) offer (e, timeout , unit) - obstructive
BlockingQueue defines a limit to wait insert, i.e., within a certain time, if there is queue space can be inserted, then the element will enter the queue, and returns true; if still no space can be inserted, then it returns false after over a specified period of time, the following analysis is limited time to wait for the operation:

public boolean offer(E e, long timeout, TimeUnit unit)
    throws InterruptedException {

    if (e == null) throw new NullPointerException();
    long nanos = unit.toNanos(timeout); // 时间转为纳秒形式
    int c = -1;
    final ReentrantLock putLock = this.putLock;
    final AtomicInteger count = this.count;
    putLock.lockInterruptibly(); // 可中断的获取锁
    try { 
        while (count.get() == capacity) { // 判断队列是否已满。这里用循环,防止可能的假醒现象。
            if (nanos <= 0) // 队列已满且剩余的等待时间为0,返回添加失败
                return false;
              // 队列已满且剩余时间>0,执行等待。awaitNanos在返回后,返回剩余可以继续等待的时间。
            nanos = notFull.awaitNanos(nanos);
        }
        enqueue(new Node<E>(e)); // 执行入队操作
          // 下面的其余操作和put都一样,此处不再详述。
        c = count.getAndIncrement();
        if (c + 1 < capacity)
            notFull.signal();
    } finally {
        putLock.unlock();
    }
    if (c == 0)
        signalNotEmpty();
    return true;
}


Through the above analysis, it should be more clear understanding of the LinkedBlockingQueue into queues, which is mainly accomplished by obtaining putLock lock, when the number of elements in the queue reaches a maximum at this time causes the thread is in the blocked state or returns false ( the specific methods of view); if there is space remaining queue, then the Node object at this time will be newly created, the queue to the tail of the queue as the last element LinkedBlockingQueue.


4. dequeue operation (take / poll)
(. 1) take () - blocking
the queue is empty when performing operations take, the block waiting queue when dequeue operation becomes non-empty.

public E take() throws InterruptedException {
    E x; // 返回值
    int c = -1;
    final AtomicInteger count = this.count;
    final ReentrantLock takeLock = this.takeLock;
    takeLock.lockInterruptibly(); // 获取takeLock锁,并且阻塞时可中断
    try {
        while (count.get() == 0) { // 检测队列是否为空。这里用循环,防止可能的假醒现象。
            notEmpty.await(); // 为空则阻塞等待
        }
        x = dequeue(); // 出队列
        c = count.getAndDecrement(); // count-1,并返回之前的count值
          // c>1表明当前出队列操作之后队列中依然存在元素(c-1>0),当前线程会唤醒其他执行元素出队列的线程,
          // 让它们也可以执行元素的获取
        if (c > 1)
            notEmpty.signal();
    } finally {
        takeLock.unlock(); // 释放putLock
    }
      // 当c==capaitcy时,即在获取当前元素之前,队列已经满了,而此时获取元素之后,队列就会空出一个位置,
      // 故当前线程会唤醒执行插入操作的线程,通知其中的一个可以进行插入操作。
    if (c == capacity)
        signalNotFull();
    return x;
}
// 出队操作(前提是获取takeLock)
// 让头部元素出队列的过程,其最终的目的是让原来的head被GC回收,让其next成为head,并且新的head的
// item为null。
private E dequeue() {
    // assert takeLock.isHeldByCurrentThread();
    // assert head.item == null;
    Node<E> h = head;
    Node<E> first = h.next;
    h.next = h; // help GC
    head = first; 
    E x = first.item;
    first.item = null;
    return x;
}
// 唤醒正在等待添加元素的线程,告诉它们现在队列中有空间了
private void signalNotFull() {
    final ReentrantLock putLock = this.putLock;
    putLock.lock();
    try {
        notFull.signal(); // 通过notFull条件唤醒添加元素的线程
    } finally {
        putLock.unlock(); 
    }
}


(2) poll () - nonblocking
poll () the previous take () different, the queue is empty if the operation is performed, the process directly returns null, without blocking the thread.

public E poll() {
    final AtomicInteger count = this.count;
    if (count.get() == 0) // 队列为空,直接返回null(非阻塞)
        return null;
    E x = null;
    int c = -1;
    final ReentrantLock takeLock = this.takeLock;
    takeLock.lock();
    try {
        if (count.get() > 0) { // 再次判断队列元素个数是否>0
                // 以下逻辑take()操作一致,不在详述
            x = dequeue();
            c = count.getAndDecrement();
            if (c > 1)
                notEmpty.signal();
        }
    } finally {
        takeLock.unlock();
    }
    if (c == capacity)
        signalNotFull();
    return x;
}


(3) poll (timeout, unit ) - blocking
limit obstruction version of poll () method.

public E poll(long timeout, TimeUnit unit) throws InterruptedException {
    E x = null;
    int c = -1;
    long nanos = unit.toNanos(timeout); // 等待时间,转为纳秒形式
    final AtomicInteger count = this.count;
    final ReentrantLock takeLock = this.takeLock;
    takeLock.lockInterruptibly();
    try {
        while (count.get() == 0) { // 判断队列是否为空。这里用循环,防止可能的假醒现象。
            if (nanos <= 0) // 队列为空且剩余的等待时间为0,返回添加失败
                return null;
              // 队列为空且剩余时间>0,执行阻塞等待。awaitNanos在返回后,返回剩余可以继续等待的时间。
            nanos = notEmpty.awaitNanos(nanos);
        }
          // 以下逻辑take()操作一致,不在详述
        x = dequeue();
        c = count.getAndDecrement();
        if (c > 1)
            notEmpty.signal();
    } finally {
        takeLock.unlock();
    }
    if (c == capacity)
        signalNotFull();
    return x;
}


Two, a LinkedBlockingQueue ArrayBlockingQueue of Comparative
ArrayBlockingQueue because its underlying based array, and specifies the size stored at the time created, it immediately assign a fixed capacity memory array size, so it is stored after completion often limited, so it is a "has world "blocking queue; LinkedBlockingQueue may be specified by the user and the maximum storage capacity may need to specify, if not specified, the maximum storage capacity will be Integer.MAX_VALUE, i.e., can be seen as a" unbounded "blocking queue, since its node are created dynamically created and may be recovered after GC-queue node, so it has a flexible stretchable. However, due to ArrayBlockingQueue are bounded, so it can better predict the performance, but LinkedBlockingQueue because there is no size limit, when a lot of task time, to keep stored in the queue, it may lead to memory overflow occurs .

Next, the process ArrayBlockingQueue with queues and a queue operation in a Lock using the same, even in the case of a multi-core CPU, the dequeue and enqueue operation can not be done in parallel, and the dequeue and the LinkedBlockingQueue lock operation team uses two different lock, uninterrupted operation of each therebetween, so two operations can be done in parallel, so that a certain LinkedBlockingQueue than ArrayBlockingQueue.

Third, select the thread pool LinkedBlockingQueue reason
// The following code is the code Executors to create a fixed-size thread pool, which is used as LinkedBlockingQueue task queue.
ExecutorService newFixedThreadPool static public (int nThreads) {
    return new new the ThreadPoolExecutor (nThreads, nThreads,
                                  0L, TimeUnit.MILLISECONDS,
                                  new new LinkedBlockingQueue <the Runnable> ());
}
the JDK fixed-size thread pool LinkedBlockingQueue selected as the reason in its blocking queue unbounded . Because the size of the fixed thread pool thread, the number of threads is not a stretchable, when the task is very busy, it will inevitably lead to all the threads are in working condition, if a bounded blocking queue for processing, then it is very likely soon lead to full queue occurs, resulting in the task can not be submitted and throw RejectedExecutionException, and an unbounded queue due to the flexibility of its good storage capacity, it can be a good buffer task. A busy case, even if very large task, expansion may be performed dynamically, when the task is processed, the queue node will be recovered along with the GC, is very flexible.

SynchronousQueue
SynchronousQueue blocking queue is a special, different from LinkedBlockingQueue, ArrayBlockingQueue blockage of the queue, which no internal capacity, any need to wait for operations enqueue dequeue another thread, and vice versa. Any thread (the producer thread or threads consumers, production types of operations such as put, offer, types of operations such as consumer poll, take) will wait until the completion of the delivery of data or data will not return, a producer thread's mission is to thread attached to the data delivered to a consumer thread, and the thread is waiting for a consumer a producer thread data. They will do to the complementary data exchange in the match when the thread, the thread producers such as the face of consumer threads, or threads consumers encounter producer thread, a producer thread will deliver data to the consumer thread, then common exit. In Java thread pool Executors.newCachedThreadPool on the use of such blocking queue.

Reference
https://www.jishuwen.com/d/2NF0#tuit: priority queue
https://xuanjian1992.top/2019/06/09/LinkedBlockingQueue%E6%BA%90%E7%A0%81%E5%88 E6% 9E% 86% 90% / 
https://xuanjian1992.top/2019/06/09/ArrayBlockingQueue%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90/ ( array using a circular queue)

Published 223 original articles · won praise 308 · views 840 000 +

Guess you like

Origin blog.csdn.net/maoyeqiu/article/details/97175361