rt/emul/compact/src/main/java/java/util/concurrent/ArrayBlockingQueue.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
import java.util.concurrent.locks.*;
jaroslav@1890
    38
import java.util.*;
jaroslav@1890
    39
jaroslav@1890
    40
/**
jaroslav@1890
    41
 * A bounded {@linkplain BlockingQueue blocking queue} backed by an
jaroslav@1890
    42
 * array.  This queue orders elements FIFO (first-in-first-out).  The
jaroslav@1890
    43
 * <em>head</em> of the queue is that element that has been on the
jaroslav@1890
    44
 * queue the longest time.  The <em>tail</em> of the queue is that
jaroslav@1890
    45
 * element that has been on the queue the shortest time. New elements
jaroslav@1890
    46
 * are inserted at the tail of the queue, and the queue retrieval
jaroslav@1890
    47
 * operations obtain elements at the head of the queue.
jaroslav@1890
    48
 *
jaroslav@1890
    49
 * <p>This is a classic &quot;bounded buffer&quot;, in which a
jaroslav@1890
    50
 * fixed-sized array holds elements inserted by producers and
jaroslav@1890
    51
 * extracted by consumers.  Once created, the capacity cannot be
jaroslav@1890
    52
 * changed.  Attempts to {@code put} an element into a full queue
jaroslav@1890
    53
 * will result in the operation blocking; attempts to {@code take} an
jaroslav@1890
    54
 * element from an empty queue will similarly block.
jaroslav@1890
    55
 *
jaroslav@1890
    56
 * <p>This class supports an optional fairness policy for ordering
jaroslav@1890
    57
 * waiting producer and consumer threads.  By default, this ordering
jaroslav@1890
    58
 * is not guaranteed. However, a queue constructed with fairness set
jaroslav@1890
    59
 * to {@code true} grants threads access in FIFO order. Fairness
jaroslav@1890
    60
 * generally decreases throughput but reduces variability and avoids
jaroslav@1890
    61
 * starvation.
jaroslav@1890
    62
 *
jaroslav@1890
    63
 * <p>This class and its iterator implement all of the
jaroslav@1890
    64
 * <em>optional</em> methods of the {@link Collection} and {@link
jaroslav@1890
    65
 * Iterator} interfaces.
jaroslav@1890
    66
 *
jaroslav@1890
    67
 * <p>This class is a member of the
jaroslav@1890
    68
 * <a href="{@docRoot}/../technotes/guides/collections/index.html">
jaroslav@1890
    69
 * Java Collections Framework</a>.
jaroslav@1890
    70
 *
jaroslav@1890
    71
 * @since 1.5
jaroslav@1890
    72
 * @author Doug Lea
jaroslav@1890
    73
 * @param <E> the type of elements held in this collection
jaroslav@1890
    74
 */
jaroslav@1890
    75
