如果队列满了,添加元素的线程将会陷入等待状态,而队列为空,获取元素的线程将会陷入等待。有了BlockingQueue,我们不需要关心什么时候需要阻塞线程,什么时候需要唤醒线程。这一切都交给了BlockingQueue。

  • ArrayBlockingQueue
    数组结构组成的游街阻塞队列
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();
    }

初始化需要传递容器大小,即数组大小,还有获取元素的线程是否公平,即ReentrantLock构造方法中的数。
添加元素

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

        checkNotNull(e);
        long nanos = unit.toNanos(timeout);
        final ReentrantLock lock = this.lock;
        lock.lockInterruptibly();
        try {
            //等待时间
            while (count == items.length) {
                if (nanos <= 0)
                    return false;
                nanos = notFull.awaitNanos(nanos);
            }
            //将元素添加到数组中,并且唤醒取线程
            enqueue(e);
            return true;
        } finally {
            lock.unlock();
        }
    }

java线程池 阻塞队列长度配置 java线程池队列满了阻塞_java线程池 阻塞队列长度配置

获取元素方法

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)
                    return null;
                nanos = notEmpty.awaitNanos(nanos);
            }
            //从数组中获取元素,唤醒添加线程。
            return dequeue();
        } finally {
            lock.unlock();
        }
    }

java线程池 阻塞队列长度配置 java线程池队列满了阻塞_java线程池 阻塞队列长度配置_02

ArrayBlockingQueue与LinkedBlockingQueue
java线程池 阻塞队列长度配置 java线程池队列满了阻塞_ci_03

  • LinkedBlockingQueue
    链表组成的有界队列
    添加元素
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)
                    return false;
                //陷入等待
                nanos = notFull.awaitNanos(nanos);
            }
            //可以添加元素
            enqueue(new Node<E>(e));
            c = count.getAndIncrement();
            if (c + 1 < capacity)
                //添加元素后没有达到最大的容量阈值,唤醒阻塞在notFull的线程
                notFull.signal();
        } finally {
            putLock.unlock();
        }
        if (c == 0)
            //c为添加之前的链表元素个数。c=0说明添加元素之前,执行拿走线程陷入等待状态,
            //需要唤醒他们去拿走添加的元素
            //可能之前元素充足,各个取线程没有陷入等待,如果没有c==0判断,signalNotEmpty执行没有意义,因为压根就没有线程陷入等待
            // 参考
            signalNotEmpty();
        return true;
    }

java线程池 阻塞队列长度配置 java线程池队列满了阻塞_java线程池 阻塞队列长度配置_04

拉取元素方法

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)
                    return null;
                // 链表元素个数为空,陷入等待
                nanos = notEmpty.awaitNanos(nanos);
            }
            //出队列
            x = dequeue();
            c = count.getAndDecrement();
            if (c > 1)
                //唤醒拿线程
                notEmpty.signal();
        } finally {
            takeLock.unlock();
        }
        if (c == capacity)
            //唤醒添加线程
            signalNotFull();
        return x;
    }

java线程池 阻塞队列长度配置 java线程池队列满了阻塞_java线程池 阻塞队列长度配置_05

  • DelayQueue
    延迟无界阻塞队列,类似于RabbitMq的延迟队列,使用案例如下
BlockingQueue<DelayedItem> blockingQueue=new DelayQueue<>();
		//设置延迟5秒钟
		blockingQueue.add(new DelayedItem(5*1000L));
		long beginTime = System.currentTimeMillis();
		System.out.println(beginTime);
		DelayedItem poll = blockingQueue.poll(60,TimeUnit.SECONDS);
		System.out.println("延迟时间:"+(System.currentTimeMillis()-beginTime));
		System.out.println("获取到的任务,延迟时间:"+poll.getDelayTime());
public static class DelayedItem implements Delayed{
	
		/**
		 * 延迟时间
		 */
		private Long delayTime;

		/**
		 * 到期时间
		 */
		private Long expireTime;
		
		public DelayedItem(Long delayTime) {
			this.delayTime = delayTime;
			this.expireTime=System.currentTimeMillis()+delayTime;
		}

		public Long getDelayTime() {
			return delayTime;
		}

		@Override
		public int compareTo(Delayed o) {
			return (int) (this.getDelay(TimeUnit.MILLISECONDS)-o.getDelay(TimeUnit.MILLISECONDS));
		}

		@Override
		public long getDelay(TimeUnit unit) {
			return expireTime-System.currentTimeMillis();
		}
	}

DelayQueue源码解析
添加任务

public boolean offer(E e) {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            //将e添加到合适的位置,如果构造DelayQueue定义了比较器,会用到Comparator,没有定义比较器,那就用到实现的compareTo方法
            //决定那个任务放到队列中的先后顺序。
            q.offer(e);
            if (q.peek() == e) {
                leader = null;
                available.signal();
            }
            return true;
        } finally {
            lock.unlock();
        }
    }

java线程池 阻塞队列长度配置 java线程池队列满了阻塞_java_06
获取数据

public E poll(long timeout, TimeUnit unit) throws InterruptedException {
        long nanos = unit.toNanos(timeout);
        final ReentrantLock lock = this.lock;
        lock.lockInterruptibly();
        try {
            for (;;) {
                E first = q.peek();
                if (first == null) {
                    if (nanos <= 0)
                        return null;
                    else
                        //没有任务,陷入等待,
                        nanos = available.awaitNanos(nanos);
                } else {
                    long delay = first.getDelay(NANOSECONDS);
                    if (delay <= 0)
                        //获取到的任务延迟时间到了,拉取出来。
                        return q.poll();
                    if (nanos <= 0)
                        //等待的时间到了,直接返回。
                        return null;
                    first = null; // don't retain ref while waiting
                    if (nanos < delay || leader != null)
                        //任务的延迟时间比等待的数据长,再等待一会。
                        nanos = available.awaitNanos(nanos);
                    else {
                        Thread thisThread = Thread.currentThread();
                        leader = thisThread;
                        try {
                            //任务的延迟时间比等待的数据短,等待任务的延迟数据,
                            long timeLeft = available.awaitNanos(delay);
                            nanos -= delay - timeLeft;
                        } finally {
                            if (leader == thisThread)
                                leader = null;
                        }
                    }
                }
            }
        } finally {
            if (leader == null && q.peek() != null)
                available.signal();
            lock.unlock();
        }
    }

java线程池 阻塞队列长度配置 java线程池队列满了阻塞_rabbitmq_07

SynchronousQueue
不存储元素的阻塞队列