java+arrayblockquene_Java多线程系列--“JUC集合”07之 ArrayBlockingQueue

1 /*

2 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.3 *4 *5 *6 *7 *8 *9 *10 *11 *12 *13 *14 *15 *16 *17 *18 *19 *20 *21 *22 *23 */

24

25 /*

26 *27 *28 *29 *30 *31 * Written by Doug Lea with assistance from members of JCP JSR-16632 * Expert Group and released to the public domain, as explained at33 *http://creativecommons.org/publicdomain/zero/1.0/

34 */

35

36 packagejava.util.concurrent;37 import java.util.concurrent.locks.*;38 import java.util.*;39

40 /**

41 * A bounded {@linkplainBlockingQueue blocking queue} backed by an42 * array. This queue orders elements FIFO (first-in-first-out). The43 * head of the queue is that element that has been on the44 * queue the longest time. The tail of the queue is that45 * element that has been on the queue the shortest time. New elements46 * are inserted at the tail of the queue, and the queue retrieval47 * operations obtain elements at the head of the queue.48 *49 *

This is a classic "bounded buffer", in which a50 * fixed-sized array holds elements inserted by producers and51 * extracted by consumers. Once created, the capacity cannot be52 * changed. Attempts to {@codeput} an element into a full queue53 * will result in the operation blocking; attempts to {@codetake} an54 * element from an empty queue will similarly block.55 *56 *

This class supports an optional fairness policy for ordering57 * waiting producer and consumer threads. By default, this ordering58 * is not guaranteed. However, a queue constructed with fairness set59 * to {@codetrue} grants threads access in FIFO order. Fairness60 * generally decreases throughput but reduces variability and avoids61 * starvation.62 *63 *

This class and its iterator implement all of the64 * optional methods of the {@linkCollection} and {@link

65 * Iterator} interfaces.66 *67 *

This class is a member of the68 * 69 * Java Collections Framework.70 *71 *@since1.572 *@authorDoug Lea73 *@param the type of elements held in this collection74 */

75 public class ArrayBlockingQueue extends AbstractQueue

