ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/main/java/util/concurrent/ConcurrentLinkedQueue.java
Revision: 1.12
Committed: Fri Aug 8 20:05:07 2003 UTC (20 years, 10 months ago) by tim
Branch: MAIN
Changes since 1.11: +5 -10 lines
Log Message:
Scrunched catch, finally, else clauses.

File Contents

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