ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/main/java/util/concurrent/LinkedBlockingQueue.java
Revision: 1.35
Committed: Thu May 27 11:06:11 2004 UTC (20 years ago) by dl
Branch: MAIN
Changes since 1.34: +8 -0 lines
Log Message:
Override javadoc specs when overriding AbstractQueue implementations
Clarify atomicity in BlockingQueue

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.33 * 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.2 import java.util.concurrent.atomic.*;
9 dl 1.7 import java.util.concurrent.locks.*;
10 tim 1.1 import java.util.*;
11    
12     /**
13 dholmes 1.14 * An optionally-bounded {@linkplain BlockingQueue blocking queue} based on
14 dholmes 1.8 * linked nodes.
15     * This queue orders elements FIFO (first-in-first-out).
16 tim 1.12 * The <em>head</em> of the queue is that element that has been on the
17 dholmes 1.8 * queue the longest time.
18     * The <em>tail</em> of the queue is that element that has been on the
19 dl 1.20 * queue the shortest time. New elements
20     * are inserted at the tail of the queue, and the queue retrieval
21     * operations obtain elements at the head of the queue.
22 dholmes 1.8 * Linked queues typically have higher throughput than array-based queues but
23     * less predictable performance in most concurrent applications.
24 tim 1.12 *
25 dl 1.3 * <p> The optional capacity bound constructor argument serves as a
26 dholmes 1.8 * way to prevent excessive queue expansion. The capacity, if unspecified,
27     * is equal to {@link Integer#MAX_VALUE}. Linked nodes are
28 dl 1.3 * dynamically created upon each insertion unless this would bring the
29     * queue above capacity.
30 dholmes 1.8 *
31 dl 1.21 * <p>This class implements all of the <em>optional</em> methods
32     * of the {@link Collection} and {@link Iterator} interfaces.
33     *
34 dl 1.34 * <p>This class is a member of the
35     * <a href="{@docRoot}/../guide/collections/index.html">
36     * Java Collections Framework</a>.
37     *
38 dl 1.6 * @since 1.5
39     * @author Doug Lea
40 dl 1.27 * @param <E> the type of elements held in this collection
41 tim 1.12 *
42 tim 1.1 **/
43 dl 1.2 public class LinkedBlockingQueue<E> extends AbstractQueue<E>
44 tim 1.1 implements BlockingQueue<E>, java.io.Serializable {
45 dl 1.18 private static final long serialVersionUID = -6903933977591709194L;
46 tim 1.1
47 dl 1.2 /*
48     * A variant of the "two lock queue" algorithm. The putLock gates
49     * entry to put (and offer), and has an associated condition for
50     * waiting puts. Similarly for the takeLock. The "count" field
51     * that they both rely on is maintained as an atomic to avoid
52     * needing to get both locks in most cases. Also, to minimize need
53     * for puts to get takeLock and vice-versa, cascading notifies are
54     * used. When a put notices that it has enabled at least one take,
55     * it signals taker. That taker in turn signals others if more
56     * items have been entered since the signal. And symmetrically for
57 tim 1.12 * takes signalling puts. Operations such as remove(Object) and
58 dl 1.2 * iterators acquire both locks.
59     */
60    
61 dl 1.6 /**
62     * Linked list node class
63     */
64 dl 1.2 static class Node<E> {
65 dl 1.6 /** The item, volatile to ensure barrier separating write and read */
66 dl 1.2 volatile E item;
67     Node<E> next;
68     Node(E x) { item = x; }
69     }
70    
71 dl 1.6 /** The capacity bound, or Integer.MAX_VALUE if none */
72 dl 1.2 private final int capacity;
73 dl 1.6
74     /** Current number of elements */
75 dl 1.19 private final AtomicInteger count = new AtomicInteger(0);
76 dl 1.2
77 dl 1.6 /** Head of linked list */
78     private transient Node<E> head;
79    
80 dholmes 1.8 /** Tail of linked list */
81 dl 1.6 private transient Node<E> last;
82 dl 1.2
83 dl 1.6 /** Lock held by take, poll, etc */
84 dl 1.5 private final ReentrantLock takeLock = new ReentrantLock();
85 dl 1.6
86     /** Wait queue for waiting takes */
87 dl 1.32 private final Condition notEmpty = takeLock.newCondition();
88 dl 1.2
89 dl 1.6 /** Lock held by put, offer, etc */
90 dl 1.5 private final ReentrantLock putLock = new ReentrantLock();
91 dl 1.6
92     /** Wait queue for waiting puts */
93 dl 1.32 private final Condition notFull = putLock.newCondition();
94 dl 1.2
95     /**
96     * Signal a waiting take. Called only from put/offer (which do not
97 dl 1.4 * otherwise ordinarily lock takeLock.)
98 dl 1.2 */
99     private void signalNotEmpty() {
100 dl 1.31 final ReentrantLock takeLock = this.takeLock;
101 dl 1.2 takeLock.lock();
102     try {
103     notEmpty.signal();
104 tim 1.17 } finally {
105 dl 1.2 takeLock.unlock();
106     }
107     }
108    
109     /**
110     * Signal a waiting put. Called only from take/poll.
111     */
112     private void signalNotFull() {
113 dl 1.31 final ReentrantLock putLock = this.putLock;
114 dl 1.2 putLock.lock();
115     try {
116     notFull.signal();
117 tim 1.17 } finally {
118 dl 1.2 putLock.unlock();
119     }
120     }
121    
122     /**
123 dholmes 1.8 * Create a node and link it at end of queue
124 dl 1.6 * @param x the item
125 dl 1.2 */
126     private void insert(E x) {
127     last = last.next = new Node<E>(x);
128     }
129    
130     /**
131     * Remove a node from head of queue,
132 dl 1.6 * @return the node
133 dl 1.2 */
134     private E extract() {
135     Node<E> first = head.next;
136     head = first;
137 dl 1.28 E x = first.item;
138 dl 1.2 first.item = null;
139     return x;
140     }
141    
142     /**
143 tim 1.12 * Lock to prevent both puts and takes.
144 dl 1.2 */
145     private void fullyLock() {
146     putLock.lock();
147     takeLock.lock();
148 tim 1.1 }
149 dl 1.2
150     /**
151 tim 1.12 * Unlock to allow both puts and takes.
152 dl 1.2 */
153     private void fullyUnlock() {
154     takeLock.unlock();
155     putLock.unlock();
156     }
157    
158    
159     /**
160 dholmes 1.13 * Creates a <tt>LinkedBlockingQueue</tt> with a capacity of
161 dholmes 1.8 * {@link Integer#MAX_VALUE}.
162 dl 1.2 */
163     public LinkedBlockingQueue() {
164     this(Integer.MAX_VALUE);
165     }
166    
167     /**
168 tim 1.16 * Creates a <tt>LinkedBlockingQueue</tt> with the given (fixed) capacity.
169     *
170 dholmes 1.8 * @param capacity the capacity of this queue.
171     * @throws IllegalArgumentException if <tt>capacity</tt> is not greater
172 tim 1.16 * than zero.
173 dl 1.2 */
174     public LinkedBlockingQueue(int capacity) {
175 dholmes 1.8 if (capacity <= 0) throw new IllegalArgumentException();
176 dl 1.2 this.capacity = capacity;
177 dl 1.6 last = head = new Node<E>(null);
178 dl 1.2 }
179    
180     /**
181 dholmes 1.13 * Creates a <tt>LinkedBlockingQueue</tt> with a capacity of
182 dholmes 1.14 * {@link Integer#MAX_VALUE}, initially containing the elements of the
183 tim 1.12 * given collection,
184 dholmes 1.8 * added in traversal order of the collection's iterator.
185 dholmes 1.9 * @param c the collection of elements to initially contain
186     * @throws NullPointerException if <tt>c</tt> or any element within it
187     * is <tt>null</tt>
188 dl 1.2 */
189 dholmes 1.10 public LinkedBlockingQueue(Collection<? extends E> c) {
190 dl 1.2 this(Integer.MAX_VALUE);
191 tim 1.12 for (Iterator<? extends E> it = c.iterator(); it.hasNext();)
192     add(it.next());
193 dl 1.2 }
194    
195 dholmes 1.9
196 dholmes 1.8 // this doc comment is overridden to remove the reference to collections
197     // greater in size than Integer.MAX_VALUE
198 tim 1.12 /**
199 dl 1.20 * Returns the number of elements in this queue.
200     *
201     * @return the number of elements in this queue.
202 dholmes 1.8 */
203 dl 1.2 public int size() {
204     return count.get();
205 tim 1.1 }
206 dl 1.2
207 dholmes 1.8 // this doc comment is a modified copy of the inherited doc comment,
208     // without the reference to unlimited queues.
209 tim 1.12 /**
210 dholmes 1.13 * Returns the number of elements that this queue can ideally (in
211 dholmes 1.8 * the absence of memory or resource constraints) accept without
212     * blocking. This is always equal to the initial capacity of this queue
213     * less the current <tt>size</tt> of this queue.
214     * <p>Note that you <em>cannot</em> always tell if
215     * an attempt to <tt>add</tt> an element will succeed by
216     * inspecting <tt>remainingCapacity</tt> because it may be the
217     * case that a waiting consumer is ready to <tt>take</tt> an
218     * element out of an otherwise full queue.
219     */
220 dl 1.2 public int remainingCapacity() {
221     return capacity - count.get();
222     }
223    
224 dholmes 1.22 /**
225     * Adds the specified element to the tail of this queue, waiting if
226     * necessary for space to become available.
227 dl 1.23 * @param o the element to add
228     * @throws InterruptedException if interrupted while waiting.
229 dholmes 1.22 * @throws NullPointerException if the specified element is <tt>null</tt>.
230     */
231 dholmes 1.14 public void put(E o) throws InterruptedException {
232     if (o == null) throw new NullPointerException();
233 dl 1.2 // Note: convention in all put/take/etc is to preset
234     // local var holding count negative to indicate failure unless set.
235 tim 1.12 int c = -1;
236 dl 1.31 final ReentrantLock putLock = this.putLock;
237     final AtomicInteger count = this.count;
238 dl 1.2 putLock.lockInterruptibly();
239     try {
240     /*
241     * Note that count is used in wait guard even though it is
242     * not protected by lock. This works because count can
243     * only decrease at this point (all other puts are shut
244     * out by lock), and we (or some other waiting put) are
245     * signalled if it ever changes from
246     * capacity. Similarly for all other uses of count in
247     * other wait guards.
248     */
249     try {
250 tim 1.12 while (count.get() == capacity)
251 dl 1.2 notFull.await();
252 tim 1.17 } catch (InterruptedException ie) {
253 dl 1.2 notFull.signal(); // propagate to a non-interrupted thread
254     throw ie;
255     }
256 dholmes 1.14 insert(o);
257 dl 1.2 c = count.getAndIncrement();
258 dl 1.6 if (c + 1 < capacity)
259 dl 1.2 notFull.signal();
260 tim 1.17 } finally {
261 dl 1.2 putLock.unlock();
262     }
263 tim 1.12 if (c == 0)
264 dl 1.2 signalNotEmpty();
265 tim 1.1 }
266 dl 1.2
267 dholmes 1.22 /**
268     * Inserts the specified element at the tail of this queue, waiting if
269     * necessary up to the specified wait time for space to become available.
270 dl 1.23 * @param o the element to add
271     * @param timeout how long to wait before giving up, in units of
272     * <tt>unit</tt>
273     * @param unit a <tt>TimeUnit</tt> determining how to interpret the
274     * <tt>timeout</tt> parameter
275     * @return <tt>true</tt> if successful, or <tt>false</tt> if
276     * the specified waiting time elapses before space is available.
277     * @throws InterruptedException if interrupted while waiting.
278 dholmes 1.22 * @throws NullPointerException if the specified element is <tt>null</tt>.
279     */
280 dholmes 1.14 public boolean offer(E o, long timeout, TimeUnit unit)
281 dholmes 1.8 throws InterruptedException {
282 tim 1.12
283 dholmes 1.14 if (o == null) throw new NullPointerException();
284 dl 1.2 long nanos = unit.toNanos(timeout);
285     int c = -1;
286 dl 1.31 final ReentrantLock putLock = this.putLock;
287     final AtomicInteger count = this.count;
288 dholmes 1.8 putLock.lockInterruptibly();
289 dl 1.2 try {
290     for (;;) {
291     if (count.get() < capacity) {
292 dholmes 1.14 insert(o);
293 dl 1.2 c = count.getAndIncrement();
294 dl 1.6 if (c + 1 < capacity)
295 dl 1.2 notFull.signal();
296     break;
297     }
298     if (nanos <= 0)
299     return false;
300     try {
301     nanos = notFull.awaitNanos(nanos);
302 tim 1.17 } catch (InterruptedException ie) {
303 dl 1.2 notFull.signal(); // propagate to a non-interrupted thread
304     throw ie;
305     }
306     }
307 tim 1.17 } finally {
308 dl 1.2 putLock.unlock();
309     }
310 tim 1.12 if (c == 0)
311 dl 1.2 signalNotEmpty();
312     return true;
313 tim 1.1 }
314 dl 1.2
315 dl 1.23 /**
316     * Inserts the specified element at the tail of this queue if possible,
317     * returning immediately if this queue is full.
318     *
319     * @param o the element to add.
320     * @return <tt>true</tt> if it was possible to add the element to
321     * this queue, else <tt>false</tt>
322     * @throws NullPointerException if the specified element is <tt>null</tt>
323     */
324 dholmes 1.14 public boolean offer(E o) {
325     if (o == null) throw new NullPointerException();
326 dl 1.31 final AtomicInteger count = this.count;
327 dl 1.2 if (count.get() == capacity)
328     return false;
329 tim 1.12 int c = -1;
330 dl 1.31 final ReentrantLock putLock = this.putLock;
331 dholmes 1.8 putLock.lock();
332 dl 1.2 try {
333     if (count.get() < capacity) {
334 dholmes 1.14 insert(o);
335 dl 1.2 c = count.getAndIncrement();
336 dl 1.6 if (c + 1 < capacity)
337 dl 1.2 notFull.signal();
338     }
339 tim 1.17 } finally {
340 dl 1.2 putLock.unlock();
341     }
342 tim 1.12 if (c == 0)
343 dl 1.2 signalNotEmpty();
344     return c >= 0;
345 tim 1.1 }
346 dl 1.2
347    
348     public E take() throws InterruptedException {
349     E x;
350     int c = -1;
351 dl 1.31 final AtomicInteger count = this.count;
352     final ReentrantLock takeLock = this.takeLock;
353 dl 1.2 takeLock.lockInterruptibly();
354     try {
355     try {
356 tim 1.12 while (count.get() == 0)
357 dl 1.2 notEmpty.await();
358 tim 1.17 } catch (InterruptedException ie) {
359 dl 1.2 notEmpty.signal(); // propagate to a non-interrupted thread
360     throw ie;
361     }
362    
363     x = extract();
364     c = count.getAndDecrement();
365     if (c > 1)
366     notEmpty.signal();
367 tim 1.17 } finally {
368 dl 1.2 takeLock.unlock();
369     }
370 tim 1.12 if (c == capacity)
371 dl 1.2 signalNotFull();
372     return x;
373     }
374    
375     public E poll(long timeout, TimeUnit unit) throws InterruptedException {
376     E x = null;
377     int c = -1;
378 dholmes 1.8 long nanos = unit.toNanos(timeout);
379 dl 1.31 final AtomicInteger count = this.count;
380     final ReentrantLock takeLock = this.takeLock;
381 dl 1.2 takeLock.lockInterruptibly();
382     try {
383     for (;;) {
384     if (count.get() > 0) {
385     x = extract();
386     c = count.getAndDecrement();
387     if (c > 1)
388     notEmpty.signal();
389     break;
390     }
391     if (nanos <= 0)
392     return null;
393     try {
394     nanos = notEmpty.awaitNanos(nanos);
395 tim 1.17 } catch (InterruptedException ie) {
396 dl 1.2 notEmpty.signal(); // propagate to a non-interrupted thread
397     throw ie;
398     }
399     }
400 tim 1.17 } finally {
401 dl 1.2 takeLock.unlock();
402     }
403 tim 1.12 if (c == capacity)
404 dl 1.2 signalNotFull();
405     return x;
406     }
407    
408     public E poll() {
409 dl 1.31 final AtomicInteger count = this.count;
410 dl 1.2 if (count.get() == 0)
411     return null;
412     E x = null;
413 tim 1.12 int c = -1;
414 dl 1.31 final ReentrantLock takeLock = this.takeLock;
415 dl 1.30 takeLock.lock();
416 dl 1.2 try {
417     if (count.get() > 0) {
418     x = extract();
419     c = count.getAndDecrement();
420     if (c > 1)
421     notEmpty.signal();
422     }
423 tim 1.17 } finally {
424 dl 1.2 takeLock.unlock();
425     }
426 tim 1.12 if (c == capacity)
427 dl 1.2 signalNotFull();
428     return x;
429 tim 1.1 }
430 dl 1.2
431    
432     public E peek() {
433     if (count.get() == 0)
434     return null;
435 dl 1.31 final ReentrantLock takeLock = this.takeLock;
436 dholmes 1.8 takeLock.lock();
437 dl 1.2 try {
438     Node<E> first = head.next;
439     if (first == null)
440     return null;
441     else
442     return first.item;
443 tim 1.17 } finally {
444 dl 1.2 takeLock.unlock();
445     }
446 tim 1.1 }
447    
448 dl 1.35 /**
449     * Removes a single instance of the specified element from this
450     * collection, if it is present.
451     */
452 dholmes 1.9 public boolean remove(Object o) {
453     if (o == null) return false;
454 dl 1.2 boolean removed = false;
455     fullyLock();
456     try {
457     Node<E> trail = head;
458     Node<E> p = head.next;
459     while (p != null) {
460 dholmes 1.9 if (o.equals(p.item)) {
461 dl 1.2 removed = true;
462     break;
463     }
464     trail = p;
465     p = p.next;
466     }
467     if (removed) {
468     p.item = null;
469     trail.next = p.next;
470     if (count.getAndDecrement() == capacity)
471     notFull.signalAll();
472     }
473 tim 1.17 } finally {
474 dl 1.2 fullyUnlock();
475     }
476     return removed;
477 tim 1.1 }
478 dl 1.2
479     public Object[] toArray() {
480     fullyLock();
481     try {
482     int size = count.get();
483 tim 1.12 Object[] a = new Object[size];
484 dl 1.2 int k = 0;
485 tim 1.12 for (Node<E> p = head.next; p != null; p = p.next)
486 dl 1.2 a[k++] = p.item;
487     return a;
488 tim 1.17 } finally {
489 dl 1.2 fullyUnlock();
490     }
491 tim 1.1 }
492 dl 1.2
493     public <T> T[] toArray(T[] a) {
494     fullyLock();
495     try {
496     int size = count.get();
497     if (a.length < size)
498 dl 1.4 a = (T[])java.lang.reflect.Array.newInstance
499     (a.getClass().getComponentType(), size);
500 tim 1.12
501 dl 1.2 int k = 0;
502 tim 1.12 for (Node p = head.next; p != null; p = p.next)
503 dl 1.2 a[k++] = (T)p.item;
504     return a;
505 tim 1.17 } finally {
506 dl 1.2 fullyUnlock();
507     }
508 tim 1.1 }
509 dl 1.2
510     public String toString() {
511     fullyLock();
512     try {
513     return super.toString();
514 tim 1.17 } finally {
515 dl 1.2 fullyUnlock();
516     }
517 tim 1.1 }
518 dl 1.2
519 dl 1.35 /**
520     * Atomically removes all of the elements from this queue.
521     * The queue will be empty after this call returns.
522     */
523 dl 1.24 public void clear() {
524     fullyLock();
525     try {
526     head.next = null;
527     if (count.getAndSet(0) == capacity)
528     notFull.signalAll();
529     } finally {
530     fullyUnlock();
531     }
532     }
533    
534     public int drainTo(Collection<? super E> c) {
535     if (c == null)
536     throw new NullPointerException();
537     if (c == this)
538     throw new IllegalArgumentException();
539     Node first;
540     fullyLock();
541     try {
542     first = head.next;
543     head.next = null;
544     if (count.getAndSet(0) == capacity)
545     notFull.signalAll();
546     } finally {
547     fullyUnlock();
548     }
549     // Transfer the elements outside of locks
550     int n = 0;
551 dl 1.29 for (Node<E> p = first; p != null; p = p.next) {
552     c.add(p.item);
553 dl 1.24 p.item = null;
554     ++n;
555     }
556     return n;
557     }
558    
559     public int drainTo(Collection<? super E> c, int maxElements) {
560     if (c == null)
561     throw new NullPointerException();
562     if (c == this)
563     throw new IllegalArgumentException();
564     if (maxElements <= 0)
565     return 0;
566     fullyLock();
567     try {
568     int n = 0;
569 dl 1.29 Node<E> p = head.next;
570 dl 1.24 while (p != null && n < maxElements) {
571 dl 1.29 c.add(p.item);
572 dl 1.24 p.item = null;
573     p = p.next;
574     ++n;
575     }
576     if (n != 0) {
577     head.next = p;
578     if (count.getAndAdd(-n) == capacity)
579     notFull.signalAll();
580     }
581     return n;
582     } finally {
583     fullyUnlock();
584     }
585     }
586    
587 dholmes 1.14 /**
588     * Returns an iterator over the elements in this queue in proper sequence.
589 dl 1.15 * The returned <tt>Iterator</tt> is a "weakly consistent" iterator that
590     * will never throw {@link java.util.ConcurrentModificationException},
591     * and guarantees to traverse elements as they existed upon
592     * construction of the iterator, and may (but is not guaranteed to)
593     * reflect any modifications subsequent to construction.
594 dholmes 1.14 *
595     * @return an iterator over the elements in this queue in proper sequence.
596     */
597 dl 1.2 public Iterator<E> iterator() {
598     return new Itr();
599 tim 1.1 }
600 dl 1.2
601     private class Itr implements Iterator<E> {
602 tim 1.12 /*
603 dl 1.4 * Basic weak-consistent iterator. At all times hold the next
604     * item to hand out so that if hasNext() reports true, we will
605     * still have it to return even if lost race with a take etc.
606     */
607 dl 1.31 private Node<E> current;
608     private Node<E> lastRet;
609     private E currentElement;
610 tim 1.12
611 dl 1.2 Itr() {
612 dl 1.31 final ReentrantLock putLock = LinkedBlockingQueue.this.putLock;
613     final ReentrantLock takeLock = LinkedBlockingQueue.this.takeLock;
614     putLock.lock();
615     takeLock.lock();
616 dl 1.2 try {
617     current = head.next;
618 dl 1.4 if (current != null)
619     currentElement = current.item;
620 tim 1.17 } finally {
621 dl 1.31 takeLock.unlock();
622     putLock.unlock();
623 dl 1.2 }
624     }
625 tim 1.12
626     public boolean hasNext() {
627 dl 1.2 return current != null;
628     }
629    
630 tim 1.12 public E next() {
631 dl 1.31 final ReentrantLock putLock = LinkedBlockingQueue.this.putLock;
632     final ReentrantLock takeLock = LinkedBlockingQueue.this.takeLock;
633     putLock.lock();
634     takeLock.lock();
635 dl 1.2 try {
636     if (current == null)
637     throw new NoSuchElementException();
638 dl 1.4 E x = currentElement;
639 dl 1.2 lastRet = current;
640     current = current.next;
641 dl 1.4 if (current != null)
642     currentElement = current.item;
643 dl 1.2 return x;
644 tim 1.17 } finally {
645 dl 1.31 takeLock.unlock();
646     putLock.unlock();
647 dl 1.2 }
648     }
649    
650 tim 1.12 public void remove() {
651 dl 1.2 if (lastRet == null)
652 tim 1.12 throw new IllegalStateException();
653 dl 1.31 final ReentrantLock putLock = LinkedBlockingQueue.this.putLock;
654     final ReentrantLock takeLock = LinkedBlockingQueue.this.takeLock;
655     putLock.lock();
656     takeLock.lock();
657 dl 1.2 try {
658     Node<E> node = lastRet;
659     lastRet = null;
660     Node<E> trail = head;
661     Node<E> p = head.next;
662     while (p != null && p != node) {
663     trail = p;
664     p = p.next;
665     }
666     if (p == node) {
667     p.item = null;
668     trail.next = p.next;
669     int c = count.getAndDecrement();
670     if (c == capacity)
671     notFull.signalAll();
672     }
673 tim 1.17 } finally {
674 dl 1.31 takeLock.unlock();
675     putLock.unlock();
676 dl 1.2 }
677     }
678 tim 1.1 }
679 dl 1.2
680     /**
681     * Save the state to a stream (that is, serialize it).
682     *
683     * @serialData The capacity is emitted (int), followed by all of
684     * its elements (each an <tt>Object</tt>) in the proper order,
685     * followed by a null
686 dl 1.6 * @param s the stream
687 dl 1.2 */
688     private void writeObject(java.io.ObjectOutputStream s)
689     throws java.io.IOException {
690    
691 tim 1.12 fullyLock();
692 dl 1.2 try {
693     // Write out any hidden stuff, plus capacity
694     s.defaultWriteObject();
695    
696     // Write out all elements in the proper order.
697 tim 1.12 for (Node<E> p = head.next; p != null; p = p.next)
698 dl 1.2 s.writeObject(p.item);
699    
700     // Use trailing null as sentinel
701     s.writeObject(null);
702 tim 1.17 } finally {
703 dl 1.2 fullyUnlock();
704     }
705 tim 1.1 }
706    
707 dl 1.2 /**
708 dholmes 1.8 * Reconstitute this queue instance from a stream (that is,
709 dl 1.2 * deserialize it).
710 dl 1.6 * @param s the stream
711 dl 1.2 */
712     private void readObject(java.io.ObjectInputStream s)
713     throws java.io.IOException, ClassNotFoundException {
714 tim 1.12 // Read in capacity, and any hidden stuff
715     s.defaultReadObject();
716 dl 1.2
717 dl 1.19 count.set(0);
718     last = head = new Node<E>(null);
719    
720 dl 1.6 // Read in all elements and place in queue
721 dl 1.2 for (;;) {
722     E item = (E)s.readObject();
723     if (item == null)
724     break;
725     add(item);
726     }
727 tim 1.1 }
728     }