76 implements BlockingQueue, java.io.Serializable {77

78 /**

79 * Serialization ID. This class relies on default serialization80 * even for the items array, which is default-serialized, even if81 * it is empty. Otherwise it could not be declared final, which is82 * necessary here.83 */

84 private static final long serialVersionUID = -817911632652898426L;85

86 /**The queued items*/

87 finalObject[] items;88

89 /**items index for next take, poll, peek or remove*/

90 inttakeIndex;91

92 /**items index for next put, offer, or add*/

93 intputIndex;94

95 /**Number of elements in the queue*/

96 intcount;97

98 /*

99 * Concurrency control uses the classic two-condition algorithm100 * found in any textbook.101 */

102

103 /**Main lock guarding all access*/

104 finalReentrantLock lock;105 /**Condition for waiting takes*/

106 private finalCondition notEmpty;107 /**Condition for waiting puts*/

108 private finalCondition notFull;109

110 //Internal helper methods

111

112 /**

113 * Circularly increment i.114 */

115 final int inc(inti) {116 return (++i == items.length) ? 0: i;117 }118

119 /**

120 * Circularly decrement i.121 */

122 final int dec(inti) {123 return ((i == 0) ? items.length : i) - 1;124 }125

126 @SuppressWarnings("unchecked")127 static E cast(Object item) {128 return(E) item;129 }130

131 /**

132 * Returns item at index i.133 */

134 final E itemAt(inti) {135 return this.cast(items[i]);136 }137

138 /**

139 * Throws NullPointerException if argument is null.140 *141 *@paramv the element142 */

143 private static voidcheckNotNull(Object v) {144 if (v == null)145 throw newNullPointerException();146 }147

148 /**

149 * Inserts element at current put position, advances, and signals.150 * Call only when holding lock.151 */

152 private voidinsert(E x) {153 items[putIndex] =x;154 putIndex =inc(putIndex);155 ++count;156 notEmpty.signal();157 }158

159 /**

160 * Extracts element at current take position, advances, and signals.161 * Call only when holding lock.162 */

163 privateE extract() {164 final Object[] items = this.items;165 E x = this.cast(items[takeIndex]);166 items[takeIndex] = null;167 takeIndex =inc(takeIndex);168 --count;169 notFull.signal();170 returnx;171 }172

173 /**

174 * Deletes item at position i.175 * Utility for remove and iterator.remove.176 * Call only when holding lock.177 */

178 void removeAt(inti) {179 final Object[] items = this.items;180 //if removing front item, just advance

181 if (i ==takeIndex) {182 items[takeIndex] = null;183 takeIndex =inc(takeIndex);184 } else{185 //slide over all others up through putIndex.

186 for(;;) {187 int nexti =inc(i);188 if (nexti !=putIndex) {189 items[i] =items[nexti];190 i =nexti;191 } else{192 items[i] = null;193 putIndex =i;194 break;195 }196 }197 }198 --count;199 notFull.signal();200 }201

202 /**

203 * Creates an {@codeArrayBlockingQueue} with the given (fixed)204 * capacity and default access policy.205 *206 *@paramcapacity the capacity of this queue207 *@throwsIllegalArgumentException if {@codecapacity < 1}208 */

209 public ArrayBlockingQueue(intcapacity) {210 this(capacity, false);211 }212

213 /**

214 * Creates an {@codeArrayBlockingQueue} with the given (fixed)215 * capacity and the specified access policy.216 *217 *@paramcapacity the capacity of this queue218 *@paramfair if {@codetrue} then queue accesses for threads blocked219 * on insertion or removal, are processed in FIFO order;220 * if {@codefalse} the access order is unspecified.221 *@throwsIllegalArgumentException if {@codecapacity < 1}222 */

223 public ArrayBlockingQueue(int capacity, booleanfair) {224 if (capacity <= 0)225 throw newIllegalArgumentException();226 this.items = newObject[capacity];227 lock = newReentrantLock(fair);228 notEmpty =lock.newCondition();229 notFull =lock.newCondition();230 }231

232 /**

233 * Creates an {@codeArrayBlockingQueue} with the given (fixed)234 * capacity, the specified access policy and initially containing the235 * elements of the given collection,236 * added in traversal order of the collection's iterator.237 *238 *@paramcapacity the capacity of this queue239 *@paramfair if {@codetrue} then queue accesses for threads blocked240 * on insertion or removal, are processed in FIFO order;241 * if {@codefalse} the access order is unspecified.242 *@paramc the collection of elements to initially contain243 *@throwsIllegalArgumentException if {@codecapacity} is less than244 * {@codec.size()}, or less than 1.245 *@throwsNullPointerException if the specified collection or any246 * of its elements are null247 */

248 public ArrayBlockingQueue(int capacity, booleanfair,249 Collection extends E>c) {250 this(capacity, fair);251

252 final ReentrantLock lock = this.lock;253 lock.lock(); //Lock only for visibility, not mutual exclusion

254 try{255 int i = 0;256 try{257 for(E e : c) {258 checkNotNull(e);259 items[i++] =e;260 }261 } catch(ArrayIndexOutOfBoundsException ex) {262 throw newIllegalArgumentException();263 }264 count =i;265 putIndex = (i == capacity) ? 0: i;266 } finally{267 lock.unlock();268 }269 }270

271 /**

272 * Inserts the specified element at the tail of this queue if it is273 * possible to do so immediately without exceeding the queue's capacity,274 * returning {@codetrue} upon success and throwing an275 * {@codeIllegalStateException} if this queue is full.276 *277 *@parame the element to add278 *@return{@codetrue} (as specified by {@linkCollection#add})279 *@throwsIllegalStateException if this queue is full280 *@throwsNullPointerException if the specified element is null281 */

282 public booleanadd(E e) {283 return super.add(e);284 }285

286 /**

287 * Inserts the specified element at the tail of this queue if it is288 * possible to do so immediately without exceeding the queue's capacity,289 * returning {@codetrue} upon success and {@codefalse} if this queue290 * is full. This method is generally preferable to method {@link#add},291 * which can fail to insert an element only by throwing an exception.292 *293 *@throwsNullPointerException if the specified element is null294 */

295 public booleanoffer(E e) {296 checkNotNull(e);297 final ReentrantLock lock = this.lock;298 lock.lock();299 try{300 if (count ==items.length)301 return false;302 else{303 insert(e);304 return true;305 }306 } finally{307 lock.unlock();308 }309 }310

311 /**

312 * Inserts the specified element at the tail of this queue, waiting313 * for space to become available if the queue is full.314 *315 *@throwsInterruptedException {@inheritDoc}316 *@throwsNullPointerException {@inheritDoc}317 */

318 public void put(E e) throwsInterruptedException {319 checkNotNull(e);320 final ReentrantLock lock = this.lock;321 lock.lockInterruptibly();322 try{323 while (count ==items.length)324 notFull.await();325 insert(e);326 } finally{327 lock.unlock();328 }329 }330

331 /**

332 * Inserts the specified element at the tail of this queue, waiting333 * up to the specified wait time for space to become available if334 * the queue is full.335 *336 *@throwsInterruptedException {@inheritDoc}337 *@throwsNullPointerException {@inheritDoc}338 */

339 public boolean offer(E e, longtimeout, TimeUnit unit)340 throwsInterruptedException {341

342 checkNotNull(e);343 long nanos =unit.toNanos(timeout);344 final ReentrantLock lock = this.lock;345 lock.lockInterruptibly();346 try{347 while (count ==items.length) {348 if (nanos <= 0)349 return false;350 nanos =notFull.awaitNanos(nanos);351 }352 insert(e);353 return true;354 } finally{355 lock.unlock();356 }357 }358

359 publicE poll() {360 final ReentrantLock lock = this.lock;361 lock.lock();362 try{363 return (count == 0) ? null: extract();364 } finally{365 lock.unlock();366 }367 }368

369 public E take() throwsInterruptedException {370 final ReentrantLock lock = this.lock;371 lock.lockInterruptibly();372 try{373 while (count == 0)374 notEmpty.await();375 returnextract();376 } finally{377 lock.unlock();378 }379 }380

381 public E poll(long timeout, TimeUnit unit) throwsInterruptedException {382 long nanos =unit.toNanos(timeout);383 final ReentrantLock lock = this.lock;384 lock.lockInterruptibly();385 try{386 while (count == 0) {387 if (nanos <= 0)388 return null;389 nanos =notEmpty.awaitNanos(nanos);390 }391 returnextract();392 } finally{393 lock.unlock();394 }395 }396

397 publicE peek() {398 final ReentrantLock lock = this.lock;399 lock.lock();400 try{401 return (count == 0) ? null: itemAt(takeIndex);402 } finally{403 lock.unlock();404 }405 }406

407 //this doc comment is overridden to remove the reference to collections408 //greater in size than Integer.MAX_VALUE

409 /**

410 * Returns the number of elements in this queue.411 *412 *@returnthe number of elements in this queue413 */

414 public intsize() {415 final ReentrantLock lock = this.lock;416 lock.lock();417 try{418 returncount;419 } finally{420 lock.unlock();421 }422 }423

424 //this doc comment is a modified copy of the inherited doc comment,425 //without the reference to unlimited queues.

426 /**

427 * Returns the number of additional elements that this queue can ideally428 * (in the absence of memory or resource constraints) accept without429 * blocking. This is always equal to the initial capacity of this queue430 * less the current {@codesize} of this queue.431 *432 *

Note that you cannot always tell if an attempt to insert433 * an element will succeed by inspecting {@coderemainingCapacity}434 * because it may be the case that another thread is about to435 * insert or remove an element.436 */

437 public intremainingCapacity() {438 final ReentrantLock lock = this.lock;439 lock.lock();440 try{441 return items.length -count;442 } finally{443 lock.unlock();444 }445 }446

447 /**

448 * Removes a single instance of the specified element from this queue,449 * if it is present. More formally, removes an element {@codee} such450 * that {@codeo.equals(e)}, if this queue contains one or more such451 * elements.452 * Returns {@codetrue} if this queue contained the specified element453 * (or equivalently, if this queue changed as a result of the call).454 *455 *

Removal of interior elements in circular array based queues456 * is an intrinsically slow and disruptive operation, so should457 * be undertaken only in exceptional circumstances, ideally458 * only when the queue is known not to be accessible by other459 * threads.460 *461 *@paramo element to be removed from this queue, if present462 *@return{@codetrue} if this queue changed as a result of the call463 */

464 public booleanremove(Object o) {465 if (o == null) return false;466 final Object[] items = this.items;467 final ReentrantLock lock = this.lock;468 lock.lock();469 try{470 for (int i = takeIndex, k = count; k > 0; i = inc(i), k--) {471 if(o.equals(items[i])) {472 removeAt(i);473 return true;474 }475 }476 return false;477 } finally{478 lock.unlock();479 }480 }481

482 /**

483 * Returns {@codetrue} if this queue contains the specified element.484 * More formally, returns {@codetrue} if and only if this queue contains485 * at least one element {@codee} such that {@codeo.equals(e)}.486 *487 *@paramo object to be checked for containment in this queue488 *@return{@codetrue} if this queue contains the specified element489 */

490 public booleancontains(Object o) {491 if (o == null) return false;492 final Object[] items = this.items;493 final ReentrantLock lock = this.lock;494 lock.lock();495 try{496 for (int i = takeIndex, k = count; k > 0; i = inc(i), k--)497 if(o.equals(items[i]))498 return true;499 return false;500 } finally{501 lock.unlock();502 }503 }504

505 /**

506 * Returns an array containing all of the elements in this queue, in507 * proper sequence.508 *509 *

The returned array will be "safe" in that no references to it are510 * maintained by this queue. (In other words, this method must allocate511 * a new array). The caller is thus free to modify the returned array.512 *513 *

This method acts as bridge between array-based and collection-based514 * APIs.515 *516 *@returnan array containing all of the elements in this queue517 */

518 publicObject[] toArray() {519 final Object[] items = this.items;520 final ReentrantLock lock = this.lock;521 lock.lock();522 try{523 final int count = this.count;524 Object[] a = newObject[count];525 for (int i = takeIndex, k = 0; k < count; i = inc(i), k++)526 a[k] =items[i];527 returna;528 } finally{529 lock.unlock();530 }531 }532

533 /**

534 * Returns an array containing all of the elements in this queue, in535 * proper sequence; the runtime type of the returned array is that of536 * the specified array. If the queue fits in the specified array, it537 * is returned therein. Otherwise, a new array is allocated with the538 * runtime type of the specified array and the size of this queue.539 *540 *

If this queue fits in the specified array with room to spare541 * (i.e., the array has more elements than this queue), the element in542 * the array immediately following the end of the queue is set to543 * {@codenull}.544 *545 *

Like the {@link#toArray()} method, this method acts as bridge between546 * array-based and collection-based APIs. Further, this method allows547 * precise control over the runtime type of the output array, and may,548 * under certain circumstances, be used to save allocation costs.549 *550 *

Suppose {@codex} is a queue known to contain only strings.551 * The following code can be used to dump the queue into a newly552 * allocated array of {@codeString}:553 *554 *

555 *     String[] y = x.toArray(new String[0]);
556 *557 * Note that {@codetoArray(new Object[0])} is identical in function to558 * {@codetoArray()}.559 *560 *@parama the array into which the elements of the queue are to561 * be stored, if it is big enough; otherwise, a new array of the562 * same runtime type is allocated for this purpose563 *@returnan array containing all of the elements in this queue564 *@throwsArrayStoreException if the runtime type of the specified array565 * is not a supertype of the runtime type of every element in566 * this queue567 *@throwsNullPointerException if the specified array is null568 */

569 @SuppressWarnings("unchecked")570 public T[] toArray(T[] a) {571 final Object[] items = this.items;572 final ReentrantLock lock = this.lock;573 lock.lock();574 try{575 final int count = this.count;576 final int len =a.length;577 if (len count)583 a[count] = null;584 returna;585 } finally{586 lock.unlock();587 }588 }589

590 publicString toString() {591 final ReentrantLock lock = this.lock;592 lock.lock();593 try{594 int k =count;595 if (k == 0)596 return "[]";597

598 StringBuilder sb = newStringBuilder();599 sb.append('[');600 for (int i = takeIndex; ; i =inc(i)) {601 Object e =items[i];602 sb.append(e == this ? "(this Collection)": e);603 if (--k == 0)604 return sb.append(']').toString();605 sb.append(',').append(' ');606 }607 } finally{608 lock.unlock();609 }610 }611

612 /**

613 * Atomically removes all of the elements from this queue.614 * The queue will be empty after this call returns.615 */

616 public voidclear() {617 final Object[] items = this.items;618 final ReentrantLock lock = this.lock;619 lock.lock();620 try{621 for (int i = takeIndex, k = count; k > 0; i = inc(i), k--)622 items[i] = null;623 count = 0;624 putIndex = 0;625 takeIndex = 0;626 notFull.signalAll();627 } finally{628 lock.unlock();629 }630 }631

632 /**

633 *@throwsUnsupportedOperationException {@inheritDoc}634 *@throwsClassCastException {@inheritDoc}635 *@throwsNullPointerException {@inheritDoc}636 *@throwsIllegalArgumentException {@inheritDoc}637 */

638 public int drainTo(Collection super E>c) {639 checkNotNull(c);640 if (c == this)641 throw newIllegalArgumentException();642 final Object[] items = this.items;643 final ReentrantLock lock = this.lock;644 lock.lock();645 try{646 int i =takeIndex;647 int n = 0;648 int max =count;649 while (n cast(items[i]));651 items[i] = null;652 i =inc(i);653 ++n;654 }655 if (n > 0) {656 count = 0;657 putIndex = 0;658 takeIndex = 0;659 notFull.signalAll();660 }661 returnn;662 } finally{663 lock.unlock();664 }665 }666

