ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/main/java/util/concurrent/ArrayBlockingQueue.java
Revision: 1.52
Committed: Mon Jul 18 19:14:17 2005 UTC (18 years, 10 months ago) by jsr166
Branch: MAIN
Changes since 1.51: +1 -1 lines
Log Message:
doc fixes

File Contents

# User Rev Content
1 dl 1.2 /*
2     * Written by Doug Lea with assistance from members of JCP JSR-166
3 dl 1.38 * Expert Group and released to the public domain, as explained at
4     * http://creativecommons.org/licenses/publicdomain
5 dl 1.2 */
6    
7 tim 1.1 package java.util.concurrent;
8 dl 1.11 import java.util.concurrent.locks.*;
9 tim 1.1 import java.util.*;
10    
11     /**
12 dl 1.25 * A bounded {@linkplain BlockingQueue blocking queue} backed by an
13     * array. This queue orders elements FIFO (first-in-first-out). The
14     * <em>head</em> of the queue is that element that has been on the
15     * queue the longest time. The <em>tail</em> of the queue is that
16     * element that has been on the queue the shortest time. New elements
17     * are inserted at the tail of the queue, and the queue retrieval
18     * operations obtain elements at the head of the queue.
19 dholmes 1.13 *
20 dl 1.40 * <p>This is a classic &quot;bounded buffer&quot;, in which a
21     * fixed-sized array holds elements inserted by producers and
22     * extracted by consumers. Once created, the capacity cannot be
23 jsr166 1.50 * increased. Attempts to <tt>put</tt> an element into a full queue
24     * will result in the operation blocking; attempts to <tt>take</tt> an
25 dl 1.40 * element from an empty queue will similarly block.
26 dl 1.11 *
27     * <p> This class supports an optional fairness policy for ordering
28 dl 1.42 * waiting producer and consumer threads. By default, this ordering
29     * is not guaranteed. However, a queue constructed with fairness set
30     * to <tt>true</tt> grants threads access in FIFO order. Fairness
31     * generally decreases throughput but reduces variability and avoids
32     * starvation.
33 brian 1.7 *
34 dl 1.43 * <p>This class and its iterator implement all of the
35     * <em>optional</em> methods of the {@link Collection} and {@link
36 jsr166 1.47 * Iterator} interfaces.
37 dl 1.26 *
38 dl 1.41 * <p>This class is a member of the
39     * <a href="{@docRoot}/../guide/collections/index.html">
40     * Java Collections Framework</a>.
41     *
42 dl 1.8 * @since 1.5
43     * @author Doug Lea
44 dl 1.33 * @param <E> the type of elements held in this collection
45 dl 1.8 */
46 dl 1.5 public class ArrayBlockingQueue<E> extends AbstractQueue<E>
47 tim 1.1 implements BlockingQueue<E>, java.io.Serializable {
48    
49 dl 1.36 /**
50 dl 1.42 * Serialization ID. This class relies on default serialization
51     * even for the items array, which is default-serialized, even if
52     * it is empty. Otherwise it could not be declared final, which is
53 dl 1.36 * necessary here.
54     */
55     private static final long serialVersionUID = -817911632652898426L;
56    
57     /** The queued items */
58     private final E[] items;
59 dl 1.8 /** items index for next take, poll or remove */
60 tim 1.12 private transient int takeIndex;
61 dl 1.8 /** items index for next put, offer, or add. */
62 tim 1.12 private transient int putIndex;
63 dl 1.8 /** Number of items in the queue */
64 dl 1.5 private int count;
65 tim 1.12
66 dl 1.5 /*
67 dl 1.36 * Concurrency control uses the classic two-condition algorithm
68 dl 1.5 * found in any textbook.
69     */
70    
71 dl 1.11 /** Main lock guarding all access */
72     private final ReentrantLock lock;
73 dholmes 1.13 /** Condition for waiting takes */
74 dl 1.37 private final Condition notEmpty;
75 dl 1.35 /** Condition for waiting puts */
76 dl 1.37 private final Condition notFull;
77 dl 1.5
78     // Internal helper methods
79    
80     /**
81     * Circularly increment i.
82     */
83 dl 1.40 final int inc(int i) {
84 dl 1.5 return (++i == items.length)? 0 : i;
85     }
86    
87     /**
88 jsr166 1.47 * Inserts element at current put position, advances, and signals.
89 dl 1.9 * Call only when holding lock.
90 dl 1.5 */
91     private void insert(E x) {
92     items[putIndex] = x;
93     putIndex = inc(putIndex);
94     ++count;
95 dl 1.9 notEmpty.signal();
96 tim 1.1 }
97 tim 1.12
98 dl 1.5 /**
99 jsr166 1.47 * Extracts element at current take position, advances, and signals.
100 dl 1.9 * Call only when holding lock.
101 dl 1.5 */
102 dholmes 1.13 private E extract() {
103 dl 1.36 final E[] items = this.items;
104 dl 1.5 E x = items[takeIndex];
105     items[takeIndex] = null;
106     takeIndex = inc(takeIndex);
107     --count;
108 dl 1.9 notFull.signal();
109 dl 1.5 return x;
110     }
111    
112     /**
113 tim 1.12 * Utility for remove and iterator.remove: Delete item at position i.
114 dl 1.9 * Call only when holding lock.
115 dl 1.5 */
116     void removeAt(int i) {
117 dl 1.36 final E[] items = this.items;
118 dl 1.9 // if removing front item, just advance
119     if (i == takeIndex) {
120     items[takeIndex] = null;
121     takeIndex = inc(takeIndex);
122 tim 1.23 } else {
123 dl 1.9 // slide over all others up through putIndex.
124     for (;;) {
125     int nexti = inc(i);
126     if (nexti != putIndex) {
127     items[i] = items[nexti];
128     i = nexti;
129 tim 1.23 } else {
130 dl 1.9 items[i] = null;
131     putIndex = i;
132     break;
133     }
134 dl 1.5 }
135     }
136 dl 1.9 --count;
137     notFull.signal();
138 tim 1.1 }
139    
140     /**
141 dholmes 1.21 * Creates an <tt>ArrayBlockingQueue</tt> with the given (fixed)
142 dholmes 1.13 * capacity and default access policy.
143 jsr166 1.50 *
144 dholmes 1.13 * @param capacity the capacity of this queue
145 dholmes 1.16 * @throws IllegalArgumentException if <tt>capacity</tt> is less than 1
146 dl 1.5 */
147 dholmes 1.13 public ArrayBlockingQueue(int capacity) {
148 dl 1.36 this(capacity, false);
149 dl 1.5 }
150 dl 1.2
151 dl 1.5 /**
152 dholmes 1.21 * Creates an <tt>ArrayBlockingQueue</tt> with the given (fixed)
153 dholmes 1.13 * capacity and the specified access policy.
154 jsr166 1.50 *
155 dholmes 1.13 * @param capacity the capacity of this queue
156     * @param fair if <tt>true</tt> then queue accesses for threads blocked
157 jsr166 1.50 * on insertion or removal, are processed in FIFO order;
158     * if <tt>false</tt> the access order is unspecified.
159 dholmes 1.16 * @throws IllegalArgumentException if <tt>capacity</tt> is less than 1
160 dl 1.11 */
161 dholmes 1.13 public ArrayBlockingQueue(int capacity, boolean fair) {
162 dl 1.36 if (capacity <= 0)
163     throw new IllegalArgumentException();
164     this.items = (E[]) new Object[capacity];
165     lock = new ReentrantLock(fair);
166     notEmpty = lock.newCondition();
167     notFull = lock.newCondition();
168 dl 1.5 }
169    
170 dholmes 1.16 /**
171 dholmes 1.21 * Creates an <tt>ArrayBlockingQueue</tt> with the given (fixed)
172     * capacity, the specified access policy and initially containing the
173 tim 1.17 * elements of the given collection,
174 dholmes 1.16 * added in traversal order of the collection's iterator.
175 jsr166 1.50 *
176 dholmes 1.16 * @param capacity the capacity of this queue
177     * @param fair if <tt>true</tt> then queue accesses for threads blocked
178 jsr166 1.50 * on insertion or removal, are processed in FIFO order;
179     * if <tt>false</tt> the access order is unspecified.
180 dholmes 1.16 * @param c the collection of elements to initially contain
181     * @throws IllegalArgumentException if <tt>capacity</tt> is less than
182 jsr166 1.50 * <tt>c.size()</tt>, or less than 1.
183     * @throws NullPointerException if the specified collection or any
184     * of its elements are null
185 dholmes 1.16 */
186 tim 1.20 public ArrayBlockingQueue(int capacity, boolean fair,
187 dholmes 1.18 Collection<? extends E> c) {
188 dl 1.36 this(capacity, fair);
189 dholmes 1.16 if (capacity < c.size())
190     throw new IllegalArgumentException();
191    
192 tim 1.20 for (Iterator<? extends E> it = c.iterator(); it.hasNext();)
193     add(it.next());
194 dholmes 1.16 }
195 dl 1.2
196 dholmes 1.13 /**
197 jsr166 1.50 * Inserts the specified element at the tail of this queue if it is
198     * possible to do so immediately without exceeding the queue's capacity,
199     * returning <tt>true</tt> upon success and throwing an
200     * <tt>IllegalStateException</tt> if this queue is full.
201 dl 1.25 *
202 jsr166 1.50 * @param e the element to add
203 jsr166 1.52 * @return <tt>true</tt> (as specified by {@link Collection#add})
204 jsr166 1.50 * @throws IllegalStateException if this queue is full
205     * @throws NullPointerException if the specified element is null
206     */
207     public boolean add(E e) {
208     return super.add(e);
209     }
210    
211     /**
212     * Inserts the specified element at the tail of this queue if it is
213     * possible to do so immediately without exceeding the queue's capacity,
214     * returning <tt>true</tt> upon success and <tt>false</tt> if this queue
215     * is full. This method is generally preferable to method {@link #add},
216     * which can fail to insert an element only by throwing an exception.
217     *
218     * @throws NullPointerException if the specified element is null
219 dholmes 1.13 */
220 jsr166 1.49 public boolean offer(E e) {
221     if (e == null) throw new NullPointerException();
222 dl 1.36 final ReentrantLock lock = this.lock;
223 dl 1.5 lock.lock();
224     try {
225 tim 1.12 if (count == items.length)
226 dl 1.2 return false;
227 dl 1.5 else {
228 jsr166 1.49 insert(e);
229 dl 1.5 return true;
230     }
231 tim 1.23 } finally {
232 tim 1.12 lock.unlock();
233 dl 1.2 }
234 dl 1.5 }
235 dl 1.2
236 dholmes 1.13 /**
237 jsr166 1.50 * Inserts the specified element at the tail of this queue, waiting
238     * for space to become available if the queue is full.
239     *
240     * @throws InterruptedException {@inheritDoc}
241     * @throws NullPointerException {@inheritDoc}
242     */
243     public void put(E e) throws InterruptedException {
244     if (e == null) throw new NullPointerException();
245     final E[] items = this.items;
246     final ReentrantLock lock = this.lock;
247     lock.lockInterruptibly();
248     try {
249     try {
250     while (count == items.length)
251     notFull.await();
252     } catch (InterruptedException ie) {
253     notFull.signal(); // propagate to non-interrupted thread
254     throw ie;
255     }
256     insert(e);
257     } finally {
258     lock.unlock();
259     }
260     }
261    
262     /**
263     * Inserts the specified element at the tail of this queue, waiting
264     * up to the specified wait time for space to become available if
265     * the queue is full.
266     *
267     * @throws InterruptedException {@inheritDoc}
268     * @throws NullPointerException {@inheritDoc}
269 brian 1.7 */
270 jsr166 1.49 public boolean offer(E e, long timeout, TimeUnit unit)
271 dholmes 1.13 throws InterruptedException {
272 dl 1.2
273 jsr166 1.49 if (e == null) throw new NullPointerException();
274 dl 1.36 final ReentrantLock lock = this.lock;
275 dl 1.5 lock.lockInterruptibly();
276     try {
277 dholmes 1.13 long nanos = unit.toNanos(timeout);
278 dl 1.5 for (;;) {
279     if (count != items.length) {
280 jsr166 1.49 insert(e);
281 dl 1.5 return true;
282     }
283     if (nanos <= 0)
284     return false;
285     try {
286     nanos = notFull.awaitNanos(nanos);
287 tim 1.23 } catch (InterruptedException ie) {
288 dl 1.5 notFull.signal(); // propagate to non-interrupted thread
289     throw ie;
290     }
291     }
292 tim 1.23 } finally {
293 dl 1.5 lock.unlock();
294 dl 1.2 }
295 dl 1.5 }
296 dl 1.2
297 dholmes 1.13 public E poll() {
298 dl 1.36 final ReentrantLock lock = this.lock;
299 dholmes 1.13 lock.lock();
300     try {
301     if (count == 0)
302     return null;
303     E x = extract();
304     return x;
305 tim 1.23 } finally {
306 tim 1.15 lock.unlock();
307 dholmes 1.13 }
308     }
309    
310 jsr166 1.50 public E take() throws InterruptedException {
311     final ReentrantLock lock = this.lock;
312     lock.lockInterruptibly();
313     try {
314     try {
315     while (count == 0)
316     notEmpty.await();
317     } catch (InterruptedException ie) {
318     notEmpty.signal(); // propagate to non-interrupted thread
319     throw ie;
320     }
321     E x = extract();
322     return x;
323     } finally {
324     lock.unlock();
325     }
326     }
327    
328 dl 1.5 public E poll(long timeout, TimeUnit unit) throws InterruptedException {
329 dl 1.36 final ReentrantLock lock = this.lock;
330 dl 1.5 lock.lockInterruptibly();
331     try {
332 dholmes 1.13 long nanos = unit.toNanos(timeout);
333 dl 1.2 for (;;) {
334 dl 1.5 if (count != 0) {
335     E x = extract();
336     return x;
337 dl 1.2 }
338 dl 1.5 if (nanos <= 0)
339     return null;
340     try {
341     nanos = notEmpty.awaitNanos(nanos);
342 tim 1.23 } catch (InterruptedException ie) {
343 dl 1.5 notEmpty.signal(); // propagate to non-interrupted thread
344     throw ie;
345     }
346    
347 dl 1.2 }
348 tim 1.23 } finally {
349 dl 1.5 lock.unlock();
350     }
351     }
352 dl 1.2
353 dholmes 1.13 public E peek() {
354 dl 1.36 final ReentrantLock lock = this.lock;
355 dholmes 1.13 lock.lock();
356     try {
357     return (count == 0) ? null : items[takeIndex];
358 tim 1.23 } finally {
359 dholmes 1.13 lock.unlock();
360     }
361     }
362    
363     // this doc comment is overridden to remove the reference to collections
364     // greater in size than Integer.MAX_VALUE
365 tim 1.15 /**
366 dl 1.25 * Returns the number of elements in this queue.
367     *
368 jsr166 1.50 * @return the number of elements in this queue
369 dholmes 1.13 */
370     public int size() {
371 dl 1.36 final ReentrantLock lock = this.lock;
372 dholmes 1.13 lock.lock();
373     try {
374     return count;
375 tim 1.23 } finally {
376 dholmes 1.13 lock.unlock();
377     }
378     }
379    
380     // this doc comment is a modified copy of the inherited doc comment,
381     // without the reference to unlimited queues.
382 tim 1.15 /**
383 jsr166 1.48 * Returns the number of additional elements that this queue can ideally
384     * (in the absence of memory or resource constraints) accept without
385 dholmes 1.13 * blocking. This is always equal to the initial capacity of this queue
386     * less the current <tt>size</tt> of this queue.
387 jsr166 1.48 *
388     * <p>Note that you <em>cannot</em> always tell if an attempt to insert
389     * an element will succeed by inspecting <tt>remainingCapacity</tt>
390     * because it may be the case that another thread is about to
391 jsr166 1.50 * insert or remove an element.
392 dholmes 1.13 */
393     public int remainingCapacity() {
394 dl 1.36 final ReentrantLock lock = this.lock;
395 dholmes 1.13 lock.lock();
396     try {
397     return items.length - count;
398 tim 1.23 } finally {
399 dholmes 1.13 lock.unlock();
400     }
401     }
402    
403 jsr166 1.50 /**
404     * Removes a single instance of the specified element from this queue,
405     * if it is present. More formally, removes an element <tt>e</tt> such
406     * that <tt>o.equals(e)</tt>, if this queue contains one or more such
407     * elements.
408     * Returns <tt>true</tt> if this queue contained the specified element
409     * (or equivalently, if this queue changed as a result of the call).
410     *
411     * @param o element to be removed from this queue, if present
412     * @return <tt>true</tt> if this queue changed as a result of the call
413     */
414     public boolean remove(Object o) {
415     if (o == null) return false;
416     final E[] items = this.items;
417     final ReentrantLock lock = this.lock;
418     lock.lock();
419     try {
420     int i = takeIndex;
421     int k = 0;
422     for (;;) {
423     if (k++ >= count)
424     return false;
425     if (o.equals(items[i])) {
426     removeAt(i);
427     return true;
428     }
429     i = inc(i);
430     }
431    
432     } finally {
433     lock.unlock();
434     }
435     }
436 dholmes 1.13
437 jsr166 1.50 /**
438     * Returns <tt>true</tt> if this queue contains the specified element.
439     * More formally, returns <tt>true</tt> if and only if this queue contains
440     * at least one element <tt>e</tt> such that <tt>o.equals(e)</tt>.
441     *
442     * @param o object to be checked for containment in this queue
443     * @return <tt>true</tt> if this queue contains the specified element
444     */
445 dholmes 1.21 public boolean contains(Object o) {
446     if (o == null) return false;
447 dl 1.36 final E[] items = this.items;
448     final ReentrantLock lock = this.lock;
449 dl 1.5 lock.lock();
450     try {
451     int i = takeIndex;
452     int k = 0;
453     while (k++ < count) {
454 dholmes 1.21 if (o.equals(items[i]))
455 dl 1.2 return true;
456 dl 1.5 i = inc(i);
457     }
458 dl 1.2 return false;
459 tim 1.23 } finally {
460 dl 1.5 lock.unlock();
461     }
462     }
463 brian 1.7
464 jsr166 1.50 /**
465     * Returns an array containing all of the elements in this queue, in
466     * proper sequence.
467     *
468     * <p>The returned array will be "safe" in that no references to it are
469     * maintained by this queue. (In other words, this method must allocate
470     * a new array). The caller is thus free to modify the returned array.
471 jsr166 1.51 *
472 jsr166 1.50 * <p>This method acts as bridge between array-based and collection-based
473     * APIs.
474     *
475     * @return an array containing all of the elements in this queue
476     */
477 dl 1.5 public Object[] toArray() {
478 dl 1.36 final E[] items = this.items;
479     final ReentrantLock lock = this.lock;
480 dl 1.5 lock.lock();
481     try {
482 dl 1.34 Object[] a = new Object[count];
483 dl 1.5 int k = 0;
484     int i = takeIndex;
485     while (k < count) {
486 dl 1.2 a[k++] = items[i];
487 dl 1.5 i = inc(i);
488     }
489 dl 1.2 return a;
490 tim 1.23 } finally {
491 dl 1.5 lock.unlock();
492     }
493     }
494 brian 1.7
495 jsr166 1.50 /**
496     * Returns an array containing all of the elements in this queue, in
497     * proper sequence; the runtime type of the returned array is that of
498     * the specified array. If the queue fits in the specified array, it
499     * is returned therein. Otherwise, a new array is allocated with the
500     * runtime type of the specified array and the size of this queue.
501     *
502     * <p>If this queue fits in the specified array with room to spare
503     * (i.e., the array has more elements than this queue), the element in
504     * the array immediately following the end of the queue is set to
505     * <tt>null</tt>.
506     *
507     * <p>Like the {@link #toArray()} method, this method acts as bridge between
508     * array-based and collection-based APIs. Further, this method allows
509     * precise control over the runtime type of the output array, and may,
510     * under certain circumstances, be used to save allocation costs.
511     *
512     * <p>Suppose <tt>x</tt> is a queue known to contain only strings.
513     * The following code can be used to dump the queue into a newly
514     * allocated array of <tt>String</tt>:
515     *
516     * <pre>
517     * String[] y = x.toArray(new String[0]);</pre>
518     *
519     * Note that <tt>toArray(new Object[0])</tt> is identical in function to
520     * <tt>toArray()</tt>.
521     *
522     * @param a the array into which the elements of the queue are to
523     * be stored, if it is big enough; otherwise, a new array of the
524     * same runtime type is allocated for this purpose
525     * @return an array containing all of the elements in this queue
526     * @throws ArrayStoreException if the runtime type of the specified array
527     * is not a supertype of the runtime type of every element in
528     * this queue
529     * @throws NullPointerException if the specified array is null
530     */
531 dl 1.5 public <T> T[] toArray(T[] a) {
532 dl 1.36 final E[] items = this.items;
533     final ReentrantLock lock = this.lock;
534 dl 1.5 lock.lock();
535     try {
536     if (a.length < count)
537 dholmes 1.16 a = (T[])java.lang.reflect.Array.newInstance(
538 tim 1.17 a.getClass().getComponentType(),
539 dholmes 1.16 count
540     );
541 tim 1.12
542 dl 1.5 int k = 0;
543     int i = takeIndex;
544     while (k < count) {
545 dl 1.2 a[k++] = (T)items[i];
546 dl 1.5 i = inc(i);
547     }
548     if (a.length > count)
549     a[count] = null;
550 dl 1.2 return a;
551 tim 1.23 } finally {
552 dl 1.5 lock.unlock();
553     }
554     }
555 dl 1.6
556     public String toString() {
557 dl 1.36 final ReentrantLock lock = this.lock;
558 dl 1.6 lock.lock();
559     try {
560     return super.toString();
561 tim 1.23 } finally {
562 dl 1.6 lock.unlock();
563     }
564     }
565 tim 1.12
566 dl 1.44 /**
567     * Atomically removes all of the elements from this queue.
568     * The queue will be empty after this call returns.
569     */
570 dl 1.30 public void clear() {
571 dl 1.36 final E[] items = this.items;
572     final ReentrantLock lock = this.lock;
573 dl 1.30 lock.lock();
574     try {
575     int i = takeIndex;
576     int k = count;
577     while (k-- > 0) {
578     items[i] = null;
579     i = inc(i);
580     }
581     count = 0;
582     putIndex = 0;
583     takeIndex = 0;
584     notFull.signalAll();
585     } finally {
586     lock.unlock();
587     }
588     }
589    
590 jsr166 1.50 /**
591     * @throws UnsupportedOperationException {@inheritDoc}
592     * @throws ClassCastException {@inheritDoc}
593     * @throws NullPointerException {@inheritDoc}
594     * @throws IllegalArgumentException {@inheritDoc}
595     */
596 dl 1.30 public int drainTo(Collection<? super E> c) {
597     if (c == null)
598     throw new NullPointerException();
599     if (c == this)
600     throw new IllegalArgumentException();
601 dl 1.36 final E[] items = this.items;
602     final ReentrantLock lock = this.lock;
603 dl 1.30 lock.lock();
604     try {
605     int i = takeIndex;
606     int n = 0;
607     int max = count;
608     while (n < max) {
609     c.add(items[i]);
610     items[i] = null;
611     i = inc(i);
612     ++n;
613     }
614     if (n > 0) {
615     count = 0;
616     putIndex = 0;
617     takeIndex = 0;
618     notFull.signalAll();
619     }
620     return n;
621     } finally {
622     lock.unlock();
623     }
624     }
625    
626 jsr166 1.50 /**
627     * @throws UnsupportedOperationException {@inheritDoc}
628     * @throws ClassCastException {@inheritDoc}
629     * @throws NullPointerException {@inheritDoc}
630     * @throws IllegalArgumentException {@inheritDoc}
631     */
632 dl 1.30 public int drainTo(Collection<? super E> c, int maxElements) {
633     if (c == null)
634     throw new NullPointerException();
635     if (c == this)
636     throw new IllegalArgumentException();
637     if (maxElements <= 0)
638     return 0;
639 dl 1.36 final E[] items = this.items;
640     final ReentrantLock lock = this.lock;
641 dl 1.30 lock.lock();
642     try {
643     int i = takeIndex;
644     int n = 0;
645     int sz = count;
646     int max = (maxElements < count)? maxElements : count;
647     while (n < max) {
648     c.add(items[i]);
649     items[i] = null;
650     i = inc(i);
651     ++n;
652     }
653     if (n > 0) {
654     count -= n;
655     takeIndex = i;
656     notFull.signalAll();
657     }
658     return n;
659     } finally {
660     lock.unlock();
661     }
662     }
663    
664    
665 brian 1.7 /**
666     * Returns an iterator over the elements in this queue in proper sequence.
667 dl 1.22 * The returned <tt>Iterator</tt> is a "weakly consistent" iterator that
668 jsr166 1.47 * will never throw {@link ConcurrentModificationException},
669 dl 1.22 * and guarantees to traverse elements as they existed upon
670     * construction of the iterator, and may (but is not guaranteed to)
671     * reflect any modifications subsequent to construction.
672 brian 1.7 *
673 jsr166 1.50 * @return an iterator over the elements in this queue in proper sequence
674 brian 1.7 */
675 dl 1.5 public Iterator<E> iterator() {
676 dl 1.36 final ReentrantLock lock = this.lock;
677 dl 1.5 lock.lock();
678     try {
679 dl 1.2 return new Itr();
680 tim 1.23 } finally {
681 dl 1.5 lock.unlock();
682     }
683     }
684 dl 1.8
685     /**
686     * Iterator for ArrayBlockingQueue
687     */
688 dl 1.5 private class Itr implements Iterator<E> {
689     /**
690     * Index of element to be returned by next,
691     * or a negative number if no such.
692     */
693 dl 1.8 private int nextIndex;
694 dl 1.2
695 tim 1.12 /**
696 dl 1.5 * nextItem holds on to item fields because once we claim
697     * that an element exists in hasNext(), we must return it in
698     * the following next() call even if it was in the process of
699     * being removed when hasNext() was called.
700 jsr166 1.47 */
701 dl 1.8 private E nextItem;
702 dl 1.5
703     /**
704     * Index of element returned by most recent call to next.
705     * Reset to -1 if this element is deleted by a call to remove.
706     */
707 dl 1.8 private int lastRet;
708 tim 1.12
709 dl 1.5 Itr() {
710     lastRet = -1;
711 tim 1.12 if (count == 0)
712 dl 1.5 nextIndex = -1;
713     else {
714     nextIndex = takeIndex;
715     nextItem = items[takeIndex];
716     }
717     }
718 tim 1.12
719 dl 1.5 public boolean hasNext() {
720     /*
721     * No sync. We can return true by mistake here
722     * only if this iterator passed across threads,
723     * which we don't support anyway.
724 dl 1.2 */
725 dl 1.5 return nextIndex >= 0;
726     }
727    
728     /**
729 jsr166 1.47 * Checks whether nextIndex is valid; if so setting nextItem.
730 dl 1.5 * Stops iterator when either hits putIndex or sees null item.
731     */
732     private void checkNext() {
733     if (nextIndex == putIndex) {
734     nextIndex = -1;
735     nextItem = null;
736 tim 1.23 } else {
737 dl 1.5 nextItem = items[nextIndex];
738     if (nextItem == null)
739     nextIndex = -1;
740 dl 1.2 }
741 dl 1.5 }
742 tim 1.12
743 dl 1.5 public E next() {
744 dl 1.36 final ReentrantLock lock = ArrayBlockingQueue.this.lock;
745 dl 1.5 lock.lock();
746     try {
747     if (nextIndex < 0)
748 dl 1.2 throw new NoSuchElementException();
749 dl 1.5 lastRet = nextIndex;
750     E x = nextItem;
751     nextIndex = inc(nextIndex);
752     checkNext();
753     return x;
754 tim 1.23 } finally {
755 tim 1.12 lock.unlock();
756 dl 1.2 }
757 dl 1.5 }
758 tim 1.12
759 dl 1.5 public void remove() {
760 dl 1.36 final ReentrantLock lock = ArrayBlockingQueue.this.lock;
761 dl 1.5 lock.lock();
762     try {
763 dl 1.2 int i = lastRet;
764     if (i == -1)
765     throw new IllegalStateException();
766     lastRet = -1;
767 tim 1.12
768 dl 1.9 int ti = takeIndex;
769 dl 1.2 removeAt(i);
770 dl 1.9 // back up cursor (reset to front if was first element)
771 tim 1.12 nextIndex = (i == ti) ? takeIndex : i;
772 dl 1.5 checkNext();
773 tim 1.23 } finally {
774 dl 1.5 lock.unlock();
775     }
776     }
777 tim 1.1 }
778     }