Java队列(Queue)的使用

概述

        队列是一种特殊的线性表,遵循的原则就是“先入先出”。在我们日常使用中,经常会用来并发操作数据。在并发编程中,有时候需要使用线程安全的队列。如果要实现一个线程安全的队列通常有两种方式:一种是使用阻塞队列,另一种是使用线程同步锁。

ArrayDueue也实现了Dueue

常用方法

队列常用方法
 boolean offer(E e); 添加一个元素并返回true 如果队列满,则返回false
 E poll(); 移出并返回队列的头元素 如果队列为空,则返回null
 E peek(); 返回队列的头元素 如果队列为空,则返回null
 boolean add(E e); 添加一个元素并返回true 如果队列满,则抛出IllegalStateException异常
 E remove(); 移出并返回头元素 如果队列空,则抛出NoSuchElementException异常
 E element() 返回队列的头元素 如果队列为空,则抛出NoSuchElementException异常
 put()                      添加一个元素   如果队列满,则阻塞     阻塞队列(Blocking queue)提供
 take() 移出并返回头元素 如果队列空,则阻塞     阻塞队列(Blocking queue)提供

什么是阻塞队列?

        阻塞队列与普通队列的区别在于,当队列是空的时,从队列中获取元素的操作将会被阻塞,或者当队列是满时,往队列里添加元素的操作会被阻塞。试图从空的阻塞队列中获取元素的线程将会被阻塞,直到其他的线程往空的队列插入新的元素。同样,试图往已满的阻塞队列中添加新元素的线程同样也会被阻塞,直到其他的线程使队列重新变得空闲起来,如从队列中移除一个或者多个元素,或者完全清空队列.

        假设有一个面包房,里面有一个客人吃面包,一个师傅烤面包。篮子里面最多放2个面包,师傅考完了面包放到篮子里,而客人吃面包则从篮子里面往外拿,为了保证客人吃面包的时候篮子里有面包或者师傅烤面包的时候篮子不会溢出,这时候就需要引用出来阻塞队列的概念,就是我们常说的生产者消费者的模式。

        阻塞队列是一个支持两个附加操作的队列。这两个附加的操作支持阻塞的插入和移除方法。

            1)支持阻塞的插入方法:意思是当队列满时,队列会阻塞插入元素的线程,直到队列不满。

            2)支持阻塞的移除方法:意思是在队列为空时,获取元素的线程会等待队列变为非空。阻塞队列常用于生产者和消费者的场景,生产者是向队列里添加元素的线程,消费者是从队列里取元素的线程。阻塞队列就是生产者用来存放元素、消费者用来获取元素的容器。

        使用非阻塞队列的时候有一个很大问题就是:它不会对当前线程产生阻塞,那么在面对类似消费者-生产者的模型时,就必须额外地实现同步策略以及线程间唤醒策略,这个实现起来就非常麻烦。但是有了阻塞队列就不一样了,它会对当前线程产生阻塞,比如一个线程从一个空的阻塞队列中取元素,此时线程会被阻塞直到阻塞队列中有了元素。当队列中有元素后,被阻塞的线程会自动被唤醒(不需要我们编写代码去唤醒)。这样提供了极大的方便性。

几种主要的阻塞队列

  • ArrayBlockingQueue:基于数组实现的一个阻塞队列,在创建ArrayBlockingQueue对象时必须制定容量大小。并且可以指定公平性与非公平性,默认情况下为非公平的,即不保证等待时间最长的队列最优先能够访问队列。

  • LinkedBlockingQueue:基于链表实现的一个阻塞队列,在创建LinkedBlockingQueue对象时如果不指定容量大小,则默认大小为Integer.MAX_VALUE。

  • PriorityBlockingQueue:以上2种队列都是先进先出队列,而PriorityBlockingQueue却不是,它会按照元素的优先级对元素进行排序,按照优先级顺序出队,每次出队的元素都是优先级最高的元素。注意,此阻塞队列为无界阻塞队列,即容量没有上限(通过源码就可以知道,它没有容器满的信号标志),前面2种都是有界队列。

  • DelayQueue:基于PriorityQueue,一种延时阻塞队列,DelayQueue中的元素只有当其指定的延迟时间到了,才能够从队列中获取到该元素。

常用的非阻塞实现类 

  • PriorityQueue:是一个比较标准的队列实现类。之所以是比较标准的原因是PriorityQueue保存队列元素的顺序并不是按照加入队列的顺序,而是按照队列元素的大小进行重新排序。因此当调用peek()或者是poll()的方法取出队列中的元素通常都是最小的元素。
  • Deque:是Queue接口的子接口,代表一个双端队列。同时Deque不仅可以作为双端队列使用,而且可以被当成栈来使用,所以可以使用出栈,入栈的方法。

  • LinkedList:是List接口的实现类,但是同时也是Deque接口实现类,所以LinkedList既可以当做双端队列来使用,也可以当做栈来使用。

猜你喜欢

转载自blog.csdn.net/JinXYan/article/details/88568027