667 /**

668 *@throwsUnsupportedOperationException {@inheritDoc}669 *@throwsClassCastException {@inheritDoc}670 *@throwsNullPointerException {@inheritDoc}671 *@throwsIllegalArgumentException {@inheritDoc}672 */

673 public int drainTo(Collection super E> c, intmaxElements) {674 checkNotNull(c);675 if (c == this)676 throw newIllegalArgumentException();677 if (maxElements <= 0)678 return 0;679 final Object[] items = this.items;680 final ReentrantLock lock = this.lock;681 lock.lock();682 try{683 int i =takeIndex;684 int n = 0;685 int max = (maxElements < count) ?maxElements : count;686 while (n cast(items[i]));688 items[i] = null;689 i =inc(i);690 ++n;691 }692 if (n > 0) {693 count -=n;694 takeIndex =i;695 notFull.signalAll();696 }697 returnn;698 } finally{699 lock.unlock();700 }701 }702

703 /**

704 * Returns an iterator over the elements in this queue in proper sequence.705 * The elements will be returned in order from first (head) to last (tail).706 *707 *

The returned {@codeIterator} is a "weakly consistent" iterator that708 * will never throw {@linkjava.util.ConcurrentModificationException709 * ConcurrentModificationException},710 * and guarantees to traverse elements as they existed upon711 * construction of the iterator, and may (but is not guaranteed to)712 * reflect any modifications subsequent to construction.713 *714 *@returnan iterator over the elements in this queue in proper sequence715 */