public class ArrayBlockingQueue<E> extends AbstractQueue<E>
jaroslav@1890
    76
        implements BlockingQueue<E>, java.io.Serializable {
jaroslav@1890
    77
jaroslav@1890
    78
    /**
jaroslav@1890
    79
     * Serialization ID. This class relies on default serialization
jaroslav@1890
    80
     * even for the items array, which is default-serialized, even if
jaroslav@1890
    81
     * it is empty. Otherwise it could not be declared final, which is
jaroslav@1890
    82
     * necessary here.
jaroslav@1890
    83
     */
jaroslav@1890
    84
    private static final long serialVersionUID = -817911632652898426L;
jaroslav@1890
    85
jaroslav@1890
    86
    /** The queued items */
jaroslav@1890
    87
    final Object[] items;
jaroslav@1890
    88
jaroslav@1890
    89
    /** items index for next take, poll, peek or remove */
jaroslav@1890
    90
    int takeIndex;
jaroslav@1890
    91
jaroslav@1890
    92
    /** items index for next put, offer, or add */
jaroslav@1890
    93
    int putIndex;
jaroslav@1890
    94
jaroslav@1890
    95
    /** Number of elements in the queue */
jaroslav@1890
    96
    int count;
jaroslav@1890
    97
jaroslav@1890
    98
    /*
jaroslav@1890
    99
     * Concurrency control uses the classic two-condition algorithm
jaroslav@1890
   100
     * found in any textbook.
jaroslav@1890
   101
     */
jaroslav@1890
   102
jaroslav@1890
   103
    /** Main lock guarding all access */
jaroslav@1890
   104
    final ReentrantLock lock;
jaroslav@1890
   105
    /** Condition for waiting takes */
jaroslav@1890
   106
    private final Condition notEmpty;
jaroslav@1890
   107
    /** Condition for waiting puts */
jaroslav@1890
   108
    private final Condition notFull;
jaroslav@1890
   109
jaroslav@1890
   110
    // Internal helper methods
jaroslav@1890
   111
jaroslav@1890
   112
    /**
jaroslav@1890
   113
     * Circularly increment i.
jaroslav@1890
   114
     */
jaroslav@1890
   115
    final int inc(int i) {
jaroslav@1890
   116
        return (++i == items.length) ? 0 : i;
jaroslav@1890
   117
    }
jaroslav@1890
   118
jaroslav@1890
   119
    /**
jaroslav@1890
   120
     * Circularly decrement i.
jaroslav@1890
   121
     */
jaroslav@1890
   122
    final int dec(int i) {
jaroslav@1890
   123
        return ((i == 0) ? items.length : i) - 1;
jaroslav@1890
   124
    }
jaroslav@1890
   125
jaroslav@1890
   126
    @SuppressWarnings("unchecked")
jaroslav@1890
   127
    static <E> E cast(Object item) {
jaroslav@1890
   128
        return (E) item;
jaroslav@1890
   129
    }
jaroslav@1890
   130
jaroslav@1890
   131
    /**
jaroslav@1890
   132
     * Returns item at index i.
jaroslav@1890
   133
     */
jaroslav@1890
   134
    final E itemAt(int i) {
jaroslav@1890
   135
        return this.<E>cast(items[i]);
jaroslav@1890
   136
    }
jaroslav@1890
   137
jaroslav@1890
   138
    /**
jaroslav@1890
   139
     * Throws NullPointerException if argument is null.
jaroslav@1890
   140
     *
jaroslav@1890
   141
     * @param v the element
jaroslav@1890
   142
     */
jaroslav@1890
   143
    private static void checkNotNull(Object v) {
jaroslav@1890
   144
        if (v == null)
jaroslav@1890
   145
            throw new NullPointerException();
jaroslav@1890
   146
    }
jaroslav@1890
   147
jaroslav@1890
   148
    /**
jaroslav@1890
   149
     * Inserts element at current put position, advances, and signals.
jaroslav@1890
   150
     * Call only when holding lock.
jaroslav@1890
   151
     */
jaroslav@1890
   152
    private void insert(E x) {
jaroslav@1890
   153
        items[putIndex] = x;
jaroslav@1890
   154
        putIndex = inc(putIndex);
jaroslav@1890
   155
        ++count;
jaroslav@1890
   156
        notEmpty.signal();
jaroslav@1890
   157
    }
jaroslav@1890
   158
jaroslav@1890
   159
    /**
jaroslav@1890
   160
     * Extracts element at current take position, advances, and signals.
jaroslav@1890
   161
     * Call only when holding lock.
jaroslav@1890
   162
     */
jaroslav@1890
   163
    private E extract() {
jaroslav@1890
   164
        final Object[] items = this.items;
jaroslav@1890
   165
        E x = this.<E>cast(items[takeIndex]);
jaroslav@1890
   166
        items[takeIndex] = null;
jaroslav@1890
   167
        takeIndex = inc(takeIndex);
jaroslav@1890
   168
        --count;
jaroslav@1890
   169
        notFull.signal();
jaroslav@1890
   170
        return x;
jaroslav@1890
   171
    }
jaroslav@1890
   172
jaroslav@1890
   173
    /**
jaroslav@1890
   174
     * Deletes item at position i.
jaroslav@1890
   175
     * Utility for remove and iterator.remove.
jaroslav@1890
   176
     * Call only when holding lock.
jaroslav@1890
   177
     */
jaroslav@1890
   178
    void removeAt(int i) {
jaroslav@1890
   179
        final Object[] items = this.items;
jaroslav@1890
   180
        // if removing front item, just advance
jaroslav@1890
   181
        if (i == takeIndex) {
jaroslav@1890
   182
            items[takeIndex] = null;
jaroslav@1890
   183
            takeIndex = inc(takeIndex);
jaroslav@1890
   184
        } else {
jaroslav@1890
   185
            // slide over all others up through putIndex.
jaroslav@1890
   186
            for (;;) {
jaroslav@1890
   187
                int nexti = inc(i);
jaroslav@1890
   188
                if (nexti != putIndex) {
jaroslav@1890
   189
                    items[i] = items[nexti];
jaroslav@1890
   190
                    i = nexti;
jaroslav@1890
   191
                } else {
jaroslav@1890
   192
                    items[i] = null;
jaroslav@1890
   193
                    putIndex = i;
jaroslav@1890
   194
                    break;
jaroslav@1890
   195
                }
jaroslav@1890
   196
            }
jaroslav@1890
   197
        }
jaroslav@1890
   198
        --count;
jaroslav@1890
   199
        notFull.signal();
jaroslav@1890
   200
    }
jaroslav@1890
   201
jaroslav@1890
   202
    /**
jaroslav@1890
   203
     * Creates an {@code ArrayBlockingQueue} with the given (fixed)
jaroslav@1890
   204
     * capacity and default access policy.
jaroslav@1890
   205
     *
jaroslav@1890
   206
     * @param capacity the capacity of this queue
jaroslav@1890
   207
     * @throws IllegalArgumentException if {@code capacity < 1}
jaroslav@1890
   208
     */
jaroslav@1890
   209
    public ArrayBlockingQueue(int capacity) {
jaroslav@1890
   210
        this(capacity, false);
jaroslav@1890
   211
    }
jaroslav@1890
   212
jaroslav@1890
   213
    /**
jaroslav@1890
   214
     * Creates an {@code ArrayBlockingQueue} with the given (fixed)
jaroslav@1890
   215
     * capacity and the specified access policy.
jaroslav@1890
   216
     *
jaroslav@1890
   217
     * @param capacity the capacity of this queue
jaroslav@1890
   218
     * @param fair if {@code true} then queue accesses for threads blocked
jaroslav@1890
   219
     *        on insertion or removal, are processed in FIFO order;
jaroslav@1890
   220
     *        if {@code false} the access order is unspecified.
jaroslav@1890
   221
     * @throws IllegalArgumentException if {@code capacity < 1}
jaroslav@1890
   222
     */
jaroslav@1890
   223
    public ArrayBlockingQueue(int capacity, boolean fair) {
jaroslav@1890
   224
        if (capacity <= 0)
jaroslav@1890
   225
            throw new IllegalArgumentException();
jaroslav@1890
   226
        this.items = new Object[capacity];
jaroslav@1890
   227
        lock = new ReentrantLock(fair);
jaroslav@1890
   228
        notEmpty = lock.newCondition();
jaroslav@1890
   229
        notFull =  lock.newCondition();
jaroslav@1890
   230
    }
jaroslav@1890
   231
jaroslav@1890
   232
    /**
jaroslav@1890
   233
     * Creates an {@code ArrayBlockingQueue} with the given (fixed)
jaroslav@1890
   234
     * capacity, the specified access policy and initially containing the
jaroslav@1890
   235
     * elements of the given collection,
jaroslav@1890
   236
     * added in traversal order of the collection's iterator.
jaroslav@1890
   237
     *
jaroslav@1890
   238
     * @param capacity the capacity of this queue
jaroslav@1890
   239
     * @param fair if {@code true} then queue accesses for threads blocked
jaroslav@1890
   240
     *        on insertion or removal, are processed in FIFO order;
jaroslav@1890
   241
     *        if {@code false} the access order is unspecified.
jaroslav@1890
   242
     * @param c the collection of elements to initially contain
jaroslav@1890
   243
     * @throws IllegalArgumentException if {@code capacity} is less than
jaroslav@1890
   244
     *         {@code c.size()}, or less than 1.
jaroslav@1890
   245
     * @throws NullPointerException if the specified collection or any
jaroslav@1890
   246
     *         of its elements are null
jaroslav@1890
   247
     */
jaroslav@1890
   248
    public ArrayBlockingQueue(int capacity, boolean fair,
jaroslav@1890
   249
                              Collection<? extends E> c) {
jaroslav@1890
   250
        this(capacity, fair);
jaroslav@1890
   251
jaroslav@1890
   252
        final ReentrantLock lock = this.lock;
jaroslav@1890
   253
        lock.lock(); // Lock only for visibility, not mutual exclusion
jaroslav@1890
   254
        try {
jaroslav@1890
   255
            int i = 0;
jaroslav@1890
   256
            try {
jaroslav@1890
   257
                for (E e : c) {
jaroslav@1890
   258
                    checkNotNull(e);
jaroslav@1890
   259
                    items[i++] = e;
jaroslav@1890
   260
                }
jaroslav@1890
   261
            } catch (ArrayIndexOutOfBoundsException ex) {
jaroslav@1890
   262
                throw new IllegalArgumentException();
jaroslav@1890
   263
            }
jaroslav@1890
   264
            count = i;
jaroslav@1890
   265
            putIndex = (i == capacity) ? 0 : i;
jaroslav@1890
   266
        } finally {
jaroslav@1890
   267
            lock.unlock();
jaroslav@1890
   268
        }
jaroslav@1890
   269
    }
jaroslav@1890
   270
jaroslav@1890
   271
    /**
jaroslav@1890
   272
     * Inserts the specified element at the tail of this queue if it is
jaroslav@1890
   273
     * possible to do so immediately without exceeding the queue's capacity,
jaroslav@1890
   274
     * returning {@code true} upon success and throwing an
jaroslav@1890
   275
     * {@code IllegalStateException} if this queue is full.
jaroslav@1890
   276
     *
jaroslav@1890
   277
     * @param e the element to add
jaroslav@1890
   278
     * @return {@code true} (as specified by {@link Collection#add})
jaroslav@1890
   279
     * @throws IllegalStateException if this queue is full
jaroslav@1890
   280
     * @throws NullPointerException if the specified element is null
jaroslav@1890
   281
     */
jaroslav@1890
   282
    public boolean add(E e) {
jaroslav@1890
   283
        return super.add(e);
jaroslav@1890
   284
    }
jaroslav@1890
   285
jaroslav@1890
   286
    /**
jaroslav@1890
   287
     * Inserts the specified element at the tail of this queue if it is
jaroslav@1890
   288
     * possible to do so immediately without exceeding the queue's capacity,
jaroslav@1890
   289
     * returning {@code true} upon success and {@code false} if this queue
jaroslav@1890
   290
     * is full.  This method is generally preferable to method {@link #add},
jaroslav@1890
   291
     * which can fail to insert an element only by throwing an exception.
jaroslav@1890
   292
     *
jaroslav@1890
   293
     * @throws NullPointerException if the specified element is null
jaroslav@1890
   294
     */
jaroslav@1890
   295
    public boolean offer(E e) {
jaroslav@1890
   296
        checkNotNull(e);
jaroslav@1890
   297
        final ReentrantLock lock = this.lock;
jaroslav@1890
   298
        lock.lock();
jaroslav@1890
   299
        try {
jaroslav@1890
   300
            if (count == items.length)
jaroslav@1890
   301
                return false;
jaroslav@1890
   302
            else {
jaroslav@1890
   303
                insert(e);
jaroslav@1890
   304
                return true;
jaroslav@1890
   305
            }
jaroslav@1890
   306
        } finally {
jaroslav@1890
   307
            lock.unlock();
jaroslav@1890
   308
        }
jaroslav@1890
   309
    }
jaroslav@1890
   310
jaroslav@1890
   311
    /**
jaroslav@1890
   312
     * Inserts the specified element at the tail of this queue, waiting
jaroslav@1890
   313
     * for space to become available if the queue is full.
jaroslav@1890
   314
     *
jaroslav@1890
   315
     * @throws InterruptedException {@inheritDoc}
jaroslav@1890
   316
     * @throws NullPointerException {@inheritDoc}
jaroslav@1890
   317
     */
jaroslav@1890
   318
    public void put(E e) throws InterruptedException {
jaroslav@1890
   319
        checkNotNull(e);
jaroslav@1890
   320
        final ReentrantLock lock = this.lock;
jaroslav@1890
   321
        lock.lockInterruptibly();
jaroslav@1890
   322
        try {
jaroslav@1890
   323
            while (count == items.length)
jaroslav@1890
   324
                notFull.await();
jaroslav@1890
   325
            insert(e);
jaroslav@1890
   326
        } finally {
jaroslav@1890
   327
            lock.unlock();
jaroslav@1890
   328
        }
jaroslav@1890
   329
    }
jaroslav@1890
   330
jaroslav@1890
   331
    /**
jaroslav@1890
   332
     * Inserts the specified element at the tail of this queue, waiting
jaroslav@1890
   333
     * up to the specified wait time for space to become available if
jaroslav@1890
   334
     * the queue is full.
jaroslav@1890
   335
     *
jaroslav@1890
   336
     * @throws InterruptedException {@inheritDoc}
jaroslav@1890
   337
     * @throws NullPointerException {@inheritDoc}
jaroslav@1890
   338
     */
jaroslav@1890
   339
    public boolean offer(E e, long timeout, TimeUnit unit)
jaroslav@1890
   340
        throws InterruptedException {
jaroslav@1890
   341
jaroslav@1890
   342
        checkNotNull(e);
jaroslav@1890
   343
        long nanos = unit.toNanos(timeout);
jaroslav@1890
   344
        final ReentrantLock lock = this.lock;
jaroslav@1890
   345
        lock.lockInterruptibly();
jaroslav@1890
   346
        try {
jaroslav@1890
   347
            while (count == items.length) {
jaroslav@1890
   348
                if (nanos <= 0)
jaroslav@1890
   349
                    return false;
jaroslav@1890
   350
                nanos = notFull.awaitNanos(nanos);
jaroslav@1890
   351
            }
jaroslav@1890
   352
            insert(e);
jaroslav@1890
   353
            return true;
jaroslav@1890
   354
        } finally {
jaroslav@1890
   355
            lock.unlock();
jaroslav@1890
   356
        }
jaroslav@1890
   357
    }
jaroslav@1890
   358
jaroslav@1890
   359
    public E poll() {
jaroslav@1890
   360
        final ReentrantLock lock = this.lock;
jaroslav@1890
   361
        lock.lock();
jaroslav@1890
   362
        try {
jaroslav@1890
   363
            return (count == 0) ? null : extract();
jaroslav@1890
   364
        } finally {
jaroslav@1890
   365
            lock.unlock();
jaroslav@1890
   366
        }
jaroslav@1890
   367
    }
jaroslav@1890
   368
jaroslav@1890
   369
    public E take() throws InterruptedException {
jaroslav@1890
   370
        final ReentrantLock lock = this.lock;
jaroslav@1890
   371
        lock.lockInterruptibly();
jaroslav@1890
   372
        try {
jaroslav@1890
   373
            while (count == 0)
jaroslav@1890
   374
                notEmpty.await();
jaroslav@1890
   375
            return extract();
jaroslav@1890
   376
        } finally {
jaroslav@1890
   377
            lock.unlock();
jaroslav@1890
   378
        }
jaroslav@1890
   379
    }
jaroslav@1890
   380
jaroslav@1890
   381
    public E poll(long timeout, TimeUnit unit) throws InterruptedException {
jaroslav@1890
   382
        long nanos = unit.toNanos(timeout);
jaroslav@1890
   383
        final ReentrantLock lock = this.lock;
jaroslav@1890
   384
        lock.lockInterruptibly();
jaroslav@1890
   385
        try {
jaroslav@1890
   386
            while (count == 0) {
jaroslav@1890
   387
                if (nanos <= 0)
jaroslav@1890
   388
                    return null;
jaroslav@1890
   389
                nanos = notEmpty.awaitNanos(nanos);
jaroslav@1890
   390
            }
jaroslav@1890
   391
            return extract();
jaroslav@1890
   392
        } finally {
jaroslav@1890
   393
            lock.unlock();
jaroslav@1890
   394
        }
jaroslav@1890
   395
    }
jaroslav@1890
   396
jaroslav@1890
   397
    public E peek() {
jaroslav@1890
   398
        final ReentrantLock lock = this.lock;
jaroslav@1890
   399
        lock.lock();
jaroslav@1890
   400
        try {
jaroslav@1890
   401
            return (count == 0) ? null : itemAt(takeIndex);
jaroslav@1890
   402
        } finally {
jaroslav@1890
   403
            lock.unlock();
jaroslav@1890
   404
        }
jaroslav@1890
   405
    }
jaroslav@1890
   406
jaroslav@1890
   407
    // this doc comment is overridden to remove the reference to collections
jaroslav@1890
   408
    // greater in size than Integer.MAX_VALUE
jaroslav@1890
   409
    /**
jaroslav@1890
   410
     * Returns the number of elements in this queue.
jaroslav@1890
   411
     *
jaroslav@1890
   412
     * @return the number of elements in this queue
jaroslav@1890
   413
     */
jaroslav@1890
   414
    public int size() {
jaroslav@1890
   415
        final ReentrantLock lock = this.lock;
jaroslav@1890
   416
        lock.lock();
jaroslav@1890
   417
        try {
jaroslav@1890
   418
            return count;
jaroslav@1890
   419
        } finally {
jaroslav@1890
   420
            lock.unlock();
jaroslav@1890
   421
        }
jaroslav@1890
   422
    }
jaroslav@1890
   423
jaroslav@1890
   424
    // this doc comment is a modified copy of the inherited doc comment,
jaroslav@1890
   425
    // without the reference to unlimited queues.
jaroslav@1890
   426
    /**
jaroslav@1890
   427
     * Returns the number of additional elements that this queue can ideally
jaroslav@1890
   428
     * (in the absence of memory or resource constraints) accept without
jaroslav@1890
   429
     * blocking. This is always equal to the initial capacity of this queue
jaroslav@1890
   430
     * less the current {@code size} of this queue.
jaroslav@1890
   431
     *
jaroslav@1890
   432
     * <p>Note that you <em>cannot</em> always tell if an attempt to insert
jaroslav@1890
   433
     * an element will succeed by inspecting {@code remainingCapacity}
jaroslav@1890
   434
     * because it may be the case that another thread is about to
jaroslav@1890
   435
     * insert or remove an element.
jaroslav@1890
   436
     */
jaroslav@1890
   437
    public int remainingCapacity() {
jaroslav@1890
   438
        final ReentrantLock lock = this.lock;
jaroslav@1890
   439
        lock.lock();
jaroslav@1890
   440
        try {
jaroslav@1890
   441
            return items.length - count;
jaroslav@1890
   442
        } finally {
jaroslav@1890
   443
            lock.unlock();
jaroslav@1890
   444
        }
jaroslav@1890
   445
    }
jaroslav@1890
   446
jaroslav@1890
   447
    /**
jaroslav@1890
   448
     * Removes a single instance of the specified element from this queue,
jaroslav@1890
   449
     * if it is present.  More formally, removes an element {@code e} such
jaroslav@1890
   450
     * that {@code o.equals(e)}, if this queue contains one or more such
jaroslav@1890
   451
     * elements.
jaroslav@1890
   452
     * Returns {@code true} if this queue contained the specified element
jaroslav@1890
   453
     * (or equivalently, if this queue changed as a result of the call).
jaroslav@1890
   454
     *
jaroslav@1890
   455
     * <p>Removal of interior elements in circular array based queues
jaroslav@1890
   456
     * is an intrinsically slow and disruptive operation, so should
jaroslav@1890
   457
     * be undertaken only in exceptional circumstances, ideally
jaroslav@1890
   458
     * only when the queue is known not to be accessible by other
jaroslav@1890
   459
     * threads.
jaroslav@1890
   460
     *
jaroslav@1890
   461
     * @param o element to be removed from this queue, if present
jaroslav@1890
   462
     * @return {@code true} if this queue changed as a result of the call
jaroslav@1890
   463
     */
jaroslav@1890
   464
    public boolean remove(Object o) {
jaroslav@1890
   465
        if (o == null) return false;
jaroslav@1890
   466
        final Object[] items = this.items;
jaroslav@1890
   467
        final ReentrantLock lock = this.lock;
jaroslav@1890
   468
        lock.lock();
jaroslav@1890
   469
        try {
jaroslav@1890
   470
            for (int i = takeIndex, k = count; k > 0; i = inc(i), k--) {
jaroslav@1890
   471
                if (o.equals(items[i])) {
jaroslav@1890
   472
                    removeAt(i);
jaroslav@1890
   473
                    return true;
jaroslav@1890
   474
                }
jaroslav@1890
   475
            }
jaroslav@1890
   476
            return false;
jaroslav@1890
   477
        } finally {
jaroslav@1890
   478
            lock.unlock();
jaroslav@1890
   479
        }
jaroslav@1890
   480
    }
jaroslav@1890
   481
jaroslav@1890
   482
    /**
jaroslav@1890
   483
     * Returns {@code true} if this queue contains the specified element.
jaroslav@1890
   484
     * More formally, returns {@code true} if and only if this queue contains
jaroslav@1890
   485
     * at least one element {@code e} such that {@code o.equals(e)}.
jaroslav@1890
   486
     *
jaroslav@1890
   487
     * @param o object to be checked for containment in this queue
jaroslav@1890
   488
     * @return {@code true} if this queue contains the specified element
jaroslav@1890
   489
     */
jaroslav@1890
   490
    public boolean contains(Object o) {
jaroslav@1890
   491
        if (o == null) return false;
jaroslav@1890
   492
        final Object[] items = this.items;
jaroslav@1890
   493
        final ReentrantLock lock = this.lock;
jaroslav@1890
   494
        lock.lock();
jaroslav@1890
   495
        try {
jaroslav@1890
   496
            for (int i = takeIndex, k = count; k > 0; i = inc(i), k--)
jaroslav@1890
   497
                if (o.equals(items[i]))
jaroslav@1890
   498
                    return true;
jaroslav@1890
   499
            return false;
jaroslav@1890
   500
        } finally {
jaroslav@1890
   501
            lock.unlock();
jaroslav@1890
   502
        }
jaroslav@1890
   503
    }
jaroslav@1890
   504
jaroslav@1890
   505
    /**
jaroslav@1890
   506
     * Returns an array containing all of the elements in this queue, in
jaroslav@1890
   507
     * proper sequence.
jaroslav@1890
   508
     *
jaroslav@1890
   509
     * <p>The returned array will be "safe" in that no references to it are
jaroslav@1890
   510
     * maintained by this queue.  (In other words, this method must allocate
jaroslav@1890
   511
     * a new array).  The caller is thus free to modify the returned array.
jaroslav@1890
   512
     *
jaroslav@1890
   513
     * <p>This method acts as bridge between array-based and collection-based
jaroslav@1890
   514
     * APIs.
jaroslav@1890
   515
     *
jaroslav@1890
   516
     * @return an array containing all of the elements in this queue
jaroslav@1890
   517
     */
jaroslav@1890
   518
    public Object[] toArray() {
jaroslav@1890
   519
        final Object[] items = this.items;
jaroslav@1890
   520
        final ReentrantLock lock = this.lock;
jaroslav@1890
   521
        lock.lock();
jaroslav@1890
   522
        try {
jaroslav@1890
   523
            final int count = this.count;
jaroslav@1890
   524
            Object[] a = new Object[count];
jaroslav@1890
   525
            for (int i = takeIndex, k = 0; k < count; i = inc(i), k++)
jaroslav@1890
   526
                a[k] = items[i];
jaroslav@1890
   527
            return a;
jaroslav@1890
   528
        } finally {
jaroslav@1890
   529
            lock.unlock();
jaroslav@1890
   530
        }
jaroslav@1890
   531
    }
jaroslav@1890
   532
jaroslav@1890
   533
    /**
jaroslav@1890
   534
     * Returns an array containing all of the elements in this queue, in
jaroslav@1890
   535
     * proper sequence; the runtime type of the returned array is that of
jaroslav@1890
   536
     * the specified array.  If the queue fits in the specified array, it
jaroslav@1890
   537
     * is returned therein.  Otherwise, a new array is allocated with the
jaroslav@1890
   538
     * runtime type of the specified array and the size of this queue.
jaroslav@1890
   539
     *
jaroslav@1890
   540
     * <p>If this queue fits in the specified array with room to spare
jaroslav@1890
   541
     * (i.e., the array has more elements than this queue), the element in
jaroslav@1890
   542
     * the array immediately following the end of the queue is set to
jaroslav@1890
   543
     * {@code null}.
jaroslav@1890
   544
     *
jaroslav@1890
   545
     * <p>Like the {@link #toArray()} method, this method acts as bridge between
jaroslav@1890
   546
     * array-based and collection-based APIs.  Further, this method allows
jaroslav@1890
   547
     * precise control over the runtime type of the output array, and may,
jaroslav@1890
   548
     * under certain circumstances, be used to save allocation costs.
jaroslav@1890
   549
     *
jaroslav@1890
   550
     * <p>Suppose {@code x} is a queue known to contain only strings.
jaroslav@1890
   551
     * The following code can be used to dump the queue into a newly
jaroslav@1890
   552
     * allocated array of {@code String}:
jaroslav@1890
   553
     *
jaroslav@1890
   554
     * <pre>
jaroslav@1890
   555
     *     String[] y = x.toArray(new String[0]);</pre>
jaroslav@1890
   556
     *
jaroslav@1890
   557
     * Note that {@code toArray(new Object[0])} is identical in function to
jaroslav@1890
   558
     * {@code toArray()}.
jaroslav@1890
   559
     *
jaroslav@1890
   560
     * @param a the array into which the elements of the queue are to
jaroslav@1890
   561
     *          be stored, if it is big enough; otherwise, a new array of the
jaroslav@1890
   562
     *          same runtime type is allocated for this purpose
jaroslav@1890
   563
     * @return an array containing all of the elements in this queue
jaroslav@1890
   564
     * @throws ArrayStoreException if the runtime type of the specified array
jaroslav@1890
   565
     *         is not a supertype of the runtime type of every element in
jaroslav@1890
   566
     *         this queue
jaroslav@1890
   567
     * @throws NullPointerException if the specified array is null
jaroslav@1890
   568
     */
jaroslav@1890
   569
    @SuppressWarnings("unchecked")
jaroslav@1890
   570
    public <T> T[] toArray(T[] a) {
jaroslav@1890
   571
        final Object[] items = this.items;
jaroslav@1890
   572
        final ReentrantLock lock = this.lock;
jaroslav@1890
   573
        lock.lock();
jaroslav@1890
   574
        try {
jaroslav@1890
   575
            final int count = this.count;
jaroslav@1890
   576
            final int len = a.length;
jaroslav@1890
   577
            if (len < count)
jaroslav@1890
   578
                a = (T[])java.lang.reflect.Array.newInstance(
jaroslav@1890
   579
                    a.getClass().getComponentType(), count);
jaroslav@1890
   580
            for (int i = takeIndex, k = 0; k < count; i = inc(i), k++)
jaroslav@1890
   581
                a[k] = (T) items[i];
jaroslav@1890
   582
            if (len > count)
jaroslav@1890
   583
                a[count] = null;
jaroslav@1890
   584
            return a;
jaroslav@1890
   585
        } finally {
jaroslav@1890
   586
            lock.unlock();
jaroslav@1890
   587
        }
jaroslav@1890
   588
    }
jaroslav@1890
   589
jaroslav@1890
   590
    public String toString() {
jaroslav@1890
   591
        final ReentrantLock lock = this.lock;
jaroslav@1890
   592
        lock.lock();
jaroslav@1890
   593
        try {
jaroslav@1890
   594
            int k = count;
jaroslav@1890
   595
            if (k == 0)
jaroslav@1890
   596
                return "[]";
jaroslav@1890
   597
jaroslav@1890
   598
            StringBuilder sb = new StringBuilder();
jaroslav@1890
   599
            sb.append('[');
jaroslav@1890
   600
            for (int i = takeIndex; ; i = inc(i)) {
jaroslav@1890
   601
                Object e = items[i];
jaroslav@1890
   602
                sb.append(e == this ? "(this Collection)" : e);
jaroslav@1890
   603
                if (--k == 0)
jaroslav@1890
   604
                    return sb.append(']').toString();
jaroslav@1890
   605
                sb.append(',').append(' ');
jaroslav@1890
   606
            }
jaroslav@1890
   607
        } finally {
jaroslav@1890
   608
            lock.unlock();
jaroslav@1890
   609
        }
jaroslav@1890
   610
    }
jaroslav@1890
   611
jaroslav@1890
   612
    /**
jaroslav@1890
   613
     * Atomically removes all of the elements from this queue.
jaroslav@1890
   614
     * The queue will be empty after this call returns.
jaroslav@1890
   615
     */
jaroslav@1890
   616
    public void clear() {
jaroslav@1890
   617
        final Object[] items = this.items;
jaroslav@1890
   618
        final ReentrantLock lock = this.lock;
jaroslav@1890
   619
        lock.lock();
jaroslav@1890
   620
        try {
jaroslav@1890
   621
            for (int i = takeIndex, k = count; k > 0; i = inc(i), k--)
jaroslav@1890
   622
                items[i] = null;
jaroslav@1890
   623
            count = 0;
jaroslav@1890
   624
            putIndex = 0;
jaroslav@1890
   625
            takeIndex = 0;
jaroslav@1890
   626
            notFull.signalAll();
jaroslav@1890
   627
        } finally {
jaroslav@1890
   628
            lock.unlock();
jaroslav@1890
   629
        }
jaroslav@1890
   630
    }
jaroslav@1890
   631
jaroslav@1890
   632
    /**
jaroslav@1890
   633
     * @throws UnsupportedOperationException {@inheritDoc}
jaroslav@1890
   634
     * @throws ClassCastException            {@inheritDoc}
jaroslav@1890
   635
     * @throws NullPointerException          {@inheritDoc}
jaroslav@1890
   636
     * @throws IllegalArgumentException      {@inheritDoc}
jaroslav@1890
   637
     */
jaroslav@1890
   638
    public int drainTo(Collection<? super E> c) {
jaroslav@1890
   639
        checkNotNull(c);
jaroslav@1890
   640
        if (c == this)
jaroslav@1890
   641
            throw new IllegalArgumentException();
jaroslav@1890
   642
        final Object[] items = this.items;
jaroslav@1890
   643
        final ReentrantLock lock = this.lock;
jaroslav@1890
   644
        lock.lock();
jaroslav@1890
   645
        try {
jaroslav@1890
   646
            int i = takeIndex;
jaroslav@1890
   647
            int n = 0;
jaroslav@1890
   648
            int max = count;
jaroslav@1890
   649
            while (n < max) {
jaroslav@1890
   650
                c.add(this.<E>cast(items[i]));
jaroslav@1890
   651
                items[i] = null;
jaroslav@1890
   652
                i = inc(i);
jaroslav@1890
   653
                ++n;
jaroslav@1890
   654
            }
jaroslav@1890
   655
            if (n > 0) {
jaroslav@1890
   656
                count = 0;
jaroslav@1890
   657
                putIndex = 0;
jaroslav@1890
   658
                takeIndex = 0;
jaroslav@1890
   659
                notFull.signalAll();
jaroslav@1890
   660
            }
jaroslav@1890
   661
            return n;
jaroslav@1890
   662
        } finally {
jaroslav@1890
   663
            lock.unlock();
jaroslav@1890
   664
        }
jaroslav@1890
   665
    }
jaroslav@1890
   666
jaroslav@1890
   667
    /**
jaroslav@1890
   668
     * @throws UnsupportedOperationException {@inheritDoc}
jaroslav@1890
   669
     * @throws ClassCastException            {@inheritDoc}
jaroslav@1890
   670
     * @throws NullPointerException          {@inheritDoc}
jaroslav@1890
   671
     * @throws IllegalArgumentException      {@inheritDoc}
jaroslav@1890
   672
     */
jaroslav@1890
   673
    public int drainTo(Collection<? super E> c, int maxElements) {
jaroslav@1890
   674
        checkNotNull(c);
jaroslav@1890
   675
        if (c == this)
jaroslav@1890
   676
            throw new IllegalArgumentException();
jaroslav@1890
   677
        if (maxElements <= 0)
jaroslav@1890
   678
            return 0;
jaroslav@1890
   679
        final Object[] items = this.items;
jaroslav@1890
   680
        final ReentrantLock lock = this.lock;
jaroslav@1890
   681
        lock.lock();
jaroslav@1890
   682
        try {
jaroslav@1890
   683
            int i = takeIndex;
jaroslav@1890
   684
            int n = 0;
jaroslav@1890
   685
            int max = (maxElements < count) ? maxElements : count;
jaroslav@1890
   686
            while (n < max) {
jaroslav@1890
   687
                c.add(this.<E>cast(items[i]));
jaroslav@1890
   688
                items[i] = null;
jaroslav@1890
   689
                i = inc(i);
jaroslav@1890
   690
                ++n;
jaroslav@1890
   691
            }
jaroslav@1890
   692
            if (n > 0) {
jaroslav@1890
   693
                count -= n;
jaroslav@1890
   694
                takeIndex = i;
jaroslav@1890
   695
                notFull.signalAll();
jaroslav@1890
   696
            }
jaroslav@1890
   697
            return n;
jaroslav@1890
   698
        } finally {
jaroslav@1890
   699
            lock.unlock();
jaroslav@1890
   700
        }
jaroslav@1890
   701
    }
jaroslav@1890
   702
jaroslav@1890
   703
    /**
jaroslav@1890
   704
     * Returns an iterator over the elements in this queue in proper sequence.
jaroslav@1890
   705
     * The elements will be returned in order from first (head) to last (tail).
jaroslav@1890
   706
     *
jaroslav@1890
   707
     * <p>The returned {@code Iterator} is a "weakly consistent" iterator that
jaroslav@1890
   708
     * will never throw {@link java.util.ConcurrentModificationException
jaroslav@1890
   709
     * ConcurrentModificationException},
jaroslav@1890
   710
     * and guarantees to traverse elements as they existed upon
jaroslav@1890
   711
     * construction of the iterator, and may (but is not guaranteed to)
jaroslav@1890
   712
     * reflect any modifications subsequent to construction.
jaroslav@1890
   713
     *
jaroslav@1890
   714
     * @return an iterator over the elements in this queue in proper sequence
jaroslav@1890
   715
     */
jaroslav@1890
   716
    public Iterator<E> iterator() {
jaroslav@1890
   717
        return new Itr();
jaroslav@1890
   718
    }
jaroslav@1890
   719
jaroslav@1890
   720
    /**
jaroslav@1890
   721
     * Iterator for ArrayBlockingQueue. To maintain weak consistency
jaroslav@1890
   722
     * with respect to puts and takes, we (1) read ahead one slot, so
jaroslav@1890
   723
     * as to not report hasNext true but then not have an element to
jaroslav@1890
   724
     * return -- however we later recheck this slot to use the most
jaroslav@1890
   725
     * current value; (2) ensure that each array slot is traversed at
jaroslav@1890
   726
     * most once (by tracking "remaining" elements); (3) skip over
jaroslav@1890
   727
     * null slots, which can occur if takes race ahead of iterators.
jaroslav@1890
   728
     * However, for circular array-based queues, we cannot rely on any
jaroslav@1890
   729
     * well established definition of what it means to be weakly
jaroslav@1890
   730
     * consistent with respect to interior removes since these may
jaroslav@1890
   731
     * require slot overwrites in the process of sliding elements to
jaroslav@1890
   732
     * cover gaps. So we settle for resiliency, operating on
jaroslav@1890
   733
     * established apparent nexts, which may miss some elements that
jaroslav@1890
   734
     * have moved between calls to next.
jaroslav@1890
   735
     */
jaroslav@1890
   736
    private class Itr implements Iterator<E> {
jaroslav@1890
   737
        private int remaining; // Number of elements yet to be returned
jaroslav@1890
   738
        private int nextIndex; // Index of element to be returned by next
jaroslav@1890
   739
        private E nextItem;    // Element to be returned by next call to next
jaroslav@1890
   740
        private E lastItem;    // Element returned by last call to next
jaroslav@1890
   741
        private int lastRet;   // Index of last element returned, or -1 if none
jaroslav@1890
   742
jaroslav@1890
   743
        Itr() {
jaroslav@1890
   744
            final ReentrantLock lock = ArrayBlockingQueue.this.lock;
jaroslav@1890
   745
            lock.lock();
jaroslav@1890
   746
            try {
jaroslav@1890
   747
                lastRet = -1;
jaroslav@1890
   748
                if ((remaining = count) > 0)
jaroslav@1890
   749
                    nextItem = itemAt(nextIndex = takeIndex);
jaroslav@1890
   750
            } finally {
jaroslav@1890
   751
                lock.unlock();
jaroslav@1890
   752
            }
jaroslav@1890
   753
        }
jaroslav@1890
   754
jaroslav@1890
   755
        public boolean hasNext() {
jaroslav@1890
   756
            return remaining > 0;
jaroslav@1890
   757
        }
jaroslav@1890
   758
jaroslav@1890
   759
        public E next() {
jaroslav@1890
   760
            final ReentrantLock lock = ArrayBlockingQueue.this.lock;
jaroslav@1890
   761
            lock.lock();
jaroslav@1890
   762
            try {
jaroslav@1890
   763
                if (remaining <= 0)
jaroslav@1890
   764
                    throw new NoSuchElementException();
jaroslav@1890
   765
                lastRet = nextIndex;
jaroslav@1890
   766
                E x = itemAt(nextIndex);  // check for fresher value
jaroslav@1890
   767
                if (x == null) {
jaroslav@1890
   768
                    x = nextItem;         // we are forced to report old value
jaroslav@1890
   769
                    lastItem = null;      // but ensure remove fails
jaroslav@1890
   770
                }
jaroslav@1890
   771
                else
jaroslav@1890
   772
                    lastItem = x;
jaroslav@1890
   773
                while (--remaining > 0 && // skip over nulls
jaroslav@1890
   774
                       (nextItem = itemAt(nextIndex = inc(nextIndex))) == null)
jaroslav@1890
   775
                    ;
jaroslav@1890
   776
                return x;
jaroslav@1890
   777
            } finally {
jaroslav@1890
   778
                lock.unlock();
jaroslav@1890
   779
            }
jaroslav@1890
   780
        }
jaroslav@1890
   781
jaroslav@1890
   782
        public void remove() {
jaroslav@1890
   783
            final ReentrantLock lock = ArrayBlockingQueue.this.lock;
jaroslav@1890
   784
            lock.lock();
jaroslav@1890
   785
            try {
jaroslav@1890
   786
                int i = lastRet;
jaroslav@1890
   787
                if (i == -1)
jaroslav@1890
   788
                    throw new IllegalStateException();
jaroslav@1890
   789
                lastRet = -1;
jaroslav@1890
   790
                E x = lastItem;
jaroslav@1890
   791
                lastItem = null;
jaroslav@1890
   792
                // only remove if item still at index
jaroslav@1890
   793
                if (x != null && x == items[i]) {
jaroslav@1890
   794
                    boolean removingHead = (i == takeIndex);
jaroslav@1890
   795
                    removeAt(i);
jaroslav@1890
   796
                    if (!removingHead)
jaroslav@1890
   797
                        nextIndex = dec(nextIndex);
jaroslav@1890
   798
                }
jaroslav@1890
   799
            } finally {
jaroslav@1890
   800
                lock.unlock();
jaroslav@1890
   801
            }
jaroslav@1890
   802
        }
jaroslav@1890
   803
    }
jaroslav@1890
   804
jaroslav@1890
   805
}