Queue队列家族介绍

微信公众号文章列表:关注公众号(coding_song)阅读更清晰,附件为微信二维码

 

Queue

队列接口,是一个为在处理前保存元素而设计的集合

Queue接口方法

add(E e):向集合中添加一个元素,如果是容量受限的队列(有界队列),当队列已满后,继续向队列中添加元素,将会抛异常,添加成功后,返回true
offer(E e):向集合中添加一个元素,如果是容量受限的队列(有界队列),当队列已满后,继续向队列中添加元素,将会返回false,否则返回true

remove():获取并删除队列中的头元素,当队列为空时,调用此方法,将会抛出异常,删除成功后,返回被删除的元素对象
poll():获取并删除队列中的头元素,当队列为空时,返回null,否则返回被删除的元素对象
element():获取队列中的头元素,当队列为空时,将抛出异常,否则返回队列的头元素
peek():获取队列中的头元素,当队列为空时,返回null,否则返回队列的头元素

BlockingQueue

阻塞队列接口,继承Queue接口,阻塞队列中的方法有4中形式,1)直接抛出一个异常;2)返回一个特定的值null或false等;3)无限期阻塞当前线程直到满足条件才继续后续操作;4)在给定的最大时间限制内阻塞;阻塞队列中的所有实现都是线程安全的,如果队列中没有元素,当获取队列中的元素时,将会一直阻塞,直到队列中有值后,才会返回元素内容;当向队列中添加元素时,如果队列已满,将会一直阻塞,直到队列中有空间时,才会将元素添加到队列中;

BlockingQueue接口方法

put(E e):向队列中添加元素,当队列已满时,将会一直阻塞,直到队列有空间时,才会成功将数据添加到队列中
offer(E e,long timeout,TimeUnit unit):将指定的元素插入到队列中,如有必要,等待指定的等待时间以使空间可用,在timeout时间后,如果队列中还是没有空间可用,将会抛出异常
take():获取并移除头元素,当队列中没有元素时,将会一直阻塞,直到有元素时,将会移除队列的头元素
poll(long timeout,TimeUnit unit):检索并删除此队列的头元素,如果需要,可等待指定的等待时间以使元素可用
drainTo(Collection<?superE> c):移除队列中的所有元素,并将这些元素添加到给定的集合中

Queue实现类

无界队列:PriorityBlockingQueue、ConcurrentLinkedQueue
有界队列:ArrayBlockingQueue、LinkedBlockingQueue、SynchronousQueue
阻塞队列:ArrayBlockingQueue、LinkedBlockingQueue、PriorityBlockingQueue

阻塞队列实现类PriorityBlockingQueue、ArrayBlockingQueue、LinkedBlockingQueue等都是线程安全的,内部调用ReentrantLock的lock或lockInterruptibly方法进行加锁,等待逻辑执行完成后,使用调用unlock释放锁

PriorityBlockingQueue:是一个使用与类PriorityQueue相同的排序规则并提供阻塞检索操作的无边界阻塞优先级队列,优先级队列不允许使用null元素,依赖自然排序的优先级队列不允许插入不能比较的对象
ConcurrentLinkedQueue:是一个基于链表节点的、线程安全的无界队列,遵循先进先出规则,队列中的头元素是队列中时间最长的元素,尾元素是队列中时间最短的元素;添加元素时,从队列尾添加元素,读取元素时,从队列的头读取元素;当多个线程需要共享一个集合时,可以使用ConcurrentLinkedQueue来保存集合,此集合不允许使用null元素
ArrayBlockingQueue:是一个由数组组成的有界阻塞队列,此队列遵循先进先出的原则,队列中的头元素是队列中时间最长的元素,尾元素是队列中时间最短的元素;添加元素时,从队列尾添加元素,读取元素时,从队列的头读取元素;这是一个景点的有界缓冲队列,是一个有生产者添加数据、消费者读取数据的固定大小的数组;一旦创建好ArrayBlockingQueue,其容量大小不可改变
LinkedBlockingQueue:是一个基于链接节点的、大小可选的有界阻塞队列,此队列遵循先进先出原则,队列中的头元素是队列中时间最长的元素,尾元素是队列中时间最短的元素;添加元素时,从队列尾添加元素,读取元素时,从队列的头读取元素;此队列比ArrayBlockingQueue具有更高的吞吐量,但其性能不好预测
SynchronousQueue:阻塞队列,其中每个put/offer操作必须等待另一个线程执行相应的take/poll操作,反之亦然;其内部没有数据缓存空间,不用来保存数据;数据是在配对的生产者和消费者线程之间直接传递的,并不会将数据缓冲数据到队列中,使用示例如下

  1. publicstaticvoid main(String[] args)throwsInterruptedException{

  2.    SynchronousQueue queue =newSynchronousQueue();

  3.    Runnable offer =()->{

  4.        try{

  5.            queue.offer(1,1000,TimeUnit.MILLISECONDS);

  6.        }catch(InterruptedException e){

  7.            e.printStackTrace();

  8.        }

  9.    };

  10.    Runnable poll =()->System.out.println("test SynchronousQueue:" + queue.poll());

  11.    newThread(offer).start();

  12.    Thread.sleep(1000);

  13.    newThread(poll).start();

  14. }

创建offer生产者线程和poll消费者线程,然后启动两个线程,最终生产者线程将数据传递给消费者线程,打印结果为:testSynchronousQueue:1

推荐阅读:回首过往、展望未来

扫码关注获取更多文章

猜你喜欢

转载自itxiaojiang.iteye.com/blog/2436425
今日推荐