线程池中的存储队列(阻塞队列)

一 概述

线程池中超过核心线程数corePoolsize的线程会放入线程池中存储队列中,存储队列是一种阻塞式队列。

二 阻塞队列

阻塞队列是支持阻塞插入和阻塞移除方法的队列。阻塞队列常用于生产者和消费者的场景,生产者是向队列里添加元素的线程,消费者是从队列里取元素的线程。阻塞队列就是生产者用来存放元素、消费者用来获取元素的容器。

支持阻塞的插入方法(put(E e)):当队列满时,队列会阻塞插入元素的线程,直至队列不满。

支持阻塞的移除方法(take()):当队列空时,队列会阻塞移除元素的线程,直至队列不为空。

 /* 
 * @since 1.5
 * @author Doug Lea
 * @param <E> the type of elements held in this collection
 */
public interface BlockingQueue<E> extends Queue<E> {
    //插入方法
    boolean add(E e);//非阻塞方法
    boolean offer(E e);
    void put(E e) throws InterruptedException;//阻塞方法
    boolean offer(E e, long timeout, TimeUnit unit) throws InterruptedException;//阻塞指定时间,超时退出
    //移除方法
    E take() throws InterruptedException;//阻塞方法
    E poll(long timeout, TimeUnit unit) throws InterruptedException;//阻塞指定时间,超时退出
    boolean remove(Object o);//非阻塞方法
    //判断元素是否存在
    public boolean contains(Object o);
    //查询队列剩余空间
    int remainingCapacity();
    //移出元素并将元素放入指定集合
    int drainTo(Collection<? super E> c);
    int drainTo(Collection<? super E> c, int maxElements);
}

如果队列是无界阻塞队列,队列不可能会出现满队列的情况,所以使用put(E e)或者offer(E e,long timeout,TimeUnit unit)方法是不会出现被阻塞的情况,而且后者会一直返回true。

三 阻塞队列的阻塞实现原理

阻塞队列是通过ReentranLock锁+Condition条件状态来实现队列的阻塞。其中,Condition通过等待await()/通知机制signal()来实现线程之间的通信。类似于Object的wait()与notify(),通过Synchronized的同步锁机制使用wait(等待)和notify(通知)来实现线程的通信。

ReentranLock

/**
 * @since 1.5
 * @author Doug Lea
 */
public class ReentrantLock implements Lock, java.io.Serializable {

}

Condition

/**
 * @since 1.5
 * @author Doug Lea
 */
public interface Condition {

    void await() throws InterruptedException;
    boolean await(long time, TimeUnit unit) throws InterruptedException;
    void signal();
    void signalAll();
}

阻塞过程:在阻塞队列A中调用put(E e)方法向队列插入数据时,如果队列已经满了,则A线程就会挂起,put(E e)方法被阻塞,会等到队列到非满的状态时恢复。如果B线程调用take()方法移出队列中的数据后,会通知执行put(E e)方法而挂起的A线程,因为这个时候B线程已经消费了队列中的一个元素,所以此时的队列为非满状态,则会激活线程A,同时线程A会调用之前挂起的put(E e)方法进行数据插入操作。相反,线程B调用take()方法移除数据时,如果队列为空,线程B也会挂起,take()方法被阻塞,当A调用put(E e)方法向队列插入数据后使得队列为非空时,此时会通知激活线程B,同时线程B调用会调用之前挂起的take()方法进行数据移出操作。

四Java8中阻塞队列的实例

ArrayBlockingQueue

 /* 
 * A bounded {@linkplain BlockingQueue blocking queue} backed by an
 * array.  This queue orders elements FIFO (first-in-first-out).
 * @since 1.5
 * @author Doug Lea
 * @param <E> the type of elements held in this collection
 */