716 public Iteratoriterator() {717 return newItr();718 }719

720 /**

721 * Iterator for ArrayBlockingQueue. To maintain weak consistency722 * with respect to puts and takes, we (1) read ahead one slot, so723 * as to not report hasNext true but then not have an element to724 * return -- however we later recheck this slot to use the most725 * current value; (2) ensure that each array slot is traversed at726 * most once (by tracking "remaining" elements); (3) skip over727 * null slots, which can occur if takes race ahead of iterators.728 * However, for circular array-based queues, we cannot rely on any729 * well established definition of what it means to be weakly730 * consistent with respect to interior removes since these may731 * require slot overwrites in the process of sliding elements to732 * cover gaps. So we settle for resiliency, operating on733 * established apparent nexts, which may miss some elements that734 * have moved between calls to next.735 */

736 private class Itr implements Iterator{737 private int remaining; //Number of elements yet to be returned

738 private int nextIndex; //Index of element to be returned by next

739 private E nextItem; //Element to be returned by next call to next

740 private E lastItem; //Element returned by last call to next

741 private int lastRet; //Index of last element returned, or -1 if none

742

743 Itr() {744 final ReentrantLock lock = ArrayBlockingQueue.this.lock;745 lock.lock();746 try{747 lastRet = -1;748 if ((remaining = count) > 0)749 nextItem = itemAt(nextIndex =takeIndex);750 } finally{751 lock.unlock();752 }753 }754

755 public booleanhasNext() {756 return remaining > 0;757 }758

759 publicE next() {760 final ReentrantLock lock = ArrayBlockingQueue.this.lock;761 lock.lock();762 try{763 if (remaining <= 0)764 throw newNoSuchElementException();765 lastRet =nextIndex;766 E x = itemAt(nextIndex); //check for fresher value

767 if (x == null) {768 x = nextItem; //we are forced to report old value

769 lastItem = null; //but ensure remove fails

770 }771 else

772 lastItem =x;773 while (--remaining > 0 && //skip over nulls

774 (nextItem = itemAt(nextIndex = inc(nextIndex))) == null)775 ;776 returnx;777 } finally{778 lock.unlock();779 }780 }781

782 public voidremove() {783 final ReentrantLock lock = ArrayBlockingQueue.this.lock;784 lock.lock();785 try{786 int i =lastRet;787 if (i == -1)788 throw newIllegalStateException();789 lastRet = -1;790 E x =lastItem;791 lastItem = null;792 //only remove if item still at index

793 if (x != null && x ==items[i]) {794 boolean removingHead = (i ==takeIndex);795 removeAt(i);796 if (!removingHead)797 nextIndex =dec(nextIndex);798 }799 } finally{800 lock.unlock();801 }802 }803 }804

805 }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值