blob: dc56a0346654b57a5aada3aadd57abd1ccf56923 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3 *
4 * This code is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 2 only, as
6 * published by the Free Software Foundation. Sun designates this
7 * particular file as subject to the "Classpath" exception as provided
8 * by Sun in the LICENSE file that accompanied this code.
9 *
10 * This code is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * version 2 for more details (a copy is included in the LICENSE file that
14 * accompanied this code).
15 *
16 * You should have received a copy of the GNU General Public License version
17 * 2 along with this work; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19 *
20 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
21 * CA 95054 USA or visit www.sun.com if you need additional information or
22 * have any questions.
23 */
24
25/*
26 * This file is available under and governed by the GNU General Public
27 * License version 2 only, as published by the Free Software Foundation.
28 * However, the following notice accompanied the original version of this
29 * file:
30 *
31 * Written by Doug Lea with assistance from members of JCP JSR-166
32 * Expert Group and released to the public domain, as explained at
33 * http://creativecommons.org/licenses/publicdomain
34 */
35
36package java.util.concurrent;
37import java.util.concurrent.atomic.*;
38import java.util.concurrent.locks.*;
39import java.util.*;
40
41/**
42 * An optionally-bounded {@linkplain BlockingQueue blocking queue} based on
43 * linked nodes.
44 * This queue orders elements FIFO (first-in-first-out).
45 * The <em>head</em> of the queue is that element that has been on the
46 * queue the longest time.
47 * The <em>tail</em> of the queue is that element that has been on the
48 * queue the shortest time. New elements
49 * are inserted at the tail of the queue, and the queue retrieval
50 * operations obtain elements at the head of the queue.
51 * Linked queues typically have higher throughput than array-based queues but
52 * less predictable performance in most concurrent applications.
53 *
54 * <p> The optional capacity bound constructor argument serves as a
55 * way to prevent excessive queue expansion. The capacity, if unspecified,
56 * is equal to {@link Integer#MAX_VALUE}. Linked nodes are
57 * dynamically created upon each insertion unless this would bring the
58 * queue above capacity.
59 *
60 * <p>This class and its iterator implement all of the
61 * <em>optional</em> methods of the {@link Collection} and {@link
62 * Iterator} interfaces.
63 *
64 * <p>This class is a member of the
65 * <a href="{@docRoot}/../technotes/guides/collections/index.html">
66 * Java Collections Framework</a>.
67 *
68 * @since 1.5
69 * @author Doug Lea
70 * @param <E> the type of elements held in this collection
71 *
72 */
73public class LinkedBlockingQueue<E> extends AbstractQueue<E>
74 implements BlockingQueue<E>, java.io.Serializable {
75 private static final long serialVersionUID = -6903933977591709194L;
76
77 /*
78 * A variant of the "two lock queue" algorithm. The putLock gates
79 * entry to put (and offer), and has an associated condition for
80 * waiting puts. Similarly for the takeLock. The "count" field
81 * that they both rely on is maintained as an atomic to avoid
82 * needing to get both locks in most cases. Also, to minimize need
83 * for puts to get takeLock and vice-versa, cascading notifies are
84 * used. When a put notices that it has enabled at least one take,
85 * it signals taker. That taker in turn signals others if more
86 * items have been entered since the signal. And symmetrically for
87 * takes signalling puts. Operations such as remove(Object) and
88 * iterators acquire both locks.
89 */
90
91 /**
92 * Linked list node class
93 */
94 static class Node<E> {
95 /** The item, volatile to ensure barrier separating write and read */
96 volatile E item;
97 Node<E> next;
98 Node(E x) { item = x; }
99 }
100
101 /** The capacity bound, or Integer.MAX_VALUE if none */
102 private final int capacity;
103
104 /** Current number of elements */
105 private final AtomicInteger count = new AtomicInteger(0);
106
107 /** Head of linked list */
108 private transient Node<E> head;
109
110 /** Tail of linked list */
111 private transient Node<E> last;
112
113 /** Lock held by take, poll, etc */
114 private final ReentrantLock takeLock = new ReentrantLock();
115
116 /** Wait queue for waiting takes */
117 private final Condition notEmpty = takeLock.newCondition();
118
119 /** Lock held by put, offer, etc */
120 private final ReentrantLock putLock = new ReentrantLock();
121
122 /** Wait queue for waiting puts */
123 private final Condition notFull = putLock.newCondition();
124
125 /**
126 * Signals a waiting take. Called only from put/offer (which do not
127 * otherwise ordinarily lock takeLock.)
128 */
129 private void signalNotEmpty() {
130 final ReentrantLock takeLock = this.takeLock;
131 takeLock.lock();
132 try {
133 notEmpty.signal();
134 } finally {
135 takeLock.unlock();
136 }
137 }
138
139 /**
140 * Signals a waiting put. Called only from take/poll.
141 */
142 private void signalNotFull() {
143 final ReentrantLock putLock = this.putLock;
144 putLock.lock();
145 try {
146 notFull.signal();
147 } finally {
148 putLock.unlock();
149 }
150 }
151
152 /**
153 * Creates a node and links it at end of queue.
154 * @param x the item
155 */
156 private void insert(E x) {
157 last = last.next = new Node<E>(x);
158 }
159
160 /**
161 * Removes a node from head of queue,
162 * @return the node
163 */
164 private E extract() {
165 Node<E> first = head.next;
166 head = first;
167 E x = first.item;
168 first.item = null;
169 return x;
170 }
171
172 /**
173 * Lock to prevent both puts and takes.
174 */
175 private void fullyLock() {
176 putLock.lock();
177 takeLock.lock();
178 }
179
180 /**
181 * Unlock to allow both puts and takes.
182 */
183 private void fullyUnlock() {
184 takeLock.unlock();
185 putLock.unlock();
186 }
187
188
189 /**
190 * Creates a <tt>LinkedBlockingQueue</tt> with a capacity of
191 * {@link Integer#MAX_VALUE}.
192 */
193 public LinkedBlockingQueue() {
194 this(Integer.MAX_VALUE);
195 }
196
197 /**
198 * Creates a <tt>LinkedBlockingQueue</tt> with the given (fixed) capacity.
199 *
200 * @param capacity the capacity of this queue
201 * @throws IllegalArgumentException if <tt>capacity</tt> is not greater
202 * than zero
203 */
204 public LinkedBlockingQueue(int capacity) {
205 if (capacity <= 0) throw new IllegalArgumentException();
206 this.capacity = capacity;
207 last = head = new Node<E>(null);
208 }
209
210 /**
211 * Creates a <tt>LinkedBlockingQueue</tt> with a capacity of
212 * {@link Integer#MAX_VALUE}, initially containing the elements of the
213 * given collection,
214 * added in traversal order of the collection's iterator.
215 *
216 * @param c the collection of elements to initially contain
217 * @throws NullPointerException if the specified collection or any
218 * of its elements are null
219 */
220 public LinkedBlockingQueue(Collection<? extends E> c) {
221 this(Integer.MAX_VALUE);
222 for (E e : c)
223 add(e);
224 }
225
226
227 // this doc comment is overridden to remove the reference to collections
228 // greater in size than Integer.MAX_VALUE
229 /**
230 * Returns the number of elements in this queue.
231 *
232 * @return the number of elements in this queue
233 */
234 public int size() {
235 return count.get();
236 }
237
238 // this doc comment is a modified copy of the inherited doc comment,
239 // without the reference to unlimited queues.
240 /**
241 * Returns the number of additional elements that this queue can ideally
242 * (in the absence of memory or resource constraints) accept without
243 * blocking. This is always equal to the initial capacity of this queue
244 * less the current <tt>size</tt> of this queue.
245 *
246 * <p>Note that you <em>cannot</em> always tell if an attempt to insert
247 * an element will succeed by inspecting <tt>remainingCapacity</tt>
248 * because it may be the case that another thread is about to
249 * insert or remove an element.
250 */
251 public int remainingCapacity() {
252 return capacity - count.get();
253 }
254
255 /**
256 * Inserts the specified element at the tail of this queue, waiting if
257 * necessary for space to become available.
258 *
259 * @throws InterruptedException {@inheritDoc}
260 * @throws NullPointerException {@inheritDoc}
261 */
262 public void put(E e) throws InterruptedException {
263 if (e == null) throw new NullPointerException();
264 // Note: convention in all put/take/etc is to preset
265 // local var holding count negative to indicate failure unless set.
266 int c = -1;
267 final ReentrantLock putLock = this.putLock;
268 final AtomicInteger count = this.count;
269 putLock.lockInterruptibly();
270 try {
271 /*
272 * Note that count is used in wait guard even though it is
273 * not protected by lock. This works because count can
274 * only decrease at this point (all other puts are shut
275 * out by lock), and we (or some other waiting put) are
276 * signalled if it ever changes from
277 * capacity. Similarly for all other uses of count in
278 * other wait guards.
279 */
280 try {
281 while (count.get() == capacity)
282 notFull.await();
283 } catch (InterruptedException ie) {
284 notFull.signal(); // propagate to a non-interrupted thread
285 throw ie;
286 }
287 insert(e);
288 c = count.getAndIncrement();
289 if (c + 1 < capacity)
290 notFull.signal();
291 } finally {
292 putLock.unlock();
293 }
294 if (c == 0)
295 signalNotEmpty();
296 }
297
298 /**
299 * Inserts the specified element at the tail of this queue, waiting if
300 * necessary up to the specified wait time for space to become available.
301 *
302 * @return <tt>true</tt> if successful, or <tt>false</tt> if
303 * the specified waiting time elapses before space is available.
304 * @throws InterruptedException {@inheritDoc}
305 * @throws NullPointerException {@inheritDoc}
306 */
307 public boolean offer(E e, long timeout, TimeUnit unit)
308 throws InterruptedException {
309
310 if (e == null) throw new NullPointerException();
311 long nanos = unit.toNanos(timeout);
312 int c = -1;
313 final ReentrantLock putLock = this.putLock;
314 final AtomicInteger count = this.count;
315 putLock.lockInterruptibly();
316 try {
317 for (;;) {
318 if (count.get() < capacity) {
319 insert(e);
320 c = count.getAndIncrement();
321 if (c + 1 < capacity)
322 notFull.signal();
323 break;
324 }
325 if (nanos <= 0)
326 return false;
327 try {
328 nanos = notFull.awaitNanos(nanos);
329 } catch (InterruptedException ie) {
330 notFull.signal(); // propagate to a non-interrupted thread
331 throw ie;
332 }
333 }
334 } finally {
335 putLock.unlock();
336 }
337 if (c == 0)
338 signalNotEmpty();
339 return true;
340 }
341
342 /**
343 * Inserts the specified element at the tail of this queue if it is
344 * possible to do so immediately without exceeding the queue's capacity,
345 * returning <tt>true</tt> upon success and <tt>false</tt> if this queue
346 * is full.
347 * When using a capacity-restricted queue, this method is generally
348 * preferable to method {@link BlockingQueue#add add}, which can fail to
349 * insert an element only by throwing an exception.
350 *
351 * @throws NullPointerException if the specified element is null
352 */
353 public boolean offer(E e) {
354 if (e == null) throw new NullPointerException();
355 final AtomicInteger count = this.count;
356 if (count.get() == capacity)
357 return false;
358 int c = -1;
359 final ReentrantLock putLock = this.putLock;
360 putLock.lock();
361 try {
362 if (count.get() < capacity) {
363 insert(e);
364 c = count.getAndIncrement();
365 if (c + 1 < capacity)
366 notFull.signal();
367 }
368 } finally {
369 putLock.unlock();
370 }
371 if (c == 0)
372 signalNotEmpty();
373 return c >= 0;
374 }
375
376
377 public E take() throws InterruptedException {
378 E x;
379 int c = -1;
380 final AtomicInteger count = this.count;
381 final ReentrantLock takeLock = this.takeLock;
382 takeLock.lockInterruptibly();
383 try {
384 try {
385 while (count.get() == 0)
386 notEmpty.await();
387 } catch (InterruptedException ie) {
388 notEmpty.signal(); // propagate to a non-interrupted thread
389 throw ie;
390 }
391
392 x = extract();
393 c = count.getAndDecrement();
394 if (c > 1)
395 notEmpty.signal();
396 } finally {
397 takeLock.unlock();
398 }
399 if (c == capacity)
400 signalNotFull();
401 return x;
402 }
403
404 public E poll(long timeout, TimeUnit unit) throws InterruptedException {
405 E x = null;
406 int c = -1;
407 long nanos = unit.toNanos(timeout);
408 final AtomicInteger count = this.count;
409 final ReentrantLock takeLock = this.takeLock;
410 takeLock.lockInterruptibly();
411 try {
412 for (;;) {
413 if (count.get() > 0) {
414 x = extract();
415 c = count.getAndDecrement();
416 if (c > 1)
417 notEmpty.signal();
418 break;
419 }
420 if (nanos <= 0)
421 return null;
422 try {
423 nanos = notEmpty.awaitNanos(nanos);
424 } catch (InterruptedException ie) {
425 notEmpty.signal(); // propagate to a non-interrupted thread
426 throw ie;
427 }
428 }
429 } finally {
430 takeLock.unlock();
431 }
432 if (c == capacity)
433 signalNotFull();
434 return x;
435 }
436
437 public E poll() {
438 final AtomicInteger count = this.count;
439 if (count.get() == 0)
440 return null;
441 E x = null;
442 int c = -1;
443 final ReentrantLock takeLock = this.takeLock;
444 takeLock.lock();
445 try {
446 if (count.get() > 0) {
447 x = extract();
448 c = count.getAndDecrement();
449 if (c > 1)
450 notEmpty.signal();
451 }
452 } finally {
453 takeLock.unlock();
454 }
455 if (c == capacity)
456 signalNotFull();
457 return x;
458 }
459
460
461 public E peek() {
462 if (count.get() == 0)
463 return null;
464 final ReentrantLock takeLock = this.takeLock;
465 takeLock.lock();
466 try {
467 Node<E> first = head.next;
468 if (first == null)
469 return null;
470 else
471 return first.item;
472 } finally {
473 takeLock.unlock();
474 }
475 }
476
477 /**
478 * Removes a single instance of the specified element from this queue,
479 * if it is present. More formally, removes an element <tt>e</tt> such
480 * that <tt>o.equals(e)</tt>, if this queue contains one or more such
481 * elements.
482 * Returns <tt>true</tt> if this queue contained the specified element
483 * (or equivalently, if this queue changed as a result of the call).
484 *
485 * @param o element to be removed from this queue, if present
486 * @return <tt>true</tt> if this queue changed as a result of the call
487 */
488 public boolean remove(Object o) {
489 if (o == null) return false;
490 boolean removed = false;
491 fullyLock();
492 try {
493 Node<E> trail = head;
494 Node<E> p = head.next;
495 while (p != null) {
496 if (o.equals(p.item)) {
497 removed = true;
498 break;
499 }
500 trail = p;
501 p = p.next;
502 }
503 if (removed) {
504 p.item = null;
505 trail.next = p.next;
506 if (last == p)
507 last = trail;
508 if (count.getAndDecrement() == capacity)
509 notFull.signalAll();
510 }
511 } finally {
512 fullyUnlock();
513 }
514 return removed;
515 }
516
517 /**
518 * Returns an array containing all of the elements in this queue, in
519 * proper sequence.
520 *
521 * <p>The returned array will be "safe" in that no references to it are
522 * maintained by this queue. (In other words, this method must allocate
523 * a new array). The caller is thus free to modify the returned array.
524 *
525 * <p>This method acts as bridge between array-based and collection-based
526 * APIs.
527 *
528 * @return an array containing all of the elements in this queue
529 */
530 public Object[] toArray() {
531 fullyLock();
532 try {
533 int size = count.get();
534 Object[] a = new Object[size];
535 int k = 0;
536 for (Node<E> p = head.next; p != null; p = p.next)
537 a[k++] = p.item;
538 return a;
539 } finally {
540 fullyUnlock();
541 }
542 }
543
544 /**
545 * Returns an array containing all of the elements in this queue, in
546 * proper sequence; the runtime type of the returned array is that of
547 * the specified array. If the queue fits in the specified array, it
548 * is returned therein. Otherwise, a new array is allocated with the
549 * runtime type of the specified array and the size of this queue.
550 *
551 * <p>If this queue fits in the specified array with room to spare
552 * (i.e., the array has more elements than this queue), the element in
553 * the array immediately following the end of the queue is set to
554 * <tt>null</tt>.
555 *
556 * <p>Like the {@link #toArray()} method, this method acts as bridge between
557 * array-based and collection-based APIs. Further, this method allows
558 * precise control over the runtime type of the output array, and may,
559 * under certain circumstances, be used to save allocation costs.
560 *
561 * <p>Suppose <tt>x</tt> is a queue known to contain only strings.
562 * The following code can be used to dump the queue into a newly
563 * allocated array of <tt>String</tt>:
564 *
565 * <pre>
566 * String[] y = x.toArray(new String[0]);</pre>
567 *
568 * Note that <tt>toArray(new Object[0])</tt> is identical in function to
569 * <tt>toArray()</tt>.
570 *
571 * @param a the array into which the elements of the queue are to
572 * be stored, if it is big enough; otherwise, a new array of the
573 * same runtime type is allocated for this purpose
574 * @return an array containing all of the elements in this queue
575 * @throws ArrayStoreException if the runtime type of the specified array
576 * is not a supertype of the runtime type of every element in
577 * this queue
578 * @throws NullPointerException if the specified array is null
579 */
580 public <T> T[] toArray(T[] a) {
581 fullyLock();
582 try {
583 int size = count.get();
584 if (a.length < size)
585 a = (T[])java.lang.reflect.Array.newInstance
586 (a.getClass().getComponentType(), size);
587
588 int k = 0;
589 for (Node p = head.next; p != null; p = p.next)
590 a[k++] = (T)p.item;
591 if (a.length > k)
592 a[k] = null;
593 return a;
594 } finally {
595 fullyUnlock();
596 }
597 }
598
599 public String toString() {
600 fullyLock();
601 try {
602 return super.toString();
603 } finally {
604 fullyUnlock();
605 }
606 }
607
608 /**
609 * Atomically removes all of the elements from this queue.
610 * The queue will be empty after this call returns.
611 */
612 public void clear() {
613 fullyLock();
614 try {
615 head.next = null;
616 assert head.item == null;
617 last = head;
618 if (count.getAndSet(0) == capacity)
619 notFull.signalAll();
620 } finally {
621 fullyUnlock();
622 }
623 }
624
625 /**
626 * @throws UnsupportedOperationException {@inheritDoc}
627 * @throws ClassCastException {@inheritDoc}
628 * @throws NullPointerException {@inheritDoc}
629 * @throws IllegalArgumentException {@inheritDoc}
630 */
631 public int drainTo(Collection<? super E> c) {
632 if (c == null)
633 throw new NullPointerException();
634 if (c == this)
635 throw new IllegalArgumentException();
636 Node<E> first;
637 fullyLock();
638 try {
639 first = head.next;
640 head.next = null;
641 assert head.item == null;
642 last = head;
643 if (count.getAndSet(0) == capacity)
644 notFull.signalAll();
645 } finally {
646 fullyUnlock();
647 }
648 // Transfer the elements outside of locks
649 int n = 0;
650 for (Node<E> p = first; p != null; p = p.next) {
651 c.add(p.item);
652 p.item = null;
653 ++n;
654 }
655 return n;
656 }
657
658 /**
659 * @throws UnsupportedOperationException {@inheritDoc}
660 * @throws ClassCastException {@inheritDoc}
661 * @throws NullPointerException {@inheritDoc}
662 * @throws IllegalArgumentException {@inheritDoc}
663 */
664 public int drainTo(Collection<? super E> c, int maxElements) {
665 if (c == null)
666 throw new NullPointerException();
667 if (c == this)
668 throw new IllegalArgumentException();
669 fullyLock();
670 try {
671 int n = 0;
672 Node<E> p = head.next;
673 while (p != null && n < maxElements) {
674 c.add(p.item);
675 p.item = null;
676 p = p.next;
677 ++n;
678 }
679 if (n != 0) {
680 head.next = p;
681 assert head.item == null;
682 if (p == null)
683 last = head;
684 if (count.getAndAdd(-n) == capacity)
685 notFull.signalAll();
686 }
687 return n;
688 } finally {
689 fullyUnlock();
690 }
691 }
692
693 /**
694 * Returns an iterator over the elements in this queue in proper sequence.
695 * The returned <tt>Iterator</tt> is a "weakly consistent" iterator that
696 * will never throw {@link ConcurrentModificationException},
697 * and guarantees to traverse elements as they existed upon
698 * construction of the iterator, and may (but is not guaranteed to)
699 * reflect any modifications subsequent to construction.
700 *
701 * @return an iterator over the elements in this queue in proper sequence
702 */
703 public Iterator<E> iterator() {
704 return new Itr();
705 }
706
707 private class Itr implements Iterator<E> {
708 /*
709 * Basic weak-consistent iterator. At all times hold the next
710 * item to hand out so that if hasNext() reports true, we will
711 * still have it to return even if lost race with a take etc.
712 */
713 private Node<E> current;
714 private Node<E> lastRet;
715 private E currentElement;
716
717 Itr() {
718 final ReentrantLock putLock = LinkedBlockingQueue.this.putLock;
719 final ReentrantLock takeLock = LinkedBlockingQueue.this.takeLock;
720 putLock.lock();
721 takeLock.lock();
722 try {
723 current = head.next;
724 if (current != null)
725 currentElement = current.item;
726 } finally {
727 takeLock.unlock();
728 putLock.unlock();
729 }
730 }
731
732 public boolean hasNext() {
733 return current != null;
734 }
735
736 public E next() {
737 final ReentrantLock putLock = LinkedBlockingQueue.this.putLock;
738 final ReentrantLock takeLock = LinkedBlockingQueue.this.takeLock;
739 putLock.lock();
740 takeLock.lock();
741 try {
742 if (current == null)
743 throw new NoSuchElementException();
744 E x = currentElement;
745 lastRet = current;
746 current = current.next;
747 if (current != null)
748 currentElement = current.item;
749 return x;
750 } finally {
751 takeLock.unlock();
752 putLock.unlock();
753 }
754 }
755
756 public void remove() {
757 if (lastRet == null)
758 throw new IllegalStateException();
759 final ReentrantLock putLock = LinkedBlockingQueue.this.putLock;
760 final ReentrantLock takeLock = LinkedBlockingQueue.this.takeLock;
761 putLock.lock();
762 takeLock.lock();
763 try {
764 Node<E> node = lastRet;
765 lastRet = null;
766 Node<E> trail = head;
767 Node<E> p = head.next;
768 while (p != null && p != node) {
769 trail = p;
770 p = p.next;
771 }
772 if (p == node) {
773 p.item = null;
774 trail.next = p.next;
775 if (last == p)
776 last = trail;
777 int c = count.getAndDecrement();
778 if (c == capacity)
779 notFull.signalAll();
780 }
781 } finally {
782 takeLock.unlock();
783 putLock.unlock();
784 }
785 }
786 }
787
788 /**
789 * Save the state to a stream (that is, serialize it).
790 *
791 * @serialData The capacity is emitted (int), followed by all of
792 * its elements (each an <tt>Object</tt>) in the proper order,
793 * followed by a null
794 * @param s the stream
795 */
796 private void writeObject(java.io.ObjectOutputStream s)
797 throws java.io.IOException {
798
799 fullyLock();
800 try {
801 // Write out any hidden stuff, plus capacity
802 s.defaultWriteObject();
803
804 // Write out all elements in the proper order.
805 for (Node<E> p = head.next; p != null; p = p.next)
806 s.writeObject(p.item);
807
808 // Use trailing null as sentinel
809 s.writeObject(null);
810 } finally {
811 fullyUnlock();
812 }
813 }
814
815 /**
816 * Reconstitute this queue instance from a stream (that is,
817 * deserialize it).
818 * @param s the stream
819 */
820 private void readObject(java.io.ObjectInputStream s)
821 throws java.io.IOException, ClassNotFoundException {
822 // Read in capacity, and any hidden stuff
823 s.defaultReadObject();
824
825 count.set(0);
826 last = head = new Node<E>(null);
827
828 // Read in all elements and place in queue
829 for (;;) {
830 E item = (E)s.readObject();
831 if (item == null)
832 break;
833 add(item);
834 }
835 }
836}