public class ArrayBlockingQueue<E> extends AbstractQueue<E>
        implements BlockingQueue<E>, java.io.Serializable {
    /** The queued items */
    final Object[] items;

    //ReentrantLock 锁
    /** Main lock guarding all access */
    final ReentrantLock lock;

    //非空的Condition状态
    /** Condition for waiting takes */
    private final Condition notEmpty;

    //非满的Condition状态
    /** Condition for waiting puts */
    private final Condition notFull;

    /** items index for next take, poll, peek or remove */
    int takeIndex;

    /** items index for next put, offer, or add */
    int putIndex;

    /** Number of elements in the queue */
    int count;

    //默认非公平访问策略
    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();
    }

    /**
     * Inserts element at current put position, advances, and signals.
     * Call only when holding lock.
     */
    private void enqueue(E x) {
        // assert lock.getHoldCount() == 1;
        // assert items[putIndex] == null;
        final Object[] items = this.items;
        items[putIndex] = x;
        if (++putIndex == items.length)
            putIndex = 0;
        count++;
        /*在tack()方法中,如果队列为空时会调用notEmpty.await()挂起当先调用take()的线程,
          当其他线程调用put(E e)方法插入元素成功后会通过notEmpty.signal()唤醒之前挂起的线程
          调用take()方法移出元素*/
        notEmpty.signal();
    }

    /**
     * Extracts element at current take position, advances, and signals.
     * Call only when holding lock.
     */
    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;
        if (++takeIndex == items.length)
            takeIndex = 0;
        count--;
        if (itrs != null)
            itrs.elementDequeued();
        /*在put(E e)方法中,如果队列为满时会调用notFull.await()挂起当先调用put(E e)的线程,
          当其他线程调用take()方法成功移出队列中的元素后会通过notFull.signal()唤醒之前挂起的线                
          程调用put(E e)方法插入元素*/
        notFull.signal();
        return x;
    }

    /**
     * Inserts the specified element at the tail of this queue, waiting
     * for space to become available if the queue is full.
     *
     * @throws InterruptedException {@inheritDoc}
     * @throws NullPointerException {@inheritDoc}
     */
    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();
        }
    }
}

ArrayBlockingQueue是一个基于数组实现的有界阻塞队列。此队列按照先进先出FIFO(first-in-first-out)的原则对元素进行排序,其中items是一个Object的数组保存队列元素,takeIndex为出队元素的下标,putIndex为入队列的下标,count为队列中的元素总数。

ArrayBlockingQueue获取数据和添加数据都是使用同一个锁对象,这样添加和获取就不会产生并发操作,但是,它使用的是Condition的等待/通知机制,使得ArrayBlockingQueue的数据写入和获取操作足够轻巧,以至于引入独立的锁机制,从而给代码的带来额外的复杂性。

此外,ArrayBlockingQueue默认情况下是不保证访问者公平的访问队列,所谓公平访问队列是指被阻塞的所有生产者线程和消费者线程在队列可用的时候,可以按照入队的先后顺序反问队列。也就是说,先阻塞的生产者线程可以先向队列插入元素,而先阻塞的消费者线程可以先从队列中获取元素。Java源码中使用了一个公平锁来保证访问线程可以公平的访问阻塞队列。

//将fair参数设置为true
ArrayBlockingQueue abq = new ArrayBlockingQueue(666, true);
//设置公平锁    
public ReentrantLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
    }

DelayQueue

/**
 * @since 1.5
 * @author Doug Lea
 * @param <E> the type of elements held in this collection
 */
public class DelayQueue<E extends Delayed> extends AbstractQueue<E>
    implements BlockingQueue<E> {

    private final PriorityQueue<E> q = new PriorityQueue<E>();

    public DelayQueue() {}

    public DelayQueue(Collection<? extends E> c) {
        this.addAll(c);
    }
    public boolean addAll(Collection<? extends E> c) {
        if (c == null)
            throw new NullPointerException();
        if (c == this)
            throw new IllegalArgumentException();
        boolean modified = false;
        for (E e : c)
            if (add(e))
                modified = true;
        return modified;
    }
}

DelayQueue是一个支持延时获取元素的无界阻塞队列,按延迟之间进行排序,需要实现Delayed接口来实现延迟功能。队列使用PriorityQueue来实现。队列中的元素必须实现Delayed接口,在对队列进行操作的时候可以指定延迟多久,当延迟时间满了才能够对队列进行操作。

