集合
框架关系图:
Collection接口下面有三个子接口:List、Set、Queue。此篇是关于Queue<E>的简单学习总结。
补充:HashTable父类是Dictionary,不是AbstractMap。
Queue:
Queue(队列):是一种特殊的链型结构,它的特点是先进先出(FIFO),通常只在尾部插入,头部删除,它经常和Stack(栈)进行比较,但Stack的特点是先进后出。注意:队列通常但不一定是以FIFO(先进先出)方式排序元素。 除了优先级队列之外,优先级队列是根据提供的比较器对元素进行排序,还是元素的自然排序,以及对元素LIFO(先进先出)进行排序的LIFO队列(或堆栈)。 无论使用什么顺序,队列的头都是通过调用remove()或poll()删除的元素。
-
方法摘要
Modifier and Type 方法 描述 boolean
add(E e)
将指定的元素插入到此队列中,如果可以立即执行此操作而不违反容量限制,true
成功返回true
,如果当前没有可用的空间,则抛出IllegalStateException
。E
element()
检索,但不删除,这个队列的头。boolean
offer(E e)
如果在不违反容量限制的情况下立即执行,则将指定的元素插入到此队列中。E
peek()
检索但不删除此队列的头,如果此队列为空,则返回null
。E
poll()
检索并删除此队列的头部,如果此队列为空,则返回null
。E
remove()
检索并删除此队列的头。
队列分为阻塞队列和非阻塞队列(平时常见的为非阻塞队列,例如:LinkedList)。
非阻塞队列:
在进行“当队列为空去删除队列中的数据”和“当队列已满继续往里追加数据”时不会进行阻塞,所以在开发中为了维护项目的稳定与数据安全就需要在其他逻辑中增添相应的处理方法。对于非阻塞队列,一般情况下建议使用offer、poll和peek三个方法,不建议使用add和remove方法。因为使用offer、poll和peek三个方法可以通过返回值判断操作成功与否,而使用add和remove方法却不能达到这样的效果。注意,非阻塞队列中的方法都没有进行同步措施。
阻塞队列:
和非阻塞队列不同的是,当线程在进行“当队列为空去删除队列中的数据”和“当队列已满继续往里追加数据”两种操作时,线程会被阻塞住,当队列不为空或者没有满的时候,被阻塞的线程会自动被唤醒然后进行后续的逻辑运行(其实原理是在非阻塞队列的方法中,加了“锁”(Lock),当线程可运行了再“解锁”)。
自从Java 1.5之后,在java.util.concurrent包下提供了若干个阻塞队列,主要有以下几个:
- ArrayBlockingQueue:基于数组实现的一个阻塞队列,在创建ArrayBlockingQueue对象时必须制定容量大小。并且可以指定公平性与非公平性,默认情况下为非公平的,即不保证等待时间最长的队列最优先能够访问队列。
- LinkedBlockingQueue:基于链表实现的一个阻塞队列,在创建LinkedBlockingQueue对象时如果不指定容量大小,则默认大小为Integer.MAX_VALUE。
- PriorityBlockingQueue:以上2种队列都是先进先出队列,而PriorityBlockingQueue却不是,它会按照元素的优先级对元素进行排序,按照优先级顺序出队,每次出队的元素都是优先级最高的元素。注意,此阻塞队列为无界阻塞队列,即容量没有上限(通过源码就可以知道,它没有容器满的信号标志),前面2种都是有界队列。
- DelayQueue:基于PriorityQueue,一种延时阻塞队列,DelayQueue中的元素只有当其指定的延迟时间到了,才能够从队列中获取到该元素。DelayQueue也是一个无界队列,因此往队列中插入数据的操作(生产者)永远不会被阻塞,而只有获取数据的操作(消费者)才会被阻塞。
1 final ReentrantLock lock; 2 3 private final Condition notEmpty; 4 5 private final Condition notFull; 6 7 public ArrayBlockingQueue(int capacity) { 8 this(capacity, false); 9 } 10 11 public ArrayBlockingQueue(int capacity, boolean fair) { 12 if (capacity <= 0) 13 throw new IllegalArgumentException(); 14 this.items = new Object[capacity]; 15 lock = new ReentrantLock(fair); 16 notEmpty = lock.newCondition(); 17 notFull = lock.newCondition(); 18 } 19 20 public ArrayBlockingQueue(int capacity, boolean fair, 21 Collection<? extends E> c) { 22 this(capacity, fair); 23 24 final ReentrantLock lock = this.lock; 25 lock.lock(); // Lock only for visibility, not mutual exclusion 26 try { 27 int i = 0; 28 try { 29 for (E e : c) { 30 checkNotNull(e); 31 items[i++] = e; 32 } 33 } catch (ArrayIndexOutOfBoundsException ex) { 34 throw new IllegalArgumentException(); 35 } 36 count = i; 37 putIndex = (i == capacity) ? 0 : i; 38 } finally { 39 lock.unlock(); 40 } 41 } 42 43 public boolean offer(E e) { 44 checkNotNull(e); 45 final ReentrantLock lock = this.lock; 46 lock.lock(); 47 try { 48 if (count == items.length) 49 return false; 50 else { 51 enqueue(e); 52 return true; 53 } 54 } finally { 55 lock.unlock(); 56 } 57 } 58 59 public void put(E e) throws InterruptedException { 60 checkNotNull(e); 61 final ReentrantLock lock = this.lock; 62 lock.lockInterruptibly(); 63 try { 64 while (count == items.length) 65 notFull.await(); 66 enqueue(e); 67 } finally { 68 lock.unlock(); 69 } 70 } 71 72 public E poll() { 73 final ReentrantLock lock = this.lock; 74 lock.lock(); 75 try { 76 return (count == 0) ? null : dequeue(); 77 } finally { 78 lock.unlock(); 79 } 80 } 81 82 public E take() throws InterruptedException { 83 final ReentrantLock lock = this.lock; 84 lock.lockInterruptibly(); 85 try { 86 while (count == 0) 87 notEmpty.await(); 88 return dequeue(); 89 } finally { 90 lock.unlock(); 91 } 92 } 93 94 public E poll(long timeout, TimeUnit unit) throws InterruptedException { 95 long nanos = unit.toNanos(timeout); 96 final ReentrantLock lock = this.lock; 97 lock.lockInterruptibly(); 98 try { 99 while (count == 0) { 100 if (nanos <= 0) 101 return null; 102 nanos = notEmpty.awaitNanos(nanos); 103 } 104 return dequeue(); 105 } finally { 106 lock.unlock(); 107 } 108 }