详解BlockingQueue

BlockingQueue

  • BlockingQueue接口主要实现: avatar

  • BlockingQueue中特有的put()和take()方法是Blocking的关键,这两个方法可以在队列为满,或者空的时候进行阻塞等到,当有新的任务被拿去执行或新的任务进入队列后,自动将线程唤醒

BlockingQueue的实现与使用

  • 介绍添加元素的几种方法

    1. add():队列已满时,再添加会抛出异常——对应remove()
    2. offer():添加元素后,会返回一个boolean值,看是否添加成功。若队列已满,再添加不会抛异常,但是返回false,表示添加失败——对应poll()
    3. put():队列已满,再添加会阻塞——对应take()
    4. 通过以下字段实现put()和take()

// 1.字段
/** Main lock guarding all access */
final ReentrantLock lock;

/** Condition for waiting takes */
private final Condition notEmpty;

/** Condition for waiting puts */
private final Condition notFull;

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

    public E take() throws InterruptedException {
            final ReentrantLock lock = this.lock;
            lock.lockInterruptibly();
            try {
                while (count == 0)
                    notEmpty.await();
                return dequeue();
            } finally {
                lock.unlock();
            }
        }

几种常见的BlockingQueu:

    1. 直接提交队列:SynchronousQueue,没有容量,所以提交的任务不能保存,总是将任务交给空闲线程,如果没有空闲线程,就创建线程,一旦达到maximumPoolSize就执行拒绝策略
    2. 有界任务队列:ArrayBlockingQueue,当线程池的数量小于corePoolSize时,当有新的任务时,创建线程,达到corePoolSize后,则将任务存到ArrayBlockingQueue中,直到有界队列容量已满时,才可能会将线程数提升到corePoolSize之上。
    3. 无界队列:LinkedBlockingQueue,除非系统资源耗尽,否则不存在任务队列入队失败的情况,因此当线程数达到corePoolSize之后,就不会增加,有新的任务到来时,都会放到无界队列中。
    4. 优先任务队列:PriorityBlockingQueue是带有优先级的队列,特殊的无界队列,理论上来说不是先入先出的,是根据任务的优先级来确定执行顺序
    5. DelayQueue:执行定时任务,将任务按延迟时间长短放入队列中,延迟时间最短的最先被执行,存放在队列头部的是延迟期满后保存时间最长的任务
    6. LinkedTransferQueue,其实和SynchronousQueue类似,当生产者生产出产品后,当先去找是否有消费者,如果有消费者在等待资源,则直接调用transfer()方法将资源给消费者消费,而不会放入队列中如果没有消费者等待,则当生产者调用transfer()方法时会阻塞,而调用其他的方法,如aput()则不会阻塞,会把资源放到队列中,因为put()方法只有在队列满的时候才会阻塞。适用于游戏服务器中,可以是并发时消息传递的效率更高


猜你喜欢

转载自blog.csdn.net/caisongcheng_good/article/details/80588462