基于DelayQueue的上述特点可以进行下列设计:

  1. 缓存系统设计:使用延时阻塞队列DelayQueue保存缓存的有效期,使用一个线程循环查询DelayQueue,一旦能够从DelayQueue中获取元素,表示缓存有效期到了。
  2. 定时任务调度:使用延时阻塞队列DelayQueue保存当天将会执行的任务和执行时间,一旦从DelayQueue中获取到任务就开始执行,如TimerQueue就是使用阻塞队列来实现的。

DelayedWorkQueue

public class ScheduledThreadPoolExecutor
        extends ThreadPoolExecutor
        implements ScheduledExecutorService {

 static class DelayedWorkQueue extends AbstractQueue<Runnable>
        implements BlockingQueue<Runnable> {
    
        private static final int INITIAL_CAPACITY = 16;
        private RunnableScheduledFuture<?>[] queue =
            new RunnableScheduledFuture<?>[INITIAL_CAPACITY];
        private final ReentrantLock lock = new ReentrantLock();
        private int size = 0;

        public int remainingCapacity() {
            return Integer.MAX_VALUE;
        }
}

DelayedWorkQueue是类的一个内部类ScheduledThreadPoolExecutor,它也实现了BlockingQueue<Runnable>接口,它是基于堆结构的阻塞延时队列,堆结构为数组实现的二叉树,初始容量为16。

LinkedBlockingQueue

 /**
 * This queue orders elements FIFO (first-in-first-out).
 * @since 1.5
 * @author Doug Lea
 * @param <E> the type of elements held in this collection
 */
public class LinkedBlockingQueue<E> extends AbstractQueue<E>
        implements BlockingQueue<E>, java.io.Serializable {
    
    /**
     * Linked list node class
     */
    static class Node<E> {
        E item;

        /**
         * One of:
         * - the real successor Node
         * - this Node, meaning the successor is head.next
         * - null, meaning there is no successor (this is the last node)
         */
        Node<E> next;

        Node(E x) { item = x; }
    }

    /**
     * Creates a {@code LinkedBlockingQueue} with a capacity of
     * {@link Integer#MAX_VALUE}.
     */
    public LinkedBlockingQueue() {
        this(Integer.MAX_VALUE);
    }

    /**
     * Creates a {@code LinkedBlockingQueue} with the given (fixed) capacity.
     *
     * @param capacity the capacity of this queue
     * @throws IllegalArgumentException if {@code capacity} is not greater
     *         than zero
     */
    public LinkedBlockingQueue(int capacity) {
        if (capacity <= 0) throw new IllegalArgumentException();
        this.capacity = capacity;
        last = head = new Node<E>(null);
    }

        /**
     * Creates a {@code LinkedBlockingQueue} with a capacity of
     * {@link Integer#MAX_VALUE}, initially containing the elements of the
     * given collection,
     * added in traversal order of the collection's iterator.
     *
     * @param c the collection of elements to initially contain
     * @throws NullPointerException if the specified collection or any
     *         of its elements are null
     */
    public LinkedBlockingQueue(Collection<? extends E> c) {
        this(Integer.MAX_VALUE);
        final ReentrantLock putLock = this.putLock;
        putLock.lock(); // Never contended, but necessary for visibility
        try {
            int n = 0;
            for (E e : c) {
                if (e == null)
                    throw new NullPointerException();
                if (n == capacity)
                    throw new IllegalStateException("Queue full");
                enqueue(new Node<E>(e));
                ++n;
            }
            count.set(n);
        } finally {
            putLock.unlock();
        }
    }
}

LinkedBlockingQueue是一个基于链表实现的无界阻塞队列,此队列的默认最大容量为Integer.MAX_VALUE(2^31-1)。此队列的出队方式为先进先出,即FIFO(first-in-first-out)。此外,它在添加和删除队列中的元素的时候会伴随着对象的对象的创建和销毁,所以在高并发和数据量大的时候会造成较大的GC压力,而且她获取元素和添加的元素使用的是不同的锁对象。

LinkedBlockingDeque

 * @since 1.6
 * @author  Doug Lea
 * @param <E> the type of elements held in this collection
 */
public class LinkedBlockingDeque<E>
    extends AbstractQueue<E>
    implements BlockingDeque<E>, java.io.Serializable {

   /** Doubly-linked list node class */
    static final class Node<E> {
        /**
         * The item, or null if this node has been removed.
         */
        E item;

        /**
         * One of:
         * - the real predecessor Node
         * - this Node, meaning the predecessor is tail
         * - null, meaning there is no predecessor
         */
        Node<E> prev;

        /**
         * One of:
         * - the real successor Node
         * - this Node, meaning the successor is head
         * - null, meaning there is no successor
         */
        Node<E> next;

        Node(E x) {
            item = x;
        }
    }

    /**
     * Creates a {@code LinkedBlockingDeque} with a capacity of
     * {@link Integer#MAX_VALUE}.
     */
    public LinkedBlockingDeque() {
        this(Integer.MAX_VALUE);
    }

    /**
     * Creates a {@code LinkedBlockingDeque} with the given (fixed) capacity.
     *
     * @param capacity the capacity of this deque
     * @throws IllegalArgumentException if {@code capacity} is less than 1
     */
    public LinkedBlockingDeque(int capacity) {
        if (capacity <= 0) throw new IllegalArgumentException();
        this.capacity = capacity;
    }

    /**
     * Creates a {@code LinkedBlockingDeque} with a capacity of
     * {@link Integer#MAX_VALUE}, initially containing the elements of
     * the given collection, added in traversal order of the
     * collection's iterator.
     *
     * @param c the collection of elements to initially contain
     * @throws NullPointerException if the specified collection or any
     *         of its elements are null
     */
    public LinkedBlockingDeque(Collection<? extends E> c) {
        this(Integer.MAX_VALUE);
        final ReentrantLock lock = this.lock;
        lock.lock(); // Never contended, but necessary for visibility
        try {
            for (E e : c) {
                if (e == null)
                    throw new NullPointerException();
                if (!linkLast(new Node<E>(e)))
                    throw new IllegalStateException("Deque full");
            }
        } finally {
            lock.unlock();
        }
    }
}

LinkedBlockingDeque是一个由双向链表构成的双向阻塞队列。双向阻塞队列意味着它可以从队列的两端插入和移出元素。由于它提供了两个队列的操作入口,所以在多线程进行插入或者移除操作时会减少一半的竞争。同时为各种方法提供了操作队首元素的方法(xxxFirst())和操作队尾元素的方法(xxxLast())。此外,双向阻塞队列可以运用在"工作窃取"模式中。

LinkedTransferQueue

/**
 * An unbounded {@link TransferQueue} based on linked nodes.
 * This queue orders elements FIFO (first-in-first-out) with respect
 * to any given producer.
 * @since 1.7
 * @author Doug Lea
 * @param <E> the type of elements held in this collection
 */
public class LinkedTransferQueue<E> extends AbstractQueue<E>
    implements TransferQueue<E>, java.io.Serializable {

     static final class Node {
     final boolean isData;   // false if this is a request node
     volatile Object item;   // initially non-null if isData; CASed to match
     volatile Node next;
     volatile Thread waiter; // null until waiting

     // CAS methods for fields
     final boolean casNext(Node cmp, Node val) {
         return UNSAFE.compareAndSwapObject(this, nextOffset, cmp, val);
    }

     final boolean casItem(Object cmp, Object val) {
         // assert cmp == null || cmp.getClass() != Node.class;
            return UNSAFE.compareAndSwapObject(this, itemOffset, cmp, val);
     }

    /**
     * Creates an initially empty {@code LinkedTransferQueue}.
     */
    public LinkedTransferQueue() {
    }

    /**
     * Creates a {@code LinkedTransferQueue}
     * initially containing the elements of the given collection,
     * added in traversal order of the collection's iterator.
     *
     * @param c the collection of elements to initially contain
     * @throws NullPointerException if the specified collection or any
     *         of its elements are null
     */
    public LinkedTransferQueue(Collection<? extends E> c) {
        this();
        addAll(c);
    }

    /**
     * Transfers the element to a waiting consumer immediately, if possible.
     *
     * <p>More precisely, transfers the specified element immediately
     * if there exists a consumer already waiting to receive it (in
     * {@link #take} or timed {@link #poll(long,TimeUnit) poll}),
     * otherwise returning {@code false} without enqueuing the element.
     *
     * @throws NullPointerException if the specified element is null
     */
    public boolean tryTransfer(E e) {
        return xfer(e, true, NOW, 0) == null;
    }

    /**
     * Transfers the element to a consumer, waiting if necessary to do so.
     *
     * <p>More precisely, transfers the specified element immediately
     * if there exists a consumer already waiting to receive it (in
     * {@link #take} or timed {@link #poll(long,TimeUnit) poll}),
     * else inserts the specified element at the tail of this queue
     * and waits until the element is received by a consumer.
     *
     * @throws NullPointerException if the specified element is null
     */
    public void transfer(E e) throws InterruptedException {
        if (xfer(e, true, SYNC, 0) != null) {
            Thread.interrupted(); // failure possible only due to interrupt
            throw new InterruptedException();
        }
    }

    /**
     * Transfers the element to a consumer if it is possible to do so
     * before the timeout elapses.
     *
     * <p>More precisely, transfers the specified element immediately
     * if there exists a consumer already waiting to receive it (in
     * {@link #take} or timed {@link #poll(long,TimeUnit) poll}),
     * else inserts the specified element at the tail of this queue
     * and waits until the element is received by a consumer,
     * returning {@code false} if the specified wait time elapses
     * before the element can be transferred.
     *
     * @throws NullPointerException if the specified element is null
     */
    public boolean tryTransfer(E e, long timeout, TimeUnit unit)
        throws InterruptedException {
        if (xfer(e, true, TIMED, unit.toNanos(timeout)) == null)
            return true;
        if (!Thread.interrupted())
            return false;
        throw new InterruptedException();
    }

    /**
     * Always returns {@code Integer.MAX_VALUE} because a
     * {@code LinkedTransferQueue} is not capacity constrained.
     *
     * @return {@code Integer.MAX_VALUE} (as specified by
     *         {@link java.util.concurrent.BlockingQueue#remainingCapacity()
     *         BlockingQueue.remainingCapacity})
     */
    public int remainingCapacity() {
        return Integer.MAX_VALUE;
    }
}

LinkedTransferQueue时一个由链表结构组成的无界阻塞TransferQueue队列。无界可以从remainingCapacity()方法一直返回的是整数的最大值可以看出。此外,它还多了tryTransfer()方法和transfer()方法。

  1. transfer(E e)方法:如果当前消费者正在等待接收操作元素的时候,即消费者使用阻塞的take()方法和带时间超时限制的阻塞方法poll(long timeout, TimeUnit unit)时,tansfer方法可以把生产者传入的元素立即transfer(E e)给消费者。如果没有消费者在等待接收元素时,transfer(E e)方法会将元素存放在队列的尾部(tail)节点,并等到该元素被消费者消费后才返回。
  2. tryTransfer(E e)方法:tryTransfer()方法是用来试探生产者传入的元素是否能直接传给消费者。如果没有消费者等待接收元素就会返回false。同fransfer(E e)方法的区别是tryTransfer(E e)方法无论消费者是否接收,方法都会立即返回,而transfer(E e)方法必须等到消费者消费后才返回。
  3. tryTransfer(E e,long timeout,TimeUnit nuit) 方法,该方法试图把生产者传入的元素直接传给消费者,但是如果没有消费者消费该元素则等待指定的时间则返回false,如果在这段时间内元素被消费者消费了则返回true。

PriorityBlockingQueue

/**
 * @since 1.5
 * @author Doug Lea
 * @param <E> the type of elements held in this collection
 */
@SuppressWarnings("unchecked")
public class PriorityBlockingQueue<E> extends AbstractQueue<E>
    implements BlockingQueue<E>, java.io.Serializable {

    /**
     * Default array capacity.
     */
    private static final int DEFAULT_INITIAL_CAPACITY = 11;

    /**
     * Creates a {@code PriorityBlockingQueue} with the default
     * initial capacity (11) that orders its elements according to
     * their {@linkplain Comparable natural ordering}.
     */
    public PriorityBlockingQueue() {
        this(DEFAULT_INITIAL_CAPACITY, null);
    }

    /**
     * Creates a {@code PriorityBlockingQueue} with the specified
     * initial capacity that orders its elements according to their
     * {@linkplain Comparable natural ordering}.
     *
     * @param initialCapacity the initial capacity for this priority queue
     * @throws IllegalArgumentException if {@code initialCapacity} is less
     *         than 1
     */
    public PriorityBlockingQueue(int initialCapacity) {
        this(initialCapacity, null);
    }

    /**
     * Creates a {@code PriorityBlockingQueue} with the specified initial
     * capacity that orders its elements according to the specified
     * comparator.
     *
     * @param initialCapacity the initial capacity for this priority queue
     * @param  comparator the comparator that will be used to order this
     *         priority queue.  If {@code null}, the {@linkplain Comparable
     *         natural ordering} of the elements will be used.
     * @throws IllegalArgumentException if {@code initialCapacity} is less
     *         than 1
     */
    public PriorityBlockingQueue(int initialCapacity,
                                 Comparator<? super E> comparator) {
        if (initialCapacity < 1)
            throw new IllegalArgumentException();
        this.lock = new ReentrantLock();
        this.notEmpty = lock.newCondition();
        this.comparator = comparator;
        this.queue = new Object[initialCapacity];
    }

    /**
     * Creates a {@code PriorityBlockingQueue} containing the elements
     * in the specified collection.  If the specified collection is a
     * {@link SortedSet} or a {@link PriorityQueue}, this
     * priority queue will be ordered according to the same ordering.
     * Otherwise, this priority queue will be ordered according to the
     * {@linkplain Comparable natural ordering} of its elements.
     *
     * @param  c the collection whose elements are to be placed
     *         into this priority queue
     * @throws ClassCastException if elements of the specified collection
     *         cannot be compared to one another according to the priority
     *         queue's ordering
     * @throws NullPointerException if the specified collection or any
     *         of its elements are null
     */
    public PriorityBlockingQueue(Collection<? extends E> c) {
        this.lock = new ReentrantLock();
        this.notEmpty = lock.newCondition();
        boolean heapify = true; // true if not known to be in heap order
        boolean screen = true;  // true if must screen for nulls
        if (c instanceof SortedSet<?>) {
            SortedSet<? extends E> ss = (SortedSet<? extends E>) c;
            this.comparator = (Comparator<? super E>) ss.comparator();
            heapify = false;
        }
        else if (c instanceof PriorityBlockingQueue<?>) {
            PriorityBlockingQueue<? extends E> pq =
                (PriorityBlockingQueue<? extends E>) c;
            this.comparator = (Comparator<? super E>) pq.comparator();
            screen = false;
            if (pq.getClass() == PriorityBlockingQueue.class) // exact match
                heapify = false;
        }
        Object[] a = c.toArray();
        int n = a.length;
        // If c.toArray incorrectly doesn't return Object[], copy it.
        if (a.getClass() != Object[].class)
            a = Arrays.copyOf(a, n, Object[].class);
        if (screen && (n == 1 || this.comparator != null)) {
            for (int i = 0; i < n; ++i)
                if (a[i] == null)
                    throw new NullPointerException();
        }
        this.queue = a;
        this.size = n;
        if (heapify)
            heapify();
    }

    //扩容操作
    private void tryGrow(Object[] array, int oldCap) {
        lock.unlock(); // must release and then re-acquire main lock
        Object[] newArray = null;
        if (allocationSpinLock == 0 &&
            UNSAFE.compareAndSwapInt(this, allocationSpinLockOffset,
                                     0, 1)) {
            try {
                int newCap = oldCap + ((oldCap < 64) ?
                                       (oldCap + 2) : // grow faster if small
                                       (oldCap >> 1));
                if (newCap - MAX_ARRAY_SIZE > 0) {    // possible overflow
                    int minCap = oldCap + 1;
                    if (minCap < 0 || minCap > MAX_ARRAY_SIZE)
                        throw new OutOfMemoryError();
                    newCap = MAX_ARRAY_SIZE;
                }
                if (newCap > oldCap && queue == array)
                    newArray = new Object[newCap];
            } finally {
                allocationSpinLock = 0;
            }
        }
        if (newArray == null) // back off if another thread is allocating
            Thread.yield();
        lock.lock();
        if (newArray != null && queue == array) {
            queue = newArray;
            System.arraycopy(array, 0, newArray, 0, oldCap);
        }
    }
}

PriorityBlockingQueue是一个支持优先级的无界阻塞队列,按自然排序,但不是先进先出的顺序。默认情况下元素初始容量为11,当数据量超过当前容量的时候就会执行扩容操作实现容量扩充,所以是无界阻塞队列,同时默认采取的自然顺序为升序排序。通过Comparable接口的compareTo()方法来指定元素的自然排序规则,通过构造函数参数Comparator来队元素进行排序。但是无法保证同优先级元素的顺序。

注意,由于需要Priority的属性,所以插入的数据必须是可以比较的,所以不可插入null值,同时可以将其视为PriorityQueue的线程安全版本,当然由于它无界的属性,所以执行put的操作的时候是不存在阻塞情况的,而take操作在队列为空的状态时就会被阻塞。

SynchronousQueue

/**
 * @since 1.5
 * @author Doug Lea and Bill Scherer and Michael Scott
 * @param <E> the type of elements held in this collection
 */
public class SynchronousQueue<E> extends AbstractQueue<E>
    implements BlockingQueue<E>, java.io.Serializable {

    /**
     * Shared internal API for dual stacks and queues.
     */
    abstract static class Transferer<E> {
        /**
         * Performs a put or take.
         *
         * @param e if non-null, the item to be handed to a consumer;
         *          if null, requests that transfer return an item
         *          offered by producer.
         * @param timed if this operation should timeout
         * @param nanos the timeout, in nanoseconds
         * @return if non-null, the item provided or received; if null,
         *         the operation failed due to timeout or interrupt --
         *         the caller can distinguish which of these occurred
         *         by checking Thread.interrupted.
         */
        abstract E transfer(E e, boolean timed, long nanos);
    }

    /**
     * Creates a {@code SynchronousQueue} with nonfair access policy.
     */
    public SynchronousQueue() {
        this(false);
    }

    /**
     * Creates a {@code SynchronousQueue} with the specified fairness policy.
     *
     * @param fair if true, waiting threads contend in FIFO order for
     *        access; otherwise the order is unspecified.
     */
    public SynchronousQueue(boolean fair) {
        transferer = fair ? new TransferQueue<E>() : new TransferStack<E>();
    }
    
    /**
     * Always returns {@code true}.
     * A {@code SynchronousQueue} has no internal capacity.
     *
     * @return {@code true}
     */
    public boolean isEmpty() {
        return true;
    }

    /**
     * Always returns zero.
     * A {@code SynchronousQueue} has no internal capacity.
     *
     * @return zero
     */
    public int size() {
        return 0;
    }

    /**
     * Always returns zero.
     * A {@code SynchronousQueue} has no internal capacity.
     *
     * @return zero
     */
    public int remainingCapacity() {
        return 0;
    }
}

SynchronouseQueue是一个不存储元素的队列,即容量为0,它完成的是直接传递的队列,从isEmpty()方法一直返回true可知。对应该队列的每一个put操作必须等待下一操作,即一个插入操作要等待一个移除操作,否则就不能进行下一次的添加元素操作。他支持公平访问队列方式,默认情况下线程采用非公平性策略访问队列。

  SynchronousQueue<E> queue = new SynchronousQueue<E>(true); //设置公平性访问策略
  public SynchronousQueue(boolean fair) {
        transferer = fair ? new TransferQueue<E>() : new TransferStack<E>();
    }

SynchronousQueue队列负责把生产者线程处理的数据直接传递给消费者线程,本身并不会存储任何线程,所以非常适合传递性场景,且SynchronousQueue的吞吐量会高于LinkedBlockingQueue和ArrayBlockingQueue。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值