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