ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/main/java/util/concurrent/ConcurrentLinkedQueue.java
Revision: 1.25
Committed: Tue Jan 27 11:36:31 2004 UTC (20 years, 4 months ago) by dl
Branch: MAIN
Changes since 1.24: +5 -1 lines
Log Message:
Add Collection framework membership doc

File Contents

# User Rev Content
1 dl 1.1 /*
2     * Written by Doug Lea with assistance from members of JCP JSR-166
3 dl 1.24 * Expert Group and released to the public domain, as explained at
4     * http://creativecommons.org/licenses/publicdomain
5 dl 1.1 */
6    
7     package java.util.concurrent;
8     import java.util.*;
9     import java.util.concurrent.atomic.*;
10    
11    
12     /**
13 dholmes 1.7 * An unbounded thread-safe {@linkplain Queue queue} based on linked nodes.
14 dholmes 1.6 * This queue orders elements FIFO (first-in-first-out).
15     * The <em>head</em> of the queue is that element that has been on the
16     * queue the longest time.
17     * The <em>tail</em> of the queue is that element that has been on the
18 dl 1.17 * queue the shortest time. New elements
19     * are inserted at the tail of the queue, and the queue retrieval
20     * operations obtain elements at the head of the queue.
21 dl 1.19 * A <tt>ConcurrentLinkedQueue</tt> is an appropriate choice when
22     * many threads will share access to a common collection.
23 dholmes 1.6 * This queue does not permit <tt>null</tt> elements.
24 dl 1.1 *
25 dholmes 1.6 * <p>This implementation employs an efficient &quot;wait-free&quot;
26     * algorithm based on one described in <a
27 dl 1.1 * href="http://www.cs.rochester.edu/u/michael/PODC96.html"> Simple,
28     * Fast, and Practical Non-Blocking and Blocking Concurrent Queue
29 dl 1.15 * Algorithms</a> by Maged M. Michael and Michael L. Scott.
30 dl 1.1 *
31 dholmes 1.7 * <p>Beware that, unlike in most collections, the <tt>size</tt> method
32 dl 1.1 * is <em>NOT</em> a constant-time operation. Because of the
33     * asynchronous nature of these queues, determining the current number
34 dl 1.15 * of elements requires a traversal of the elements.
35 dl 1.18 *
36     * <p>This class implements all of the <em>optional</em> methods
37     * of the {@link Collection} and {@link Iterator} interfaces.
38     *
39 dl 1.25 * <p>This class is a member of the
40     * <a href="{@docRoot}/../guide/collections/index.html">
41     * Java Collections Framework</a>.
42     *
43 dl 1.1 * @since 1.5
44     * @author Doug Lea
45 dl 1.21 * @param <E> the type of elements held in this collection
46 tim 1.2 *
47 dl 1.25 */
48 dl 1.1 public class ConcurrentLinkedQueue<E> extends AbstractQueue<E>
49     implements Queue<E>, java.io.Serializable {
50 dl 1.14 private static final long serialVersionUID = 196745693267521676L;
51 dl 1.1
52     /*
53     * This is a straight adaptation of Michael & Scott algorithm.
54     * For explanation, read the paper. The only (minor) algorithmic
55     * difference is that this version supports lazy deletion of
56     * internal nodes (method remove(Object)) -- remove CAS'es item
57     * fields to null. The normal queue operations unlink but then
58     * pass over nodes with null item fields. Similarly, iteration
59     * methods ignore those with nulls.
60     */
61    
62 dl 1.23 private static class Node<E> {
63 dl 1.22 private volatile E item;
64 dl 1.23 private volatile Node<E> next;
65 dl 1.13
66     private static final
67 dl 1.23 AtomicReferenceFieldUpdater<Node, Node>
68 dl 1.13 nextUpdater =
69     AtomicReferenceFieldUpdater.newUpdater
70 dl 1.23 (Node.class, Node.class, "next");
71 dl 1.13 private static final
72 dl 1.23 AtomicReferenceFieldUpdater<Node, Object>
73 dl 1.13 itemUpdater =
74     AtomicReferenceFieldUpdater.newUpdater
75 dl 1.23 (Node.class, Object.class, "item");
76 dl 1.13
77 dl 1.23 Node(E x) { item = x; }
78 dl 1.13
79 dl 1.23 Node(E x, Node<E> n) { item = x; next = n; }
80 dl 1.13
81 dl 1.22 E getItem() {
82 dl 1.13 return item;
83     }
84    
85 dl 1.22 boolean casItem(E cmp, E val) {
86 dl 1.13 return itemUpdater.compareAndSet(this, cmp, val);
87     }
88    
89 dl 1.22 void setItem(E val) {
90 dl 1.13 itemUpdater.set(this, val);
91     }
92    
93 dl 1.23 Node<E> getNext() {
94 dl 1.13 return next;
95     }
96    
97 dl 1.23 boolean casNext(Node<E> cmp, Node<E> val) {
98 dl 1.13 return nextUpdater.compareAndSet(this, cmp, val);
99     }
100    
101 dl 1.23 void setNext(Node<E> val) {
102 dl 1.13 nextUpdater.set(this, val);
103     }
104    
105     }
106 dl 1.1
107 dl 1.5 private static final
108 dl 1.23 AtomicReferenceFieldUpdater<ConcurrentLinkedQueue, Node>
109 dl 1.5 tailUpdater =
110     AtomicReferenceFieldUpdater.newUpdater
111 dl 1.23 (ConcurrentLinkedQueue.class, Node.class, "tail");
112 dl 1.5 private static final
113 dl 1.23 AtomicReferenceFieldUpdater<ConcurrentLinkedQueue, Node>
114 dl 1.5 headUpdater =
115     AtomicReferenceFieldUpdater.newUpdater
116 dl 1.23 (ConcurrentLinkedQueue.class, Node.class, "head");
117 dl 1.1
118 dl 1.23 private boolean casTail(Node<E> cmp, Node<E> val) {
119 dl 1.1 return tailUpdater.compareAndSet(this, cmp, val);
120     }
121    
122 dl 1.23 private boolean casHead(Node<E> cmp, Node<E> val) {
123 dl 1.1 return headUpdater.compareAndSet(this, cmp, val);
124     }
125    
126    
127 tim 1.2 /**
128 dl 1.1 * Pointer to header node, initialized to a dummy node. The first
129     * actual node is at head.getNext().
130     */
131 dl 1.23 private transient volatile Node<E> head = new Node<E>(null, null);
132 dl 1.1
133     /** Pointer to last node on list **/
134 dl 1.23 private transient volatile Node<E> tail = head;
135 dl 1.1
136    
137     /**
138 dholmes 1.6 * Creates a <tt>ConcurrentLinkedQueue</tt> that is initially empty.
139 dl 1.1 */
140     public ConcurrentLinkedQueue() {}
141    
142     /**
143 dholmes 1.6 * Creates a <tt>ConcurrentLinkedQueue</tt>
144 dholmes 1.7 * initially containing the elements of the given collection,
145 dholmes 1.6 * added in traversal order of the collection's iterator.
146     * @param c the collection of elements to initially contain
147     * @throws NullPointerException if <tt>c</tt> or any element within it
148     * is <tt>null</tt>
149 dl 1.1 */
150 dholmes 1.6 public ConcurrentLinkedQueue(Collection<? extends E> c) {
151     for (Iterator<? extends E> it = c.iterator(); it.hasNext();)
152 dl 1.1 add(it.next());
153     }
154    
155 dholmes 1.7 // Have to override just to update the javadoc
156 dholmes 1.6
157     /**
158 dholmes 1.7 * Adds the specified element to the tail of this queue.
159 dl 1.17 * @param o the element to add.
160 dholmes 1.7 * @return <tt>true</tt> (as per the general contract of
161     * <tt>Collection.add</tt>).
162     *
163 dl 1.17 * @throws NullPointerException if the specified element is <tt>null</tt>
164 dholmes 1.6 */
165     public boolean add(E o) {
166 dl 1.17 return offer(o);
167 dholmes 1.6 }
168    
169     /**
170 dl 1.17 * Inserts the specified element to the tail of this queue.
171     *
172     * @param o the element to add.
173     * @return <tt>true</tt> (as per the general contract of
174     * <tt>Queue.offer</tt>).
175 dholmes 1.6 * @throws NullPointerException if the specified element is <tt>null</tt>
176     */
177     public boolean offer(E o) {
178     if (o == null) throw new NullPointerException();
179 dl 1.23 Node<E> n = new Node<E>(o, null);
180 dl 1.1 for(;;) {
181 dl 1.23 Node<E> t = tail;
182     Node<E> s = t.getNext();
183 dl 1.1 if (t == tail) {
184     if (s == null) {
185     if (t.casNext(s, n)) {
186 tim 1.2 casTail(t, n);
187 dl 1.1 return true;
188     }
189 tim 1.12 } else {
190 dl 1.1 casTail(t, s);
191     }
192     }
193     }
194     }
195    
196     public E poll() {
197     for (;;) {
198 dl 1.23 Node<E> h = head;
199     Node<E> t = tail;
200     Node<E> first = h.getNext();
201 dl 1.1 if (h == head) {
202     if (h == t) {
203     if (first == null)
204     return null;
205     else
206     casTail(t, first);
207 tim 1.12 } else if (casHead(h, first)) {
208 dl 1.22 E item = first.getItem();
209 dl 1.1 if (item != null) {
210     first.setItem(null);
211     return item;
212     }
213 tim 1.2 // else skip over deleted item, continue loop,
214 dl 1.1 }
215     }
216     }
217     }
218    
219     public E peek() { // same as poll except don't remove item
220     for (;;) {
221 dl 1.23 Node<E> h = head;
222     Node<E> t = tail;
223     Node<E> first = h.getNext();
224 dl 1.1 if (h == head) {
225     if (h == t) {
226     if (first == null)
227     return null;
228     else
229     casTail(t, first);
230 tim 1.12 } else {
231 dl 1.22 E item = first.getItem();
232 dl 1.1 if (item != null)
233     return item;
234     else // remove deleted node and continue
235     casHead(h, first);
236     }
237     }
238     }
239     }
240    
241     /**
242 dholmes 1.6 * Returns the first actual (non-header) node on list. This is yet
243 dl 1.1 * another variant of poll/peek; here returning out the first
244     * node, not element (so we cannot collapse with peek() without
245     * introducing race.)
246     */
247 dl 1.23 Node<E> first() {
248 dl 1.1 for (;;) {
249 dl 1.23 Node<E> h = head;
250     Node<E> t = tail;
251     Node<E> first = h.getNext();
252 dl 1.1 if (h == head) {
253     if (h == t) {
254     if (first == null)
255     return null;
256     else
257     casTail(t, first);
258 tim 1.12 } else {
259 dl 1.1 if (first.getItem() != null)
260     return first;
261     else // remove deleted node and continue
262     casHead(h, first);
263     }
264     }
265     }
266     }
267    
268    
269     public boolean isEmpty() {
270     return first() == null;
271     }
272    
273     /**
274 dl 1.17 * Returns the number of elements in this queue. If this queue
275     * contains more than <tt>Integer.MAX_VALUE</tt> elements, returns
276     * <tt>Integer.MAX_VALUE</tt>.
277 tim 1.2 *
278 dl 1.17 * <p>Beware that, unlike in most collections, this method is
279 dl 1.1 * <em>NOT</em> a constant-time operation. Because of the
280     * asynchronous nature of these queues, determining the current
281     * number of elements requires an O(n) traversal.
282 dl 1.17 *
283     * @return the number of elements in this queue.
284 tim 1.2 */
285 dl 1.1 public int size() {
286     int count = 0;
287 dl 1.23 for (Node<E> p = first(); p != null; p = p.getNext()) {
288 dl 1.8 if (p.getItem() != null) {
289     // Collections.size() spec says to max out
290     if (++count == Integer.MAX_VALUE)
291     break;
292     }
293 dl 1.1 }
294     return count;
295     }
296    
297 dholmes 1.6 public boolean contains(Object o) {
298     if (o == null) return false;
299 dl 1.23 for (Node<E> p = first(); p != null; p = p.getNext()) {
300 dl 1.22 E item = p.getItem();
301 tim 1.2 if (item != null &&
302 dholmes 1.6 o.equals(item))
303 dl 1.1 return true;
304     }
305     return false;
306     }
307    
308 dholmes 1.6 public boolean remove(Object o) {
309     if (o == null) return false;
310 dl 1.23 for (Node<E> p = first(); p != null; p = p.getNext()) {
311 dl 1.22 E item = p.getItem();
312 tim 1.2 if (item != null &&
313 dholmes 1.6 o.equals(item) &&
314 dl 1.1 p.casItem(item, null))
315     return true;
316     }
317     return false;
318     }
319 tim 1.2
320 dl 1.1 public Object[] toArray() {
321     // Use ArrayList to deal with resizing.
322 tim 1.3 ArrayList<E> al = new ArrayList<E>();
323 dl 1.23 for (Node<E> p = first(); p != null; p = p.getNext()) {
324 dl 1.22 E item = p.getItem();
325 dl 1.1 if (item != null)
326     al.add(item);
327     }
328     return al.toArray();
329     }
330    
331     public <T> T[] toArray(T[] a) {
332     // try to use sent-in array
333     int k = 0;
334 dl 1.23 Node<E> p;
335 dl 1.1 for (p = first(); p != null && k < a.length; p = p.getNext()) {
336 dl 1.22 E item = p.getItem();
337 dl 1.1 if (item != null)
338     a[k++] = (T)item;
339     }
340     if (p == null) {
341     if (k < a.length)
342     a[k] = null;
343     return a;
344     }
345    
346     // If won't fit, use ArrayList version
347 tim 1.3 ArrayList<E> al = new ArrayList<E>();
348 dl 1.23 for (Node<E> q = first(); q != null; q = q.getNext()) {
349 dl 1.22 E item = q.getItem();
350 dl 1.1 if (item != null)
351     al.add(item);
352     }
353     return (T[])al.toArray(a);
354     }
355    
356 dholmes 1.7 /**
357     * Returns an iterator over the elements in this queue in proper sequence.
358 dl 1.9 * The returned iterator is a "weakly consistent" iterator that
359     * will never throw {@link java.util.ConcurrentModificationException},
360     * and guarantees to traverse elements as they existed upon
361     * construction of the iterator, and may (but is not guaranteed to)
362     * reflect any modifications subsequent to construction.
363 dholmes 1.7 *
364     * @return an iterator over the elements in this queue in proper sequence.
365     */
366 dl 1.1 public Iterator<E> iterator() {
367     return new Itr();
368     }
369    
370     private class Itr implements Iterator<E> {
371     /**
372     * Next node to return item for.
373     */
374 dl 1.23 private Node<E> nextNode;
375 dl 1.1
376 tim 1.2 /**
377 dl 1.1 * nextItem holds on to item fields because once we claim
378     * that an element exists in hasNext(), we must return it in
379     * the following next() call even if it was in the process of
380     * being removed when hasNext() was called.
381     **/
382     private E nextItem;
383    
384     /**
385     * Node of the last returned item, to support remove.
386     */
387 dl 1.23 private Node<E> lastRet;
388 dl 1.1
389 tim 1.2 Itr() {
390 dl 1.1 advance();
391     }
392 tim 1.2
393 dl 1.1 /**
394 tim 1.2 * Move to next valid node.
395 dl 1.1 * Return item to return for next(), or null if no such.
396     */
397 tim 1.2 private E advance() {
398 dl 1.1 lastRet = nextNode;
399 dl 1.22 E x = nextItem;
400 dl 1.1
401 dl 1.23 Node<E> p = (nextNode == null)? first() : nextNode.getNext();
402 dl 1.1 for (;;) {
403     if (p == null) {
404     nextNode = null;
405     nextItem = null;
406     return x;
407     }
408 dl 1.22 E item = p.getItem();
409 dl 1.1 if (item != null) {
410     nextNode = p;
411     nextItem = item;
412     return x;
413 tim 1.12 } else // skip over nulls
414 dl 1.1 p = p.getNext();
415     }
416     }
417 tim 1.2
418 dl 1.1 public boolean hasNext() {
419     return nextNode != null;
420     }
421 tim 1.2
422 dl 1.1 public E next() {
423     if (nextNode == null) throw new NoSuchElementException();
424     return advance();
425     }
426 tim 1.2
427 dl 1.1 public void remove() {
428 dl 1.23 Node<E> l = lastRet;
429 dl 1.1 if (l == null) throw new IllegalStateException();
430     // rely on a future traversal to relink.
431     l.setItem(null);
432     lastRet = null;
433     }
434     }
435    
436     /**
437     * Save the state to a stream (that is, serialize it).
438     *
439     * @serialData All of the elements (each an <tt>E</tt>) in
440     * the proper order, followed by a null
441     * @param s the stream
442     */
443     private void writeObject(java.io.ObjectOutputStream s)
444     throws java.io.IOException {
445    
446     // Write out any hidden stuff
447     s.defaultWriteObject();
448 tim 1.2
449 dl 1.1 // Write out all elements in the proper order.
450 dl 1.23 for (Node<E> p = first(); p != null; p = p.getNext()) {
451 dl 1.1 Object item = p.getItem();
452     if (item != null)
453     s.writeObject(item);
454     }
455    
456     // Use trailing null as sentinel
457     s.writeObject(null);
458     }
459    
460     /**
461     * Reconstitute the Queue instance from a stream (that is,
462     * deserialize it).
463     * @param s the stream
464     */
465     private void readObject(java.io.ObjectInputStream s)
466     throws java.io.IOException, ClassNotFoundException {
467 tim 1.2 // Read in capacity, and any hidden stuff
468     s.defaultReadObject();
469 dl 1.23 head = new Node<E>(null, null);
470 dl 1.16 tail = head;
471 tim 1.2 // Read in all elements and place in queue
472 dl 1.1 for (;;) {
473     E item = (E)s.readObject();
474     if (item == null)
475     break;
476 dl 1.16 else
477     offer(item);
478 dl 1.1 }
479     }
480    
481     }