# HG changeset patch # User Jaroslav Tulach # Date 1458380909 -3600 # Node ID c8af252ea9ebcd9eca7ca8adbec9c36dc426c12e # Parent e1953d8b83387bd8c9bd5a3d4d1dba72652fd55c# Parent 212417b74b72c7c783fa0636307de3ef404b0552 Merging in JDK's concurrent interfaces diff -r e1953d8b8338 -r c8af252ea9eb rt/emul/compact/src/main/java/java/util/concurrent/AbstractExecutorService.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/AbstractExecutorService.java Sat Mar 19 10:48:29 2016 +0100 @@ -0,0 +1,309 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +package java.util.concurrent; +import java.util.*; + +/** + * Provides default implementations of {@link ExecutorService} + * execution methods. This class implements the submit, + * invokeAny and invokeAll methods using a + * {@link RunnableFuture} returned by newTaskFor, which defaults + * to the {@link FutureTask} class provided in this package. For example, + * the implementation of submit(Runnable) creates an + * associated RunnableFuture that is executed and + * returned. Subclasses may override the newTaskFor methods + * to return RunnableFuture implementations other than + * FutureTask. + * + *

Extension example. Here is a sketch of a class + * that customizes {@link ThreadPoolExecutor} to use + * a CustomTask class instead of the default FutureTask: + *

 {@code
+ * public class CustomThreadPoolExecutor extends ThreadPoolExecutor {
+ *
+ *   static class CustomTask implements RunnableFuture {...}
+ *
+ *   protected  RunnableFuture newTaskFor(Callable c) {
+ *       return new CustomTask(c);
+ *   }
+ *   protected  RunnableFuture newTaskFor(Runnable r, V v) {
+ *       return new CustomTask(r, v);
+ *   }
+ *   // ... add constructors, etc.
+ * }}
+ * + * @since 1.5 + * @author Doug Lea + */ +public abstract class AbstractExecutorService implements ExecutorService { + + /** + * Returns a RunnableFuture for the given runnable and default + * value. + * + * @param runnable the runnable task being wrapped + * @param value the default value for the returned future + * @return a RunnableFuture which when run will run the + * underlying runnable and which, as a Future, will yield + * the given value as its result and provide for cancellation of + * the underlying task. + * @since 1.6 + */ + protected RunnableFuture newTaskFor(Runnable runnable, T value) { + return new FutureTask(runnable, value); + } + + /** + * Returns a RunnableFuture for the given callable task. + * + * @param callable the callable task being wrapped + * @return a RunnableFuture which when run will call the + * underlying callable and which, as a Future, will yield + * the callable's result as its result and provide for + * cancellation of the underlying task. + * @since 1.6 + */ + protected RunnableFuture newTaskFor(Callable callable) { + return new FutureTask(callable); + } + + /** + * @throws RejectedExecutionException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + */ + public Future submit(Runnable task) { + if (task == null) throw new NullPointerException(); + RunnableFuture ftask = newTaskFor(task, null); + execute(ftask); + return ftask; + } + + /** + * @throws RejectedExecutionException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + */ + public Future submit(Runnable task, T result) { + if (task == null) throw new NullPointerException(); + RunnableFuture ftask = newTaskFor(task, result); + execute(ftask); + return ftask; + } + + /** + * @throws RejectedExecutionException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + */ + public Future submit(Callable task) { + if (task == null) throw new NullPointerException(); + RunnableFuture ftask = newTaskFor(task); + execute(ftask); + return ftask; + } + + /** + * the main mechanics of invokeAny. + */ + private T doInvokeAny(Collection> tasks, + boolean timed, long nanos) + throws InterruptedException, ExecutionException, TimeoutException { + if (tasks == null) + throw new NullPointerException(); + int ntasks = tasks.size(); + if (ntasks == 0) + throw new IllegalArgumentException(); + List> futures= new ArrayList>(ntasks); + ExecutorCompletionService ecs = + new ExecutorCompletionService(this); + + // For efficiency, especially in executors with limited + // parallelism, check to see if previously submitted tasks are + // done before submitting more of them. This interleaving + // plus the exception mechanics account for messiness of main + // loop. + + try { + // Record exceptions so that if we fail to obtain any + // result, we can throw the last exception we got. + ExecutionException ee = null; + long lastTime = timed ? System.nanoTime() : 0; + Iterator> it = tasks.iterator(); + + // Start one task for sure; the rest incrementally + futures.add(ecs.submit(it.next())); + --ntasks; + int active = 1; + + for (;;) { + Future f = ecs.poll(); + if (f == null) { + if (ntasks > 0) { + --ntasks; + futures.add(ecs.submit(it.next())); + ++active; + } + else if (active == 0) + break; + else if (timed) { + f = ecs.poll(nanos, TimeUnit.NANOSECONDS); + if (f == null) + throw new TimeoutException(); + long now = System.nanoTime(); + nanos -= now - lastTime; + lastTime = now; + } + else + f = ecs.take(); + } + if (f != null) { + --active; + try { + return f.get(); + } catch (ExecutionException eex) { + ee = eex; + } catch (RuntimeException rex) { + ee = new ExecutionException(rex); + } + } + } + + if (ee == null) + ee = new ExecutionException(); + throw ee; + + } finally { + for (Future f : futures) + f.cancel(true); + } + } + + public T invokeAny(Collection> tasks) + throws InterruptedException, ExecutionException { + try { + return doInvokeAny(tasks, false, 0); + } catch (TimeoutException cannotHappen) { + assert false; + return null; + } + } + + public T invokeAny(Collection> tasks, + long timeout, TimeUnit unit) + throws InterruptedException, ExecutionException, TimeoutException { + return doInvokeAny(tasks, true, unit.toNanos(timeout)); + } + + public List> invokeAll(Collection> tasks) + throws InterruptedException { + if (tasks == null) + throw new NullPointerException(); + List> futures = new ArrayList>(tasks.size()); + boolean done = false; + try { + for (Callable t : tasks) { + RunnableFuture f = newTaskFor(t); + futures.add(f); + execute(f); + } + for (Future f : futures) { + if (!f.isDone()) { + try { + f.get(); + } catch (CancellationException ignore) { + } catch (ExecutionException ignore) { + } + } + } + done = true; + return futures; + } finally { + if (!done) + for (Future f : futures) + f.cancel(true); + } + } + + public List> invokeAll(Collection> tasks, + long timeout, TimeUnit unit) + throws InterruptedException { + if (tasks == null || unit == null) + throw new NullPointerException(); + long nanos = unit.toNanos(timeout); + List> futures = new ArrayList>(tasks.size()); + boolean done = false; + try { + for (Callable t : tasks) + futures.add(newTaskFor(t)); + + long lastTime = System.nanoTime(); + + // Interleave time checks and calls to execute in case + // executor doesn't have any/much parallelism. + Iterator> it = futures.iterator(); + while (it.hasNext()) { + execute((Runnable)(it.next())); + long now = System.nanoTime(); + nanos -= now - lastTime; + lastTime = now; + if (nanos <= 0) + return futures; + } + + for (Future f : futures) { + if (!f.isDone()) { + if (nanos <= 0) + return futures; + try { + f.get(nanos, TimeUnit.NANOSECONDS); + } catch (CancellationException ignore) { + } catch (ExecutionException ignore) { + } catch (TimeoutException toe) { + return futures; + } + long now = System.nanoTime(); + nanos -= now - lastTime; + lastTime = now; + } + } + done = true; + return futures; + } finally { + if (!done) + for (Future f : futures) + f.cancel(true); + } + } + +} diff -r e1953d8b8338 -r c8af252ea9eb rt/emul/compact/src/main/java/java/util/concurrent/ArrayBlockingQueue.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/ArrayBlockingQueue.java Sat Mar 19 10:48:29 2016 +0100 @@ -0,0 +1,805 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +package java.util.concurrent; +import java.util.concurrent.locks.*; +import java.util.*; + +/** + * A bounded {@linkplain BlockingQueue blocking queue} backed by an + * array. This queue orders elements FIFO (first-in-first-out). The + * head of the queue is that element that has been on the + * queue the longest time. The tail of the queue is that + * element that has been on the queue the shortest time. New elements + * are inserted at the tail of the queue, and the queue retrieval + * operations obtain elements at the head of the queue. + * + *

This is a classic "bounded buffer", in which a + * fixed-sized array holds elements inserted by producers and + * extracted by consumers. Once created, the capacity cannot be + * changed. Attempts to {@code put} an element into a full queue + * will result in the operation blocking; attempts to {@code take} an + * element from an empty queue will similarly block. + * + *

This class supports an optional fairness policy for ordering + * waiting producer and consumer threads. By default, this ordering + * is not guaranteed. However, a queue constructed with fairness set + * to {@code true} grants threads access in FIFO order. Fairness + * generally decreases throughput but reduces variability and avoids + * starvation. + * + *

This class and its iterator implement all of the + * optional methods of the {@link Collection} and {@link + * Iterator} interfaces. + * + *

This class is a member of the + * + * Java Collections Framework. + * + * @since 1.5 + * @author Doug Lea + * @param the type of elements held in this collection + */ +public class ArrayBlockingQueue extends AbstractQueue + implements BlockingQueue, java.io.Serializable { + + /** + * Serialization ID. This class relies on default serialization + * even for the items array, which is default-serialized, even if + * it is empty. Otherwise it could not be declared final, which is + * necessary here. + */ + private static final long serialVersionUID = -817911632652898426L; + + /** The queued items */ + final Object[] items; + + /** items index for next take, poll, peek or remove */ + int takeIndex; + + /** items index for next put, offer, or add */ + int putIndex; + + /** Number of elements in the queue */ + int count; + + /* + * Concurrency control uses the classic two-condition algorithm + * found in any textbook. + */ + + /** Main lock guarding all access */ + final ReentrantLock lock; + /** Condition for waiting takes */ + private final Condition notEmpty; + /** Condition for waiting puts */ + private final Condition notFull; + + // Internal helper methods + + /** + * Circularly increment i. + */ + final int inc(int i) { + return (++i == items.length) ? 0 : i; + } + + /** + * Circularly decrement i. + */ + final int dec(int i) { + return ((i == 0) ? items.length : i) - 1; + } + + @SuppressWarnings("unchecked") + static E cast(Object item) { + return (E) item; + } + + /** + * Returns item at index i. + */ + final E itemAt(int i) { + return this.cast(items[i]); + } + + /** + * Throws NullPointerException if argument is null. + * + * @param v the element + */ + private static void checkNotNull(Object v) { + if (v == null) + throw new NullPointerException(); + } + + /** + * Inserts element at current put position, advances, and signals. + * Call only when holding lock. + */ + private void insert(E x) { + items[putIndex] = x; + putIndex = inc(putIndex); + ++count; + notEmpty.signal(); + } + + /** + * Extracts element at current take position, advances, and signals. + * Call only when holding lock. + */ + private E extract() { + final Object[] items = this.items; + E x = this.cast(items[takeIndex]); + items[takeIndex] = null; + takeIndex = inc(takeIndex); + --count; + notFull.signal(); + return x; + } + + /** + * Deletes item at position i. + * Utility for remove and iterator.remove. + * Call only when holding lock. + */ + void removeAt(int i) { + final Object[] items = this.items; + // if removing front item, just advance + if (i == takeIndex) { + items[takeIndex] = null; + takeIndex = inc(takeIndex); + } else { + // slide over all others up through putIndex. + for (;;) { + int nexti = inc(i); + if (nexti != putIndex) { + items[i] = items[nexti]; + i = nexti; + } else { + items[i] = null; + putIndex = i; + break; + } + } + } + --count; + notFull.signal(); + } + + /** + * Creates an {@code ArrayBlockingQueue} with the given (fixed) + * capacity and default access policy. + * + * @param capacity the capacity of this queue + * @throws IllegalArgumentException if {@code capacity < 1} + */ + public ArrayBlockingQueue(int capacity) { + this(capacity, false); + } + + /** + * Creates an {@code ArrayBlockingQueue} with the given (fixed) + * capacity and the specified access policy. + * + * @param capacity the capacity of this queue + * @param fair if {@code true} then queue accesses for threads blocked + * on insertion or removal, are processed in FIFO order; + * if {@code false} the access order is unspecified. + * @throws IllegalArgumentException if {@code capacity < 1} + */ + public ArrayBlockingQueue(int capacity, boolean fair) { + if (capacity <= 0) + throw new IllegalArgumentException(); + this.items = new Object[capacity]; + lock = new ReentrantLock(fair); + notEmpty = lock.newCondition(); + notFull = lock.newCondition(); + } + + /** + * Creates an {@code ArrayBlockingQueue} with the given (fixed) + * capacity, the specified access policy and initially containing the + * elements of the given collection, + * added in traversal order of the collection's iterator. + * + * @param capacity the capacity of this queue + * @param fair if {@code true} then queue accesses for threads blocked + * on insertion or removal, are processed in FIFO order; + * if {@code false} the access order is unspecified. + * @param c the collection of elements to initially contain + * @throws IllegalArgumentException if {@code capacity} is less than + * {@code c.size()}, or less than 1. + * @throws NullPointerException if the specified collection or any + * of its elements are null + */ + public ArrayBlockingQueue(int capacity, boolean fair, + Collection c) { + this(capacity, fair); + + final ReentrantLock lock = this.lock; + lock.lock(); // Lock only for visibility, not mutual exclusion + try { + int i = 0; + try { + for (E e : c) { + checkNotNull(e); + items[i++] = e; + } + } catch (ArrayIndexOutOfBoundsException ex) { + throw new IllegalArgumentException(); + } + count = i; + putIndex = (i == capacity) ? 0 : i; + } finally { + lock.unlock(); + } + } + + /** + * Inserts the specified element at the tail of this queue if it is + * possible to do so immediately without exceeding the queue's capacity, + * returning {@code true} upon success and throwing an + * {@code IllegalStateException} if this queue is full. + * + * @param e the element to add + * @return {@code true} (as specified by {@link Collection#add}) + * @throws IllegalStateException if this queue is full + * @throws NullPointerException if the specified element is null + */ + public boolean add(E e) { + return super.add(e); + } + + /** + * Inserts the specified element at the tail of this queue if it is + * possible to do so immediately without exceeding the queue's capacity, + * returning {@code true} upon success and {@code false} if this queue + * is full. This method is generally preferable to method {@link #add}, + * which can fail to insert an element only by throwing an exception. + * + * @throws NullPointerException if the specified element is null + */ + public boolean offer(E e) { + checkNotNull(e); + final ReentrantLock lock = this.lock; + lock.lock(); + try { + if (count == items.length) + return false; + else { + insert(e); + return true; + } + } finally { + lock.unlock(); + } + } + + /** + * Inserts the specified element at the tail of this queue, waiting + * for space to become available if the queue is full. + * + * @throws InterruptedException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + */ + public void put(E e) throws InterruptedException { + checkNotNull(e); + final ReentrantLock lock = this.lock; + lock.lockInterruptibly(); + try { + while (count == items.length) + notFull.await(); + insert(e); + } finally { + lock.unlock(); + } + } + + /** + * Inserts the specified element at the tail of this queue, waiting + * up to the specified wait time for space to become available if + * the queue is full. + * + * @throws InterruptedException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + */ + public boolean offer(E e, long timeout, TimeUnit unit) + throws InterruptedException { + + checkNotNull(e); + long nanos = unit.toNanos(timeout); + final ReentrantLock lock = this.lock; + lock.lockInterruptibly(); + try { + while (count == items.length) { + if (nanos <= 0) + return false; + nanos = notFull.awaitNanos(nanos); + } + insert(e); + return true; + } finally { + lock.unlock(); + } + } + + public E poll() { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + return (count == 0) ? null : extract(); + } finally { + lock.unlock(); + } + } + + public E take() throws InterruptedException { + final ReentrantLock lock = this.lock; + lock.lockInterruptibly(); + try { + while (count == 0) + notEmpty.await(); + return extract(); + } finally { + lock.unlock(); + } + } + + public E poll(long timeout, TimeUnit unit) throws InterruptedException { + long nanos = unit.toNanos(timeout); + final ReentrantLock lock = this.lock; + lock.lockInterruptibly(); + try { + while (count == 0) { + if (nanos <= 0) + return null; + nanos = notEmpty.awaitNanos(nanos); + } + return extract(); + } finally { + lock.unlock(); + } + } + + public E peek() { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + return (count == 0) ? null : itemAt(takeIndex); + } finally { + lock.unlock(); + } + } + + // this doc comment is overridden to remove the reference to collections + // greater in size than Integer.MAX_VALUE + /** + * Returns the number of elements in this queue. + * + * @return the number of elements in this queue + */ + public int size() { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + return count; + } finally { + lock.unlock(); + } + } + + // this doc comment is a modified copy of the inherited doc comment, + // without the reference to unlimited queues. + /** + * Returns the number of additional elements that this queue can ideally + * (in the absence of memory or resource constraints) accept without + * blocking. This is always equal to the initial capacity of this queue + * less the current {@code size} of this queue. + * + *

Note that you cannot always tell if an attempt to insert + * an element will succeed by inspecting {@code remainingCapacity} + * because it may be the case that another thread is about to + * insert or remove an element. + */ + public int remainingCapacity() { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + return items.length - count; + } finally { + lock.unlock(); + } + } + + /** + * Removes a single instance of the specified element from this queue, + * if it is present. More formally, removes an element {@code e} such + * that {@code o.equals(e)}, if this queue contains one or more such + * elements. + * Returns {@code true} if this queue contained the specified element + * (or equivalently, if this queue changed as a result of the call). + * + *

Removal of interior elements in circular array based queues + * is an intrinsically slow and disruptive operation, so should + * be undertaken only in exceptional circumstances, ideally + * only when the queue is known not to be accessible by other + * threads. + * + * @param o element to be removed from this queue, if present + * @return {@code true} if this queue changed as a result of the call + */ + public boolean remove(Object o) { + if (o == null) return false; + final Object[] items = this.items; + final ReentrantLock lock = this.lock; + lock.lock(); + try { + for (int i = takeIndex, k = count; k > 0; i = inc(i), k--) { + if (o.equals(items[i])) { + removeAt(i); + return true; + } + } + return false; + } finally { + lock.unlock(); + } + } + + /** + * Returns {@code true} if this queue contains the specified element. + * More formally, returns {@code true} if and only if this queue contains + * at least one element {@code e} such that {@code o.equals(e)}. + * + * @param o object to be checked for containment in this queue + * @return {@code true} if this queue contains the specified element + */ + public boolean contains(Object o) { + if (o == null) return false; + final Object[] items = this.items; + final ReentrantLock lock = this.lock; + lock.lock(); + try { + for (int i = takeIndex, k = count; k > 0; i = inc(i), k--) + if (o.equals(items[i])) + return true; + return false; + } finally { + lock.unlock(); + } + } + + /** + * Returns an array containing all of the elements in this queue, in + * proper sequence. + * + *

The returned array will be "safe" in that no references to it are + * maintained by this queue. (In other words, this method must allocate + * a new array). The caller is thus free to modify the returned array. + * + *

This method acts as bridge between array-based and collection-based + * APIs. + * + * @return an array containing all of the elements in this queue + */ + public Object[] toArray() { + final Object[] items = this.items; + final ReentrantLock lock = this.lock; + lock.lock(); + try { + final int count = this.count; + Object[] a = new Object[count]; + for (int i = takeIndex, k = 0; k < count; i = inc(i), k++) + a[k] = items[i]; + return a; + } finally { + lock.unlock(); + } + } + + /** + * Returns an array containing all of the elements in this queue, in + * proper sequence; the runtime type of the returned array is that of + * the specified array. If the queue fits in the specified array, it + * is returned therein. Otherwise, a new array is allocated with the + * runtime type of the specified array and the size of this queue. + * + *

If this queue fits in the specified array with room to spare + * (i.e., the array has more elements than this queue), the element in + * the array immediately following the end of the queue is set to + * {@code null}. + * + *

Like the {@link #toArray()} method, this method acts as bridge between + * array-based and collection-based APIs. Further, this method allows + * precise control over the runtime type of the output array, and may, + * under certain circumstances, be used to save allocation costs. + * + *

Suppose {@code x} is a queue known to contain only strings. + * The following code can be used to dump the queue into a newly + * allocated array of {@code String}: + * + *

+     *     String[] y = x.toArray(new String[0]);
+ * + * Note that {@code toArray(new Object[0])} is identical in function to + * {@code toArray()}. + * + * @param a the array into which the elements of the queue are to + * be stored, if it is big enough; otherwise, a new array of the + * same runtime type is allocated for this purpose + * @return an array containing all of the elements in this queue + * @throws ArrayStoreException if the runtime type of the specified array + * is not a supertype of the runtime type of every element in + * this queue + * @throws NullPointerException if the specified array is null + */ + @SuppressWarnings("unchecked") + public T[] toArray(T[] a) { + final Object[] items = this.items; + final ReentrantLock lock = this.lock; + lock.lock(); + try { + final int count = this.count; + final int len = a.length; + if (len < count) + a = (T[])java.lang.reflect.Array.newInstance( + a.getClass().getComponentType(), count); + for (int i = takeIndex, k = 0; k < count; i = inc(i), k++) + a[k] = (T) items[i]; + if (len > count) + a[count] = null; + return a; + } finally { + lock.unlock(); + } + } + + public String toString() { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + int k = count; + if (k == 0) + return "[]"; + + StringBuilder sb = new StringBuilder(); + sb.append('['); + for (int i = takeIndex; ; i = inc(i)) { + Object e = items[i]; + sb.append(e == this ? "(this Collection)" : e); + if (--k == 0) + return sb.append(']').toString(); + sb.append(',').append(' '); + } + } finally { + lock.unlock(); + } + } + + /** + * Atomically removes all of the elements from this queue. + * The queue will be empty after this call returns. + */ + public void clear() { + final Object[] items = this.items; + final ReentrantLock lock = this.lock; + lock.lock(); + try { + for (int i = takeIndex, k = count; k > 0; i = inc(i), k--) + items[i] = null; + count = 0; + putIndex = 0; + takeIndex = 0; + notFull.signalAll(); + } finally { + lock.unlock(); + } + } + + /** + * @throws UnsupportedOperationException {@inheritDoc} + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + * @throws IllegalArgumentException {@inheritDoc} + */ + public int drainTo(Collection c) { + checkNotNull(c); + if (c == this) + throw new IllegalArgumentException(); + final Object[] items = this.items; + final ReentrantLock lock = this.lock; + lock.lock(); + try { + int i = takeIndex; + int n = 0; + int max = count; + while (n < max) { + c.add(this.cast(items[i])); + items[i] = null; + i = inc(i); + ++n; + } + if (n > 0) { + count = 0; + putIndex = 0; + takeIndex = 0; + notFull.signalAll(); + } + return n; + } finally { + lock.unlock(); + } + } + + /** + * @throws UnsupportedOperationException {@inheritDoc} + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + * @throws IllegalArgumentException {@inheritDoc} + */ + public int drainTo(Collection c, int maxElements) { + checkNotNull(c); + if (c == this) + throw new IllegalArgumentException(); + if (maxElements <= 0) + return 0; + final Object[] items = this.items; + final ReentrantLock lock = this.lock; + lock.lock(); + try { + int i = takeIndex; + int n = 0; + int max = (maxElements < count) ? maxElements : count; + while (n < max) { + c.add(this.cast(items[i])); + items[i] = null; + i = inc(i); + ++n; + } + if (n > 0) { + count -= n; + takeIndex = i; + notFull.signalAll(); + } + return n; + } finally { + lock.unlock(); + } + } + + /** + * Returns an iterator over the elements in this queue in proper sequence. + * The elements will be returned in order from first (head) to last (tail). + * + *

The returned {@code Iterator} is a "weakly consistent" iterator that + * will never throw {@link java.util.ConcurrentModificationException + * ConcurrentModificationException}, + * and guarantees to traverse elements as they existed upon + * construction of the iterator, and may (but is not guaranteed to) + * reflect any modifications subsequent to construction. + * + * @return an iterator over the elements in this queue in proper sequence + */ + public Iterator iterator() { + return new Itr(); + } + + /** + * Iterator for ArrayBlockingQueue. To maintain weak consistency + * with respect to puts and takes, we (1) read ahead one slot, so + * as to not report hasNext true but then not have an element to + * return -- however we later recheck this slot to use the most + * current value; (2) ensure that each array slot is traversed at + * most once (by tracking "remaining" elements); (3) skip over + * null slots, which can occur if takes race ahead of iterators. + * However, for circular array-based queues, we cannot rely on any + * well established definition of what it means to be weakly + * consistent with respect to interior removes since these may + * require slot overwrites in the process of sliding elements to + * cover gaps. So we settle for resiliency, operating on + * established apparent nexts, which may miss some elements that + * have moved between calls to next. + */ + private class Itr implements Iterator { + private int remaining; // Number of elements yet to be returned + private int nextIndex; // Index of element to be returned by next + private E nextItem; // Element to be returned by next call to next + private E lastItem; // Element returned by last call to next + private int lastRet; // Index of last element returned, or -1 if none + + Itr() { + final ReentrantLock lock = ArrayBlockingQueue.this.lock; + lock.lock(); + try { + lastRet = -1; + if ((remaining = count) > 0) + nextItem = itemAt(nextIndex = takeIndex); + } finally { + lock.unlock(); + } + } + + public boolean hasNext() { + return remaining > 0; + } + + public E next() { + final ReentrantLock lock = ArrayBlockingQueue.this.lock; + lock.lock(); + try { + if (remaining <= 0) + throw new NoSuchElementException(); + lastRet = nextIndex; + E x = itemAt(nextIndex); // check for fresher value + if (x == null) { + x = nextItem; // we are forced to report old value + lastItem = null; // but ensure remove fails + } + else + lastItem = x; + while (--remaining > 0 && // skip over nulls + (nextItem = itemAt(nextIndex = inc(nextIndex))) == null) + ; + return x; + } finally { + lock.unlock(); + } + } + + public void remove() { + final ReentrantLock lock = ArrayBlockingQueue.this.lock; + lock.lock(); + try { + int i = lastRet; + if (i == -1) + throw new IllegalStateException(); + lastRet = -1; + E x = lastItem; + lastItem = null; + // only remove if item still at index + if (x != null && x == items[i]) { + boolean removingHead = (i == takeIndex); + removeAt(i); + if (!removingHead) + nextIndex = dec(nextIndex); + } + } finally { + lock.unlock(); + } + } + } + +} diff -r e1953d8b8338 -r c8af252ea9eb rt/emul/compact/src/main/java/java/util/concurrent/BlockingDeque.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/BlockingDeque.java Sat Mar 19 10:48:29 2016 +0100 @@ -0,0 +1,650 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +package java.util.concurrent; +import java.util.*; + +/** + * A {@link Deque} that additionally supports blocking operations that wait + * for the deque to become non-empty when retrieving an element, and wait for + * space to become available in the deque when storing an element. + * + *

BlockingDeque methods come in four forms, with different ways + * of handling operations that cannot be satisfied immediately, but may be + * satisfied at some point in the future: + * one throws an exception, the second returns a special value (either + * null or false, depending on the operation), the third + * blocks the current thread indefinitely until the operation can succeed, + * and the fourth blocks for only a given maximum time limit before giving + * up. These methods are summarized in the following table: + * + *

+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
First Element (Head)
Throws exceptionSpecial valueBlocksTimes out
Insert{@link #addFirst addFirst(e)}{@link #offerFirst(Object) offerFirst(e)}{@link #putFirst putFirst(e)}{@link #offerFirst(Object, long, TimeUnit) offerFirst(e, time, unit)}
Remove{@link #removeFirst removeFirst()}{@link #pollFirst pollFirst()}{@link #takeFirst takeFirst()}{@link #pollFirst(long, TimeUnit) pollFirst(time, unit)}
Examine{@link #getFirst getFirst()}{@link #peekFirst peekFirst()}not applicablenot applicable
Last Element (Tail)
Throws exceptionSpecial valueBlocksTimes out
Insert{@link #addLast addLast(e)}{@link #offerLast(Object) offerLast(e)}{@link #putLast putLast(e)}{@link #offerLast(Object, long, TimeUnit) offerLast(e, time, unit)}
Remove{@link #removeLast() removeLast()}{@link #pollLast() pollLast()}{@link #takeLast takeLast()}{@link #pollLast(long, TimeUnit) pollLast(time, unit)}
Examine{@link #getLast getLast()}{@link #peekLast peekLast()}not applicablenot applicable
+ * + *

Like any {@link BlockingQueue}, a BlockingDeque is thread safe, + * does not permit null elements, and may (or may not) be + * capacity-constrained. + * + *

A BlockingDeque implementation may be used directly as a FIFO + * BlockingQueue. The methods inherited from the + * BlockingQueue interface are precisely equivalent to + * BlockingDeque methods as indicated in the following table: + * + *

+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
BlockingQueue Method Equivalent BlockingDeque Method
Insert
{@link #add(Object) add(e)}{@link #addLast(Object) addLast(e)}
{@link #offer(Object) offer(e)}{@link #offerLast(Object) offerLast(e)}
{@link #put(Object) put(e)}{@link #putLast(Object) putLast(e)}
{@link #offer(Object, long, TimeUnit) offer(e, time, unit)}{@link #offerLast(Object, long, TimeUnit) offerLast(e, time, unit)}
Remove
{@link #remove() remove()}{@link #removeFirst() removeFirst()}
{@link #poll() poll()}{@link #pollFirst() pollFirst()}
{@link #take() take()}{@link #takeFirst() takeFirst()}
{@link #poll(long, TimeUnit) poll(time, unit)}{@link #pollFirst(long, TimeUnit) pollFirst(time, unit)}
Examine
{@link #element() element()}{@link #getFirst() getFirst()}
{@link #peek() peek()}{@link #peekFirst() peekFirst()}
+ * + *

Memory consistency effects: As with other concurrent + * collections, actions in a thread prior to placing an object into a + * {@code BlockingDeque} + * happen-before + * actions subsequent to the access or removal of that element from + * the {@code BlockingDeque} in another thread. + * + *

This interface is a member of the + * + * Java Collections Framework. + * + * @since 1.6 + * @author Doug Lea + * @param the type of elements held in this collection + */ +public interface BlockingDeque extends BlockingQueue, Deque { + /* + * We have "diamond" multiple interface inheritance here, and that + * introduces ambiguities. Methods might end up with different + * specs depending on the branch chosen by javadoc. Thus a lot of + * methods specs here are copied from superinterfaces. + */ + + /** + * Inserts the specified element at the front of this deque if it is + * possible to do so immediately without violating capacity restrictions, + * throwing an IllegalStateException if no space is currently + * available. When using a capacity-restricted deque, it is generally + * preferable to use {@link #offerFirst(Object) offerFirst}. + * + * @param e the element to add + * @throws IllegalStateException {@inheritDoc} + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if the specified element is null + * @throws IllegalArgumentException {@inheritDoc} + */ + void addFirst(E e); + + /** + * Inserts the specified element at the end of this deque if it is + * possible to do so immediately without violating capacity restrictions, + * throwing an IllegalStateException if no space is currently + * available. When using a capacity-restricted deque, it is generally + * preferable to use {@link #offerLast(Object) offerLast}. + * + * @param e the element to add + * @throws IllegalStateException {@inheritDoc} + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if the specified element is null + * @throws IllegalArgumentException {@inheritDoc} + */ + void addLast(E e); + + /** + * Inserts the specified element at the front of this deque if it is + * possible to do so immediately without violating capacity restrictions, + * returning true upon success and false if no space is + * currently available. + * When using a capacity-restricted deque, this method is generally + * preferable to the {@link #addFirst(Object) addFirst} method, which can + * fail to insert an element only by throwing an exception. + * + * @param e the element to add + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if the specified element is null + * @throws IllegalArgumentException {@inheritDoc} + */ + boolean offerFirst(E e); + + /** + * Inserts the specified element at the end of this deque if it is + * possible to do so immediately without violating capacity restrictions, + * returning true upon success and false if no space is + * currently available. + * When using a capacity-restricted deque, this method is generally + * preferable to the {@link #addLast(Object) addLast} method, which can + * fail to insert an element only by throwing an exception. + * + * @param e the element to add + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if the specified element is null + * @throws IllegalArgumentException {@inheritDoc} + */ + boolean offerLast(E e); + + /** + * Inserts the specified element at the front of this deque, + * waiting if necessary for space to become available. + * + * @param e the element to add + * @throws InterruptedException if interrupted while waiting + * @throws ClassCastException if the class of the specified element + * prevents it from being added to this deque + * @throws NullPointerException if the specified element is null + * @throws IllegalArgumentException if some property of the specified + * element prevents it from being added to this deque + */ + void putFirst(E e) throws InterruptedException; + + /** + * Inserts the specified element at the end of this deque, + * waiting if necessary for space to become available. + * + * @param e the element to add + * @throws InterruptedException if interrupted while waiting + * @throws ClassCastException if the class of the specified element + * prevents it from being added to this deque + * @throws NullPointerException if the specified element is null + * @throws IllegalArgumentException if some property of the specified + * element prevents it from being added to this deque + */ + void putLast(E e) throws InterruptedException; + + /** + * Inserts the specified element at the front of this deque, + * waiting up to the specified wait time if necessary for space to + * become available. + * + * @param e the element to add + * @param timeout how long to wait before giving up, in units of + * unit + * @param unit a TimeUnit determining how to interpret the + * timeout parameter + * @return true if successful, or false if + * the specified waiting time elapses before space is available + * @throws InterruptedException if interrupted while waiting + * @throws ClassCastException if the class of the specified element + * prevents it from being added to this deque + * @throws NullPointerException if the specified element is null + * @throws IllegalArgumentException if some property of the specified + * element prevents it from being added to this deque + */ + boolean offerFirst(E e, long timeout, TimeUnit unit) + throws InterruptedException; + + /** + * Inserts the specified element at the end of this deque, + * waiting up to the specified wait time if necessary for space to + * become available. + * + * @param e the element to add + * @param timeout how long to wait before giving up, in units of + * unit + * @param unit a TimeUnit determining how to interpret the + * timeout parameter + * @return true if successful, or false if + * the specified waiting time elapses before space is available + * @throws InterruptedException if interrupted while waiting + * @throws ClassCastException if the class of the specified element + * prevents it from being added to this deque + * @throws NullPointerException if the specified element is null + * @throws IllegalArgumentException if some property of the specified + * element prevents it from being added to this deque + */ + boolean offerLast(E e, long timeout, TimeUnit unit) + throws InterruptedException; + + /** + * Retrieves and removes the first element of this deque, waiting + * if necessary until an element becomes available. + * + * @return the head of this deque + * @throws InterruptedException if interrupted while waiting + */ + E takeFirst() throws InterruptedException; + + /** + * Retrieves and removes the last element of this deque, waiting + * if necessary until an element becomes available. + * + * @return the tail of this deque + * @throws InterruptedException if interrupted while waiting + */ + E takeLast() throws InterruptedException; + + /** + * Retrieves and removes the first element of this deque, waiting + * up to the specified wait time if necessary for an element to + * become available. + * + * @param timeout how long to wait before giving up, in units of + * unit + * @param unit a TimeUnit determining how to interpret the + * timeout parameter + * @return the head of this deque, or null if the specified + * waiting time elapses before an element is available + * @throws InterruptedException if interrupted while waiting + */ + E pollFirst(long timeout, TimeUnit unit) + throws InterruptedException; + + /** + * Retrieves and removes the last element of this deque, waiting + * up to the specified wait time if necessary for an element to + * become available. + * + * @param timeout how long to wait before giving up, in units of + * unit + * @param unit a TimeUnit determining how to interpret the + * timeout parameter + * @return the tail of this deque, or null if the specified + * waiting time elapses before an element is available + * @throws InterruptedException if interrupted while waiting + */ + E pollLast(long timeout, TimeUnit unit) + throws InterruptedException; + + /** + * Removes the first occurrence of the specified element from this deque. + * If the deque does not contain the element, it is unchanged. + * More formally, removes the first element e such that + * o.equals(e) (if such an element exists). + * Returns true if this deque contained the specified element + * (or equivalently, if this deque changed as a result of the call). + * + * @param o element to be removed from this deque, if present + * @return true if an element was removed as a result of this call + * @throws ClassCastException if the class of the specified element + * is incompatible with this deque + * (optional) + * @throws NullPointerException if the specified element is null + * (optional) + */ + boolean removeFirstOccurrence(Object o); + + /** + * Removes the last occurrence of the specified element from this deque. + * If the deque does not contain the element, it is unchanged. + * More formally, removes the last element e such that + * o.equals(e) (if such an element exists). + * Returns true if this deque contained the specified element + * (or equivalently, if this deque changed as a result of the call). + * + * @param o element to be removed from this deque, if present + * @return true if an element was removed as a result of this call + * @throws ClassCastException if the class of the specified element + * is incompatible with this deque + * (optional) + * @throws NullPointerException if the specified element is null + * (optional) + */ + boolean removeLastOccurrence(Object o); + + // *** BlockingQueue methods *** + + /** + * Inserts the specified element into the queue represented by this deque + * (in other words, at the tail of this deque) if it is possible to do so + * immediately without violating capacity restrictions, returning + * true upon success and throwing an + * IllegalStateException if no space is currently available. + * When using a capacity-restricted deque, it is generally preferable to + * use {@link #offer(Object) offer}. + * + *

This method is equivalent to {@link #addLast(Object) addLast}. + * + * @param e the element to add + * @throws IllegalStateException {@inheritDoc} + * @throws ClassCastException if the class of the specified element + * prevents it from being added to this deque + * @throws NullPointerException if the specified element is null + * @throws IllegalArgumentException if some property of the specified + * element prevents it from being added to this deque + */ + boolean add(E e); + + /** + * Inserts the specified element into the queue represented by this deque + * (in other words, at the tail of this deque) if it is possible to do so + * immediately without violating capacity restrictions, returning + * true upon success and false if no space is currently + * available. When using a capacity-restricted deque, this method is + * generally preferable to the {@link #add} method, which can fail to + * insert an element only by throwing an exception. + * + *

This method is equivalent to {@link #offerLast(Object) offerLast}. + * + * @param e the element to add + * @throws ClassCastException if the class of the specified element + * prevents it from being added to this deque + * @throws NullPointerException if the specified element is null + * @throws IllegalArgumentException if some property of the specified + * element prevents it from being added to this deque + */ + boolean offer(E e); + + /** + * Inserts the specified element into the queue represented by this deque + * (in other words, at the tail of this deque), waiting if necessary for + * space to become available. + * + *

This method is equivalent to {@link #putLast(Object) putLast}. + * + * @param e the element to add + * @throws InterruptedException {@inheritDoc} + * @throws ClassCastException if the class of the specified element + * prevents it from being added to this deque + * @throws NullPointerException if the specified element is null + * @throws IllegalArgumentException if some property of the specified + * element prevents it from being added to this deque + */ + void put(E e) throws InterruptedException; + + /** + * Inserts the specified element into the queue represented by this deque + * (in other words, at the tail of this deque), waiting up to the + * specified wait time if necessary for space to become available. + * + *

This method is equivalent to + * {@link #offerLast(Object,long,TimeUnit) offerLast}. + * + * @param e the element to add + * @return true if the element was added to this deque, else + * false + * @throws InterruptedException {@inheritDoc} + * @throws ClassCastException if the class of the specified element + * prevents it from being added to this deque + * @throws NullPointerException if the specified element is null + * @throws IllegalArgumentException if some property of the specified + * element prevents it from being added to this deque + */ + boolean offer(E e, long timeout, TimeUnit unit) + throws InterruptedException; + + /** + * Retrieves and removes the head of the queue represented by this deque + * (in other words, the first element of this deque). + * This method differs from {@link #poll poll} only in that it + * throws an exception if this deque is empty. + * + *

This method is equivalent to {@link #removeFirst() removeFirst}. + * + * @return the head of the queue represented by this deque + * @throws NoSuchElementException if this deque is empty + */ + E remove(); + + /** + * Retrieves and removes the head of the queue represented by this deque + * (in other words, the first element of this deque), or returns + * null if this deque is empty. + * + *

This method is equivalent to {@link #pollFirst()}. + * + * @return the head of this deque, or null if this deque is empty + */ + E poll(); + + /** + * Retrieves and removes the head of the queue represented by this deque + * (in other words, the first element of this deque), waiting if + * necessary until an element becomes available. + * + *

This method is equivalent to {@link #takeFirst() takeFirst}. + * + * @return the head of this deque + * @throws InterruptedException if interrupted while waiting + */ + E take() throws InterruptedException; + + /** + * Retrieves and removes the head of the queue represented by this deque + * (in other words, the first element of this deque), waiting up to the + * specified wait time if necessary for an element to become available. + * + *

This method is equivalent to + * {@link #pollFirst(long,TimeUnit) pollFirst}. + * + * @return the head of this deque, or null if the + * specified waiting time elapses before an element is available + * @throws InterruptedException if interrupted while waiting + */ + E poll(long timeout, TimeUnit unit) + throws InterruptedException; + + /** + * Retrieves, but does not remove, the head of the queue represented by + * this deque (in other words, the first element of this deque). + * This method differs from {@link #peek peek} only in that it throws an + * exception if this deque is empty. + * + *

This method is equivalent to {@link #getFirst() getFirst}. + * + * @return the head of this deque + * @throws NoSuchElementException if this deque is empty + */ + E element(); + + /** + * Retrieves, but does not remove, the head of the queue represented by + * this deque (in other words, the first element of this deque), or + * returns null if this deque is empty. + * + *

This method is equivalent to {@link #peekFirst() peekFirst}. + * + * @return the head of this deque, or null if this deque is empty + */ + E peek(); + + /** + * Removes the first occurrence of the specified element from this deque. + * If the deque does not contain the element, it is unchanged. + * More formally, removes the first element e such that + * o.equals(e) (if such an element exists). + * Returns true if this deque contained the specified element + * (or equivalently, if this deque changed as a result of the call). + * + *

This method is equivalent to + * {@link #removeFirstOccurrence(Object) removeFirstOccurrence}. + * + * @param o element to be removed from this deque, if present + * @return true if this deque changed as a result of the call + * @throws ClassCastException if the class of the specified element + * is incompatible with this deque + * (optional) + * @throws NullPointerException if the specified element is null + * (optional) + */ + boolean remove(Object o); + + /** + * Returns true if this deque contains the specified element. + * More formally, returns true if and only if this deque contains + * at least one element e such that o.equals(e). + * + * @param o object to be checked for containment in this deque + * @return true if this deque contains the specified element + * @throws ClassCastException if the class of the specified element + * is incompatible with this deque + * (optional) + * @throws NullPointerException if the specified element is null + * (optional) + */ + public boolean contains(Object o); + + /** + * Returns the number of elements in this deque. + * + * @return the number of elements in this deque + */ + public int size(); + + /** + * Returns an iterator over the elements in this deque in proper sequence. + * The elements will be returned in order from first (head) to last (tail). + * + * @return an iterator over the elements in this deque in proper sequence + */ + Iterator iterator(); + + // *** Stack methods *** + + /** + * Pushes an element onto the stack represented by this deque. In other + * words, inserts the element at the front of this deque unless it would + * violate capacity restrictions. + * + *

This method is equivalent to {@link #addFirst(Object) addFirst}. + * + * @throws IllegalStateException {@inheritDoc} + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if the specified element is null + * @throws IllegalArgumentException {@inheritDoc} + */ + void push(E e); +} diff -r e1953d8b8338 -r c8af252ea9eb rt/emul/compact/src/main/java/java/util/concurrent/BlockingQueue.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/BlockingQueue.java Sat Mar 19 10:48:29 2016 +0100 @@ -0,0 +1,377 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +package java.util.concurrent; + +import java.util.Collection; +import java.util.Queue; + +/** + * A {@link java.util.Queue} that additionally supports operations + * that wait for the queue to become non-empty when retrieving an + * element, and wait for space to become available in the queue when + * storing an element. + * + *

BlockingQueue methods come in four forms, with different ways + * of handling operations that cannot be satisfied immediately, but may be + * satisfied at some point in the future: + * one throws an exception, the second returns a special value (either + * null or false, depending on the operation), the third + * blocks the current thread indefinitely until the operation can succeed, + * and the fourth blocks for only a given maximum time limit before giving + * up. These methods are summarized in the following table: + * + *

+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Throws exceptionSpecial valueBlocksTimes out
Insert{@link #add add(e)}{@link #offer offer(e)}{@link #put put(e)}{@link #offer(Object, long, TimeUnit) offer(e, time, unit)}
Remove{@link #remove remove()}{@link #poll poll()}{@link #take take()}{@link #poll(long, TimeUnit) poll(time, unit)}
Examine{@link #element element()}{@link #peek peek()}not applicablenot applicable
+ * + *

A BlockingQueue does not accept null elements. + * Implementations throw NullPointerException on attempts + * to add, put or offer a null. A + * null is used as a sentinel value to indicate failure of + * poll operations. + * + *

A BlockingQueue may be capacity bounded. At any given + * time it may have a remainingCapacity beyond which no + * additional elements can be put without blocking. + * A BlockingQueue without any intrinsic capacity constraints always + * reports a remaining capacity of Integer.MAX_VALUE. + * + *

BlockingQueue implementations are designed to be used + * primarily for producer-consumer queues, but additionally support + * the {@link java.util.Collection} interface. So, for example, it is + * possible to remove an arbitrary element from a queue using + * remove(x). However, such operations are in general + * not performed very efficiently, and are intended for only + * occasional use, such as when a queued message is cancelled. + * + *

BlockingQueue implementations are thread-safe. All + * queuing methods achieve their effects atomically using internal + * locks or other forms of concurrency control. However, the + * bulk Collection operations addAll, + * containsAll, retainAll and removeAll are + * not necessarily performed atomically unless specified + * otherwise in an implementation. So it is possible, for example, for + * addAll(c) to fail (throwing an exception) after adding + * only some of the elements in c. + * + *

A BlockingQueue does not intrinsically support + * any kind of "close" or "shutdown" operation to + * indicate that no more items will be added. The needs and usage of + * such features tend to be implementation-dependent. For example, a + * common tactic is for producers to insert special + * end-of-stream or poison objects, that are + * interpreted accordingly when taken by consumers. + * + *

+ * Usage example, based on a typical producer-consumer scenario. + * Note that a BlockingQueue can safely be used with multiple + * producers and multiple consumers. + *

+ * class Producer implements Runnable {
+ *   private final BlockingQueue queue;
+ *   Producer(BlockingQueue q) { queue = q; }
+ *   public void run() {
+ *     try {
+ *       while (true) { queue.put(produce()); }
+ *     } catch (InterruptedException ex) { ... handle ...}
+ *   }
+ *   Object produce() { ... }
+ * }
+ *
+ * class Consumer implements Runnable {
+ *   private final BlockingQueue queue;
+ *   Consumer(BlockingQueue q) { queue = q; }
+ *   public void run() {
+ *     try {
+ *       while (true) { consume(queue.take()); }
+ *     } catch (InterruptedException ex) { ... handle ...}
+ *   }
+ *   void consume(Object x) { ... }
+ * }
+ *
+ * class Setup {
+ *   void main() {
+ *     BlockingQueue q = new SomeQueueImplementation();
+ *     Producer p = new Producer(q);
+ *     Consumer c1 = new Consumer(q);
+ *     Consumer c2 = new Consumer(q);
+ *     new Thread(p).start();
+ *     new Thread(c1).start();
+ *     new Thread(c2).start();
+ *   }
+ * }
+ * 
+ * + *

Memory consistency effects: As with other concurrent + * collections, actions in a thread prior to placing an object into a + * {@code BlockingQueue} + * happen-before + * actions subsequent to the access or removal of that element from + * the {@code BlockingQueue} in another thread. + * + *

This interface is a member of the + * + * Java Collections Framework. + * + * @since 1.5 + * @author Doug Lea + * @param the type of elements held in this collection + */ +public interface BlockingQueue extends Queue { + /** + * Inserts the specified element into this queue if it is possible to do + * so immediately without violating capacity restrictions, returning + * true upon success and throwing an + * IllegalStateException if no space is currently available. + * When using a capacity-restricted queue, it is generally preferable to + * use {@link #offer(Object) offer}. + * + * @param e the element to add + * @return true (as specified by {@link Collection#add}) + * @throws IllegalStateException if the element cannot be added at this + * time due to capacity restrictions + * @throws ClassCastException if the class of the specified element + * prevents it from being added to this queue + * @throws NullPointerException if the specified element is null + * @throws IllegalArgumentException if some property of the specified + * element prevents it from being added to this queue + */ + boolean add(E e); + + /** + * Inserts the specified element into this queue if it is possible to do + * so immediately without violating capacity restrictions, returning + * true upon success and false if no space is currently + * available. When using a capacity-restricted queue, this method is + * generally preferable to {@link #add}, which can fail to insert an + * element only by throwing an exception. + * + * @param e the element to add + * @return true if the element was added to this queue, else + * false + * @throws ClassCastException if the class of the specified element + * prevents it from being added to this queue + * @throws NullPointerException if the specified element is null + * @throws IllegalArgumentException if some property of the specified + * element prevents it from being added to this queue + */ + boolean offer(E e); + + /** + * Inserts the specified element into this queue, waiting if necessary + * for space to become available. + * + * @param e the element to add + * @throws InterruptedException if interrupted while waiting + * @throws ClassCastException if the class of the specified element + * prevents it from being added to this queue + * @throws NullPointerException if the specified element is null + * @throws IllegalArgumentException if some property of the specified + * element prevents it from being added to this queue + */ + void put(E e) throws InterruptedException; + + /** + * Inserts the specified element into this queue, waiting up to the + * specified wait time if necessary for space to become available. + * + * @param e the element to add + * @param timeout how long to wait before giving up, in units of + * unit + * @param unit a TimeUnit determining how to interpret the + * timeout parameter + * @return true if successful, or false if + * the specified waiting time elapses before space is available + * @throws InterruptedException if interrupted while waiting + * @throws ClassCastException if the class of the specified element + * prevents it from being added to this queue + * @throws NullPointerException if the specified element is null + * @throws IllegalArgumentException if some property of the specified + * element prevents it from being added to this queue + */ + boolean offer(E e, long timeout, TimeUnit unit) + throws InterruptedException; + + /** + * Retrieves and removes the head of this queue, waiting if necessary + * until an element becomes available. + * + * @return the head of this queue + * @throws InterruptedException if interrupted while waiting + */ + E take() throws InterruptedException; + + /** + * Retrieves and removes the head of this queue, waiting up to the + * specified wait time if necessary for an element to become available. + * + * @param timeout how long to wait before giving up, in units of + * unit + * @param unit a TimeUnit determining how to interpret the + * timeout parameter + * @return the head of this queue, or null if the + * specified waiting time elapses before an element is available + * @throws InterruptedException if interrupted while waiting + */ + E poll(long timeout, TimeUnit unit) + throws InterruptedException; + + /** + * Returns the number of additional elements that this queue can ideally + * (in the absence of memory or resource constraints) accept without + * blocking, or Integer.MAX_VALUE if there is no intrinsic + * limit. + * + *

Note that you cannot always tell if an attempt to insert + * an element will succeed by inspecting remainingCapacity + * because it may be the case that another thread is about to + * insert or remove an element. + * + * @return the remaining capacity + */ + int remainingCapacity(); + + /** + * Removes a single instance of the specified element from this queue, + * if it is present. More formally, removes an element e such + * that o.equals(e), if this queue contains one or more such + * elements. + * Returns true if this queue contained the specified element + * (or equivalently, if this queue changed as a result of the call). + * + * @param o element to be removed from this queue, if present + * @return true if this queue changed as a result of the call + * @throws ClassCastException if the class of the specified element + * is incompatible with this queue + * (optional) + * @throws NullPointerException if the specified element is null + * (optional) + */ + boolean remove(Object o); + + /** + * Returns true if this queue contains the specified element. + * More formally, returns true if and only if this queue contains + * at least one element e such that o.equals(e). + * + * @param o object to be checked for containment in this queue + * @return true if this queue contains the specified element + * @throws ClassCastException if the class of the specified element + * is incompatible with this queue + * (optional) + * @throws NullPointerException if the specified element is null + * (optional) + */ + public boolean contains(Object o); + + /** + * Removes all available elements from this queue and adds them + * to the given collection. This operation may be more + * efficient than repeatedly polling this queue. A failure + * encountered while attempting to add elements to + * collection c may result in elements being in neither, + * either or both collections when the associated exception is + * thrown. Attempts to drain a queue to itself result in + * IllegalArgumentException. Further, the behavior of + * this operation is undefined if the specified collection is + * modified while the operation is in progress. + * + * @param c the collection to transfer elements into + * @return the number of elements transferred + * @throws UnsupportedOperationException if addition of elements + * is not supported by the specified collection + * @throws ClassCastException if the class of an element of this queue + * prevents it from being added to the specified collection + * @throws NullPointerException if the specified collection is null + * @throws IllegalArgumentException if the specified collection is this + * queue, or some property of an element of this queue prevents + * it from being added to the specified collection + */ + int drainTo(Collection c); + + /** + * Removes at most the given number of available elements from + * this queue and adds them to the given collection. A failure + * encountered while attempting to add elements to + * collection c may result in elements being in neither, + * either or both collections when the associated exception is + * thrown. Attempts to drain a queue to itself result in + * IllegalArgumentException. Further, the behavior of + * this operation is undefined if the specified collection is + * modified while the operation is in progress. + * + * @param c the collection to transfer elements into + * @param maxElements the maximum number of elements to transfer + * @return the number of elements transferred + * @throws UnsupportedOperationException if addition of elements + * is not supported by the specified collection + * @throws ClassCastException if the class of an element of this queue + * prevents it from being added to the specified collection + * @throws NullPointerException if the specified collection is null + * @throws IllegalArgumentException if the specified collection is this + * queue, or some property of an element of this queue prevents + * it from being added to the specified collection + */ + int drainTo(Collection c, int maxElements); +} diff -r e1953d8b8338 -r c8af252ea9eb rt/emul/compact/src/main/java/java/util/concurrent/BrokenBarrierException.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/BrokenBarrierException.java Sat Mar 19 10:48:29 2016 +0100 @@ -0,0 +1,67 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +package java.util.concurrent; + +/** + * Exception thrown when a thread tries to wait upon a barrier that is + * in a broken state, or which enters the broken state while the thread + * is waiting. + * + * @see CyclicBarrier + * + * @since 1.5 + * @author Doug Lea + * + */ +public class BrokenBarrierException extends Exception { + private static final long serialVersionUID = 7117394618823254244L; + + /** + * Constructs a BrokenBarrierException with no specified detail + * message. + */ + public BrokenBarrierException() {} + + /** + * Constructs a BrokenBarrierException with the specified + * detail message. + * + * @param message the detail message + */ + public BrokenBarrierException(String message) { + super(message); + } +} diff -r e1953d8b8338 -r c8af252ea9eb rt/emul/compact/src/main/java/java/util/concurrent/CancellationException.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/CancellationException.java Sat Mar 19 10:48:29 2016 +0100 @@ -0,0 +1,63 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +package java.util.concurrent; + +/** + * Exception indicating that the result of a value-producing task, + * such as a {@link FutureTask}, cannot be retrieved because the task + * was cancelled. + * + * @since 1.5 + * @author Doug Lea + */ +public class CancellationException extends IllegalStateException { + private static final long serialVersionUID = -9202173006928992231L; + + /** + * Constructs a CancellationException with no detail message. + */ + public CancellationException() {} + + /** + * Constructs a CancellationException with the specified detail + * message. + * + * @param message the detail message + */ + public CancellationException(String message) { + super(message); + } +} diff -r e1953d8b8338 -r c8af252ea9eb rt/emul/compact/src/main/java/java/util/concurrent/CompletionService.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/CompletionService.java Sat Mar 19 10:48:29 2016 +0100 @@ -0,0 +1,126 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +package java.util.concurrent; + +/** + * A service that decouples the production of new asynchronous tasks + * from the consumption of the results of completed tasks. Producers + * submit tasks for execution. Consumers take + * completed tasks and process their results in the order they + * complete. A CompletionService can for example be used to + * manage asynchronous IO, in which tasks that perform reads are + * submitted in one part of a program or system, and then acted upon + * in a different part of the program when the reads complete, + * possibly in a different order than they were requested. + * + *

Typically, a CompletionService relies on a separate + * {@link Executor} to actually execute the tasks, in which case the + * CompletionService only manages an internal completion + * queue. The {@link ExecutorCompletionService} class provides an + * implementation of this approach. + * + *

Memory consistency effects: Actions in a thread prior to + * submitting a task to a {@code CompletionService} + * happen-before + * actions taken by that task, which in turn happen-before + * actions following a successful return from the corresponding {@code take()}. + * + */ +public interface CompletionService { + /** + * Submits a value-returning task for execution and returns a Future + * representing the pending results of the task. Upon completion, + * this task may be taken or polled. + * + * @param task the task to submit + * @return a Future representing pending completion of the task + * @throws RejectedExecutionException if the task cannot be + * scheduled for execution + * @throws NullPointerException if the task is null + */ + Future submit(Callable task); + + /** + * Submits a Runnable task for execution and returns a Future + * representing that task. Upon completion, this task may be + * taken or polled. + * + * @param task the task to submit + * @param result the result to return upon successful completion + * @return a Future representing pending completion of the task, + * and whose get() method will return the given + * result value upon completion + * @throws RejectedExecutionException if the task cannot be + * scheduled for execution + * @throws NullPointerException if the task is null + */ + Future submit(Runnable task, V result); + + /** + * Retrieves and removes the Future representing the next + * completed task, waiting if none are yet present. + * + * @return the Future representing the next completed task + * @throws InterruptedException if interrupted while waiting + */ + Future take() throws InterruptedException; + + + /** + * Retrieves and removes the Future representing the next + * completed task or null if none are present. + * + * @return the Future representing the next completed task, or + * null if none are present + */ + Future poll(); + + /** + * Retrieves and removes the Future representing the next + * completed task, waiting if necessary up to the specified wait + * time if none are yet present. + * + * @param timeout how long to wait before giving up, in units of + * unit + * @param unit a TimeUnit determining how to interpret the + * timeout parameter + * @return the Future representing the next completed task or + * null if the specified waiting time elapses + * before one is present + * @throws InterruptedException if interrupted while waiting + */ + Future poll(long timeout, TimeUnit unit) throws InterruptedException; +} diff -r e1953d8b8338 -r c8af252ea9eb rt/emul/compact/src/main/java/java/util/concurrent/ConcurrentLinkedDeque.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/ConcurrentLinkedDeque.java Sat Mar 19 10:48:29 2016 +0100 @@ -0,0 +1,1469 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea and Martin Buchholz with assistance from members of + * JCP JSR-166 Expert Group and released to the public domain, as explained + * at http://creativecommons.org/publicdomain/zero/1.0/ + */ + +package java.util.concurrent; + +import java.util.AbstractCollection; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Deque; +import java.util.Iterator; +import java.util.NoSuchElementException; +import java.util.Queue; + +/** + * An unbounded concurrent {@linkplain Deque deque} based on linked nodes. + * Concurrent insertion, removal, and access operations execute safely + * across multiple threads. + * A {@code ConcurrentLinkedDeque} is an appropriate choice when + * many threads will share access to a common collection. + * Like most other concurrent collection implementations, this class + * does not permit the use of {@code null} elements. + * + *

Iterators are weakly consistent, returning elements + * reflecting the state of the deque at some point at or since the + * creation of the iterator. They do not throw {@link + * java.util.ConcurrentModificationException + * ConcurrentModificationException}, and may proceed concurrently with + * other operations. + * + *

Beware that, unlike in most collections, the {@code size} method + * is NOT a constant-time operation. Because of the + * asynchronous nature of these deques, determining the current number + * of elements requires a traversal of the elements, and so may report + * inaccurate results if this collection is modified during traversal. + * Additionally, the bulk operations {@code addAll}, + * {@code removeAll}, {@code retainAll}, {@code containsAll}, + * {@code equals}, and {@code toArray} are not guaranteed + * to be performed atomically. For example, an iterator operating + * concurrently with an {@code addAll} operation might view only some + * of the added elements. + * + *

This class and its iterator implement all of the optional + * methods of the {@link Deque} and {@link Iterator} interfaces. + * + *

Memory consistency effects: As with other concurrent collections, + * actions in a thread prior to placing an object into a + * {@code ConcurrentLinkedDeque} + * happen-before + * actions subsequent to the access or removal of that element from + * the {@code ConcurrentLinkedDeque} in another thread. + * + *

This class is a member of the + * + * Java Collections Framework. + * + * @since 1.7 + * @author Doug Lea + * @author Martin Buchholz + * @param the type of elements held in this collection + */ + +public class ConcurrentLinkedDeque + extends AbstractCollection + implements Deque, java.io.Serializable { + + /* + * This is an implementation of a concurrent lock-free deque + * supporting interior removes but not interior insertions, as + * required to support the entire Deque interface. + * + * We extend the techniques developed for ConcurrentLinkedQueue and + * LinkedTransferQueue (see the internal docs for those classes). + * Understanding the ConcurrentLinkedQueue implementation is a + * prerequisite for understanding the implementation of this class. + * + * The data structure is a symmetrical doubly-linked "GC-robust" + * linked list of nodes. We minimize the number of volatile writes + * using two techniques: advancing multiple hops with a single CAS + * and mixing volatile and non-volatile writes of the same memory + * locations. + * + * A node contains the expected E ("item") and links to predecessor + * ("prev") and successor ("next") nodes: + * + * class Node { volatile Node prev, next; volatile E item; } + * + * A node p is considered "live" if it contains a non-null item + * (p.item != null). When an item is CASed to null, the item is + * atomically logically deleted from the collection. + * + * At any time, there is precisely one "first" node with a null + * prev reference that terminates any chain of prev references + * starting at a live node. Similarly there is precisely one + * "last" node terminating any chain of next references starting at + * a live node. The "first" and "last" nodes may or may not be live. + * The "first" and "last" nodes are always mutually reachable. + * + * A new element is added atomically by CASing the null prev or + * next reference in the first or last node to a fresh node + * containing the element. The element's node atomically becomes + * "live" at that point. + * + * A node is considered "active" if it is a live node, or the + * first or last node. Active nodes cannot be unlinked. + * + * A "self-link" is a next or prev reference that is the same node: + * p.prev == p or p.next == p + * Self-links are used in the node unlinking process. Active nodes + * never have self-links. + * + * A node p is active if and only if: + * + * p.item != null || + * (p.prev == null && p.next != p) || + * (p.next == null && p.prev != p) + * + * The deque object has two node references, "head" and "tail". + * The head and tail are only approximations to the first and last + * nodes of the deque. The first node can always be found by + * following prev pointers from head; likewise for tail. However, + * it is permissible for head and tail to be referring to deleted + * nodes that have been unlinked and so may not be reachable from + * any live node. + * + * There are 3 stages of node deletion; + * "logical deletion", "unlinking", and "gc-unlinking". + * + * 1. "logical deletion" by CASing item to null atomically removes + * the element from the collection, and makes the containing node + * eligible for unlinking. + * + * 2. "unlinking" makes a deleted node unreachable from active + * nodes, and thus eventually reclaimable by GC. Unlinked nodes + * may remain reachable indefinitely from an iterator. + * + * Physical node unlinking is merely an optimization (albeit a + * critical one), and so can be performed at our convenience. At + * any time, the set of live nodes maintained by prev and next + * links are identical, that is, the live nodes found via next + * links from the first node is equal to the elements found via + * prev links from the last node. However, this is not true for + * nodes that have already been logically deleted - such nodes may + * be reachable in one direction only. + * + * 3. "gc-unlinking" takes unlinking further by making active + * nodes unreachable from deleted nodes, making it easier for the + * GC to reclaim future deleted nodes. This step makes the data + * structure "gc-robust", as first described in detail by Boehm + * (http://portal.acm.org/citation.cfm?doid=503272.503282). + * + * GC-unlinked nodes may remain reachable indefinitely from an + * iterator, but unlike unlinked nodes, are never reachable from + * head or tail. + * + * Making the data structure GC-robust will eliminate the risk of + * unbounded memory retention with conservative GCs and is likely + * to improve performance with generational GCs. + * + * When a node is dequeued at either end, e.g. via poll(), we would + * like to break any references from the node to active nodes. We + * develop further the use of self-links that was very effective in + * other concurrent collection classes. The idea is to replace + * prev and next pointers with special values that are interpreted + * to mean off-the-list-at-one-end. These are approximations, but + * good enough to preserve the properties we want in our + * traversals, e.g. we guarantee that a traversal will never visit + * the same element twice, but we don't guarantee whether a + * traversal that runs out of elements will be able to see more + * elements later after enqueues at that end. Doing gc-unlinking + * safely is particularly tricky, since any node can be in use + * indefinitely (for example by an iterator). We must ensure that + * the nodes pointed at by head/tail never get gc-unlinked, since + * head/tail are needed to get "back on track" by other nodes that + * are gc-unlinked. gc-unlinking accounts for much of the + * implementation complexity. + * + * Since neither unlinking nor gc-unlinking are necessary for + * correctness, there are many implementation choices regarding + * frequency (eagerness) of these operations. Since volatile + * reads are likely to be much cheaper than CASes, saving CASes by + * unlinking multiple adjacent nodes at a time may be a win. + * gc-unlinking can be performed rarely and still be effective, + * since it is most important that long chains of deleted nodes + * are occasionally broken. + * + * The actual representation we use is that p.next == p means to + * goto the first node (which in turn is reached by following prev + * pointers from head), and p.next == null && p.prev == p means + * that the iteration is at an end and that p is a (static final) + * dummy node, NEXT_TERMINATOR, and not the last active node. + * Finishing the iteration when encountering such a TERMINATOR is + * good enough for read-only traversals, so such traversals can use + * p.next == null as the termination condition. When we need to + * find the last (active) node, for enqueueing a new node, we need + * to check whether we have reached a TERMINATOR node; if so, + * restart traversal from tail. + * + * The implementation is completely directionally symmetrical, + * except that most public methods that iterate through the list + * follow next pointers ("forward" direction). + * + * We believe (without full proof) that all single-element deque + * operations (e.g., addFirst, peekLast, pollLast) are linearizable + * (see Herlihy and Shavit's book). However, some combinations of + * operations are known not to be linearizable. In particular, + * when an addFirst(A) is racing with pollFirst() removing B, it is + * possible for an observer iterating over the elements to observe + * A B C and subsequently observe A C, even though no interior + * removes are ever performed. Nevertheless, iterators behave + * reasonably, providing the "weakly consistent" guarantees. + * + * Empirically, microbenchmarks suggest that this class adds about + * 40% overhead relative to ConcurrentLinkedQueue, which feels as + * good as we can hope for. + */ + + private static final long serialVersionUID = 876323262645176354L; + + /** + * A node from which the first node on list (that is, the unique node p + * with p.prev == null && p.next != p) can be reached in O(1) time. + * Invariants: + * - the first node is always O(1) reachable from head via prev links + * - all live nodes are reachable from the first node via succ() + * - head != null + * - (tmp = head).next != tmp || tmp != head + * - head is never gc-unlinked (but may be unlinked) + * Non-invariants: + * - head.item may or may not be null + * - head may not be reachable from the first or last node, or from tail + */ + private transient volatile Node head; + + /** + * A node from which the last node on list (that is, the unique node p + * with p.next == null && p.prev != p) can be reached in O(1) time. + * Invariants: + * - the last node is always O(1) reachable from tail via next links + * - all live nodes are reachable from the last node via pred() + * - tail != null + * - tail is never gc-unlinked (but may be unlinked) + * Non-invariants: + * - tail.item may or may not be null + * - tail may not be reachable from the first or last node, or from head + */ + private transient volatile Node tail; + + private static final Node PREV_TERMINATOR, NEXT_TERMINATOR; + + @SuppressWarnings("unchecked") + Node prevTerminator() { + return (Node) PREV_TERMINATOR; + } + + @SuppressWarnings("unchecked") + Node nextTerminator() { + return (Node) NEXT_TERMINATOR; + } + + static final class Node { + volatile Node prev; + volatile E item; + volatile Node next; + + Node() { // default constructor for NEXT_TERMINATOR, PREV_TERMINATOR + } + + /** + * Constructs a new node. Uses relaxed write because item can + * only be seen after publication via casNext or casPrev. + */ + Node(E item) { + UNSAFE.putObject(this, itemOffset, item); + } + + boolean casItem(E cmp, E val) { + return UNSAFE.compareAndSwapObject(this, itemOffset, cmp, val); + } + + void lazySetNext(Node val) { + UNSAFE.putOrderedObject(this, nextOffset, val); + } + + boolean casNext(Node cmp, Node val) { + return UNSAFE.compareAndSwapObject(this, nextOffset, cmp, val); + } + + void lazySetPrev(Node val) { + UNSAFE.putOrderedObject(this, prevOffset, val); + } + + boolean casPrev(Node cmp, Node val) { + return UNSAFE.compareAndSwapObject(this, prevOffset, cmp, val); + } + + // Unsafe mechanics + + private static final sun.misc.Unsafe UNSAFE; + private static final long prevOffset; + private static final long itemOffset; + private static final long nextOffset; + + static { + try { + UNSAFE = sun.misc.Unsafe.getUnsafe(); + Class k = Node.class; + prevOffset = UNSAFE.objectFieldOffset + (k.getDeclaredField("prev")); + itemOffset = UNSAFE.objectFieldOffset + (k.getDeclaredField("item")); + nextOffset = UNSAFE.objectFieldOffset + (k.getDeclaredField("next")); + } catch (Exception e) { + throw new Error(e); + } + } + } + + /** + * Links e as first element. + */ + private void linkFirst(E e) { + checkNotNull(e); + final Node newNode = new Node(e); + + restartFromHead: + for (;;) + for (Node h = head, p = h, q;;) { + if ((q = p.prev) != null && + (q = (p = q).prev) != null) + // Check for head updates every other hop. + // If p == q, we are sure to follow head instead. + p = (h != (h = head)) ? h : q; + else if (p.next == p) // PREV_TERMINATOR + continue restartFromHead; + else { + // p is first node + newNode.lazySetNext(p); // CAS piggyback + if (p.casPrev(null, newNode)) { + // Successful CAS is the linearization point + // for e to become an element of this deque, + // and for newNode to become "live". + if (p != h) // hop two nodes at a time + casHead(h, newNode); // Failure is OK. + return; + } + // Lost CAS race to another thread; re-read prev + } + } + } + + /** + * Links e as last element. + */ + private void linkLast(E e) { + checkNotNull(e); + final Node newNode = new Node(e); + + restartFromTail: + for (;;) + for (Node t = tail, p = t, q;;) { + if ((q = p.next) != null && + (q = (p = q).next) != null) + // Check for tail updates every other hop. + // If p == q, we are sure to follow tail instead. + p = (t != (t = tail)) ? t : q; + else if (p.prev == p) // NEXT_TERMINATOR + continue restartFromTail; + else { + // p is last node + newNode.lazySetPrev(p); // CAS piggyback + if (p.casNext(null, newNode)) { + // Successful CAS is the linearization point + // for e to become an element of this deque, + // and for newNode to become "live". + if (p != t) // hop two nodes at a time + casTail(t, newNode); // Failure is OK. + return; + } + // Lost CAS race to another thread; re-read next + } + } + } + + private static final int HOPS = 2; + + /** + * Unlinks non-null node x. + */ + void unlink(Node x) { + // assert x != null; + // assert x.item == null; + // assert x != PREV_TERMINATOR; + // assert x != NEXT_TERMINATOR; + + final Node prev = x.prev; + final Node next = x.next; + if (prev == null) { + unlinkFirst(x, next); + } else if (next == null) { + unlinkLast(x, prev); + } else { + // Unlink interior node. + // + // This is the common case, since a series of polls at the + // same end will be "interior" removes, except perhaps for + // the first one, since end nodes cannot be unlinked. + // + // At any time, all active nodes are mutually reachable by + // following a sequence of either next or prev pointers. + // + // Our strategy is to find the unique active predecessor + // and successor of x. Try to fix up their links so that + // they point to each other, leaving x unreachable from + // active nodes. If successful, and if x has no live + // predecessor/successor, we additionally try to gc-unlink, + // leaving active nodes unreachable from x, by rechecking + // that the status of predecessor and successor are + // unchanged and ensuring that x is not reachable from + // tail/head, before setting x's prev/next links to their + // logical approximate replacements, self/TERMINATOR. + Node activePred, activeSucc; + boolean isFirst, isLast; + int hops = 1; + + // Find active predecessor + for (Node p = prev; ; ++hops) { + if (p.item != null) { + activePred = p; + isFirst = false; + break; + } + Node q = p.prev; + if (q == null) { + if (p.next == p) + return; + activePred = p; + isFirst = true; + break; + } + else if (p == q) + return; + else + p = q; + } + + // Find active successor + for (Node p = next; ; ++hops) { + if (p.item != null) { + activeSucc = p; + isLast = false; + break; + } + Node q = p.next; + if (q == null) { + if (p.prev == p) + return; + activeSucc = p; + isLast = true; + break; + } + else if (p == q) + return; + else + p = q; + } + + // TODO: better HOP heuristics + if (hops < HOPS + // always squeeze out interior deleted nodes + && (isFirst | isLast)) + return; + + // Squeeze out deleted nodes between activePred and + // activeSucc, including x. + skipDeletedSuccessors(activePred); + skipDeletedPredecessors(activeSucc); + + // Try to gc-unlink, if possible + if ((isFirst | isLast) && + + // Recheck expected state of predecessor and successor + (activePred.next == activeSucc) && + (activeSucc.prev == activePred) && + (isFirst ? activePred.prev == null : activePred.item != null) && + (isLast ? activeSucc.next == null : activeSucc.item != null)) { + + updateHead(); // Ensure x is not reachable from head + updateTail(); // Ensure x is not reachable from tail + + // Finally, actually gc-unlink + x.lazySetPrev(isFirst ? prevTerminator() : x); + x.lazySetNext(isLast ? nextTerminator() : x); + } + } + } + + /** + * Unlinks non-null first node. + */ + private void unlinkFirst(Node first, Node next) { + // assert first != null; + // assert next != null; + // assert first.item == null; + for (Node o = null, p = next, q;;) { + if (p.item != null || (q = p.next) == null) { + if (o != null && p.prev != p && first.casNext(next, p)) { + skipDeletedPredecessors(p); + if (first.prev == null && + (p.next == null || p.item != null) && + p.prev == first) { + + updateHead(); // Ensure o is not reachable from head + updateTail(); // Ensure o is not reachable from tail + + // Finally, actually gc-unlink + o.lazySetNext(o); + o.lazySetPrev(prevTerminator()); + } + } + return; + } + else if (p == q) + return; + else { + o = p; + p = q; + } + } + } + + /** + * Unlinks non-null last node. + */ + private void unlinkLast(Node last, Node prev) { + // assert last != null; + // assert prev != null; + // assert last.item == null; + for (Node o = null, p = prev, q;;) { + if (p.item != null || (q = p.prev) == null) { + if (o != null && p.next != p && last.casPrev(prev, p)) { + skipDeletedSuccessors(p); + if (last.next == null && + (p.prev == null || p.item != null) && + p.next == last) { + + updateHead(); // Ensure o is not reachable from head + updateTail(); // Ensure o is not reachable from tail + + // Finally, actually gc-unlink + o.lazySetPrev(o); + o.lazySetNext(nextTerminator()); + } + } + return; + } + else if (p == q) + return; + else { + o = p; + p = q; + } + } + } + + /** + * Guarantees that any node which was unlinked before a call to + * this method will be unreachable from head after it returns. + * Does not guarantee to eliminate slack, only that head will + * point to a node that was active while this method was running. + */ + private final void updateHead() { + // Either head already points to an active node, or we keep + // trying to cas it to the first node until it does. + Node h, p, q; + restartFromHead: + while ((h = head).item == null && (p = h.prev) != null) { + for (;;) { + if ((q = p.prev) == null || + (q = (p = q).prev) == null) { + // It is possible that p is PREV_TERMINATOR, + // but if so, the CAS is guaranteed to fail. + if (casHead(h, p)) + return; + else + continue restartFromHead; + } + else if (h != head) + continue restartFromHead; + else + p = q; + } + } + } + + /** + * Guarantees that any node which was unlinked before a call to + * this method will be unreachable from tail after it returns. + * Does not guarantee to eliminate slack, only that tail will + * point to a node that was active while this method was running. + */ + private final void updateTail() { + // Either tail already points to an active node, or we keep + // trying to cas it to the last node until it does. + Node t, p, q; + restartFromTail: + while ((t = tail).item == null && (p = t.next) != null) { + for (;;) { + if ((q = p.next) == null || + (q = (p = q).next) == null) { + // It is possible that p is NEXT_TERMINATOR, + // but if so, the CAS is guaranteed to fail. + if (casTail(t, p)) + return; + else + continue restartFromTail; + } + else if (t != tail) + continue restartFromTail; + else + p = q; + } + } + } + + private void skipDeletedPredecessors(Node x) { + whileActive: + do { + Node prev = x.prev; + // assert prev != null; + // assert x != NEXT_TERMINATOR; + // assert x != PREV_TERMINATOR; + Node p = prev; + findActive: + for (;;) { + if (p.item != null) + break findActive; + Node q = p.prev; + if (q == null) { + if (p.next == p) + continue whileActive; + break findActive; + } + else if (p == q) + continue whileActive; + else + p = q; + } + + // found active CAS target + if (prev == p || x.casPrev(prev, p)) + return; + + } while (x.item != null || x.next == null); + } + + private void skipDeletedSuccessors(Node x) { + whileActive: + do { + Node next = x.next; + // assert next != null; + // assert x != NEXT_TERMINATOR; + // assert x != PREV_TERMINATOR; + Node p = next; + findActive: + for (;;) { + if (p.item != null) + break findActive; + Node q = p.next; + if (q == null) { + if (p.prev == p) + continue whileActive; + break findActive; + } + else if (p == q) + continue whileActive; + else + p = q; + } + + // found active CAS target + if (next == p || x.casNext(next, p)) + return; + + } while (x.item != null || x.prev == null); + } + + /** + * Returns the successor of p, or the first node if p.next has been + * linked to self, which will only be true if traversing with a + * stale pointer that is now off the list. + */ + final Node succ(Node p) { + // TODO: should we skip deleted nodes here? + Node q = p.next; + return (p == q) ? first() : q; + } + + /** + * Returns the predecessor of p, or the last node if p.prev has been + * linked to self, which will only be true if traversing with a + * stale pointer that is now off the list. + */ + final Node pred(Node p) { + Node q = p.prev; + return (p == q) ? last() : q; + } + + /** + * Returns the first node, the unique node p for which: + * p.prev == null && p.next != p + * The returned node may or may not be logically deleted. + * Guarantees that head is set to the returned node. + */ + Node first() { + restartFromHead: + for (;;) + for (Node h = head, p = h, q;;) { + if ((q = p.prev) != null && + (q = (p = q).prev) != null) + // Check for head updates every other hop. + // If p == q, we are sure to follow head instead. + p = (h != (h = head)) ? h : q; + else if (p == h + // It is possible that p is PREV_TERMINATOR, + // but if so, the CAS is guaranteed to fail. + || casHead(h, p)) + return p; + else + continue restartFromHead; + } + } + + /** + * Returns the last node, the unique node p for which: + * p.next == null && p.prev != p + * The returned node may or may not be logically deleted. + * Guarantees that tail is set to the returned node. + */ + Node last() { + restartFromTail: + for (;;) + for (Node t = tail, p = t, q;;) { + if ((q = p.next) != null && + (q = (p = q).next) != null) + // Check for tail updates every other hop. + // If p == q, we are sure to follow tail instead. + p = (t != (t = tail)) ? t : q; + else if (p == t + // It is possible that p is NEXT_TERMINATOR, + // but if so, the CAS is guaranteed to fail. + || casTail(t, p)) + return p; + else + continue restartFromTail; + } + } + + // Minor convenience utilities + + /** + * Throws NullPointerException if argument is null. + * + * @param v the element + */ + private static void checkNotNull(Object v) { + if (v == null) + throw new NullPointerException(); + } + + /** + * Returns element unless it is null, in which case throws + * NoSuchElementException. + * + * @param v the element + * @return the element + */ + private E screenNullResult(E v) { + if (v == null) + throw new NoSuchElementException(); + return v; + } + + /** + * Creates an array list and fills it with elements of this list. + * Used by toArray. + * + * @return the arrayList + */ + private ArrayList toArrayList() { + ArrayList list = new ArrayList(); + for (Node p = first(); p != null; p = succ(p)) { + E item = p.item; + if (item != null) + list.add(item); + } + return list; + } + + /** + * Constructs an empty deque. + */ + public ConcurrentLinkedDeque() { + head = tail = new Node(null); + } + + /** + * Constructs a deque initially containing the elements of + * the given collection, added in traversal order of the + * collection's iterator. + * + * @param c the collection of elements to initially contain + * @throws NullPointerException if the specified collection or any + * of its elements are null + */ + public ConcurrentLinkedDeque(Collection c) { + // Copy c into a private chain of Nodes + Node h = null, t = null; + for (E e : c) { + checkNotNull(e); + Node newNode = new Node(e); + if (h == null) + h = t = newNode; + else { + t.lazySetNext(newNode); + newNode.lazySetPrev(t); + t = newNode; + } + } + initHeadTail(h, t); + } + + /** + * Initializes head and tail, ensuring invariants hold. + */ + private void initHeadTail(Node h, Node t) { + if (h == t) { + if (h == null) + h = t = new Node(null); + else { + // Avoid edge case of a single Node with non-null item. + Node newNode = new Node(null); + t.lazySetNext(newNode); + newNode.lazySetPrev(t); + t = newNode; + } + } + head = h; + tail = t; + } + + /** + * Inserts the specified element at the front of this deque. + * As the deque is unbounded, this method will never throw + * {@link IllegalStateException}. + * + * @throws NullPointerException if the specified element is null + */ + public void addFirst(E e) { + linkFirst(e); + } + + /** + * Inserts the specified element at the end of this deque. + * As the deque is unbounded, this method will never throw + * {@link IllegalStateException}. + * + *

This method is equivalent to {@link #add}. + * + * @throws NullPointerException if the specified element is null + */ + public void addLast(E e) { + linkLast(e); + } + + /** + * Inserts the specified element at the front of this deque. + * As the deque is unbounded, this method will never return {@code false}. + * + * @return {@code true} (as specified by {@link Deque#offerFirst}) + * @throws NullPointerException if the specified element is null + */ + public boolean offerFirst(E e) { + linkFirst(e); + return true; + } + + /** + * Inserts the specified element at the end of this deque. + * As the deque is unbounded, this method will never return {@code false}. + * + *

This method is equivalent to {@link #add}. + * + * @return {@code true} (as specified by {@link Deque#offerLast}) + * @throws NullPointerException if the specified element is null + */ + public boolean offerLast(E e) { + linkLast(e); + return true; + } + + public E peekFirst() { + for (Node p = first(); p != null; p = succ(p)) { + E item = p.item; + if (item != null) + return item; + } + return null; + } + + public E peekLast() { + for (Node p = last(); p != null; p = pred(p)) { + E item = p.item; + if (item != null) + return item; + } + return null; + } + + /** + * @throws NoSuchElementException {@inheritDoc} + */ + public E getFirst() { + return screenNullResult(peekFirst()); + } + + /** + * @throws NoSuchElementException {@inheritDoc} + */ + public E getLast() { + return screenNullResult(peekLast()); + } + + public E pollFirst() { + for (Node p = first(); p != null; p = succ(p)) { + E item = p.item; + if (item != null && p.casItem(item, null)) { + unlink(p); + return item; + } + } + return null; + } + + public E pollLast() { + for (Node p = last(); p != null; p = pred(p)) { + E item = p.item; + if (item != null && p.casItem(item, null)) { + unlink(p); + return item; + } + } + return null; + } + + /** + * @throws NoSuchElementException {@inheritDoc} + */ + public E removeFirst() { + return screenNullResult(pollFirst()); + } + + /** + * @throws NoSuchElementException {@inheritDoc} + */ + public E removeLast() { + return screenNullResult(pollLast()); + } + + // *** Queue and stack methods *** + + /** + * Inserts the specified element at the tail of this deque. + * As the deque is unbounded, this method will never return {@code false}. + * + * @return {@code true} (as specified by {@link Queue#offer}) + * @throws NullPointerException if the specified element is null + */ + public boolean offer(E e) { + return offerLast(e); + } + + /** + * Inserts the specified element at the tail of this deque. + * As the deque is unbounded, this method will never throw + * {@link IllegalStateException} or return {@code false}. + * + * @return {@code true} (as specified by {@link Collection#add}) + * @throws NullPointerException if the specified element is null + */ + public boolean add(E e) { + return offerLast(e); + } + + public E poll() { return pollFirst(); } + public E remove() { return removeFirst(); } + public E peek() { return peekFirst(); } + public E element() { return getFirst(); } + public void push(E e) { addFirst(e); } + public E pop() { return removeFirst(); } + + /** + * Removes the first element {@code e} such that + * {@code o.equals(e)}, if such an element exists in this deque. + * If the deque does not contain the element, it is unchanged. + * + * @param o element to be removed from this deque, if present + * @return {@code true} if the deque contained the specified element + * @throws NullPointerException if the specified element is null + */ + public boolean removeFirstOccurrence(Object o) { + checkNotNull(o); + for (Node p = first(); p != null; p = succ(p)) { + E item = p.item; + if (item != null && o.equals(item) && p.casItem(item, null)) { + unlink(p); + return true; + } + } + return false; + } + + /** + * Removes the last element {@code e} such that + * {@code o.equals(e)}, if such an element exists in this deque. + * If the deque does not contain the element, it is unchanged. + * + * @param o element to be removed from this deque, if present + * @return {@code true} if the deque contained the specified element + * @throws NullPointerException if the specified element is null + */ + public boolean removeLastOccurrence(Object o) { + checkNotNull(o); + for (Node p = last(); p != null; p = pred(p)) { + E item = p.item; + if (item != null && o.equals(item) && p.casItem(item, null)) { + unlink(p); + return true; + } + } + return false; + } + + /** + * Returns {@code true} if this deque contains at least one + * element {@code e} such that {@code o.equals(e)}. + * + * @param o element whose presence in this deque is to be tested + * @return {@code true} if this deque contains the specified element + */ + public boolean contains(Object o) { + if (o == null) return false; + for (Node p = first(); p != null; p = succ(p)) { + E item = p.item; + if (item != null && o.equals(item)) + return true; + } + return false; + } + + /** + * Returns {@code true} if this collection contains no elements. + * + * @return {@code true} if this collection contains no elements + */ + public boolean isEmpty() { + return peekFirst() == null; + } + + /** + * Returns the number of elements in this deque. If this deque + * contains more than {@code Integer.MAX_VALUE} elements, it + * returns {@code Integer.MAX_VALUE}. + * + *

Beware that, unlike in most collections, this method is + * NOT a constant-time operation. Because of the + * asynchronous nature of these deques, determining the current + * number of elements requires traversing them all to count them. + * Additionally, it is possible for the size to change during + * execution of this method, in which case the returned result + * will be inaccurate. Thus, this method is typically not very + * useful in concurrent applications. + * + * @return the number of elements in this deque + */ + public int size() { + int count = 0; + for (Node p = first(); p != null; p = succ(p)) + if (p.item != null) + // Collection.size() spec says to max out + if (++count == Integer.MAX_VALUE) + break; + return count; + } + + /** + * Removes the first element {@code e} such that + * {@code o.equals(e)}, if such an element exists in this deque. + * If the deque does not contain the element, it is unchanged. + * + * @param o element to be removed from this deque, if present + * @return {@code true} if the deque contained the specified element + * @throws NullPointerException if the specified element is null + */ + public boolean remove(Object o) { + return removeFirstOccurrence(o); + } + + /** + * Appends all of the elements in the specified collection to the end of + * this deque, in the order that they are returned by the specified + * collection's iterator. Attempts to {@code addAll} of a deque to + * itself result in {@code IllegalArgumentException}. + * + * @param c the elements to be inserted into this deque + * @return {@code true} if this deque changed as a result of the call + * @throws NullPointerException if the specified collection or any + * of its elements are null + * @throws IllegalArgumentException if the collection is this deque + */ + public boolean addAll(Collection c) { + if (c == this) + // As historically specified in AbstractQueue#addAll + throw new IllegalArgumentException(); + + // Copy c into a private chain of Nodes + Node beginningOfTheEnd = null, last = null; + for (E e : c) { + checkNotNull(e); + Node newNode = new Node(e); + if (beginningOfTheEnd == null) + beginningOfTheEnd = last = newNode; + else { + last.lazySetNext(newNode); + newNode.lazySetPrev(last); + last = newNode; + } + } + if (beginningOfTheEnd == null) + return false; + + // Atomically append the chain at the tail of this collection + restartFromTail: + for (;;) + for (Node t = tail, p = t, q;;) { + if ((q = p.next) != null && + (q = (p = q).next) != null) + // Check for tail updates every other hop. + // If p == q, we are sure to follow tail instead. + p = (t != (t = tail)) ? t : q; + else if (p.prev == p) // NEXT_TERMINATOR + continue restartFromTail; + else { + // p is last node + beginningOfTheEnd.lazySetPrev(p); // CAS piggyback + if (p.casNext(null, beginningOfTheEnd)) { + // Successful CAS is the linearization point + // for all elements to be added to this deque. + if (!casTail(t, last)) { + // Try a little harder to update tail, + // since we may be adding many elements. + t = tail; + if (last.next == null) + casTail(t, last); + } + return true; + } + // Lost CAS race to another thread; re-read next + } + } + } + + /** + * Removes all of the elements from this deque. + */ + public void clear() { + while (pollFirst() != null) + ; + } + + /** + * Returns an array containing all of the elements in this deque, in + * proper sequence (from first to last element). + * + *

The returned array will be "safe" in that no references to it are + * maintained by this deque. (In other words, this method must allocate + * a new array). The caller is thus free to modify the returned array. + * + *

This method acts as bridge between array-based and collection-based + * APIs. + * + * @return an array containing all of the elements in this deque + */ + public Object[] toArray() { + return toArrayList().toArray(); + } + + /** + * Returns an array containing all of the elements in this deque, + * in proper sequence (from first to last element); the runtime + * type of the returned array is that of the specified array. If + * the deque fits in the specified array, it is returned therein. + * Otherwise, a new array is allocated with the runtime type of + * the specified array and the size of this deque. + * + *

If this deque fits in the specified array with room to spare + * (i.e., the array has more elements than this deque), the element in + * the array immediately following the end of the deque is set to + * {@code null}. + * + *

Like the {@link #toArray()} method, this method acts as + * bridge between array-based and collection-based APIs. Further, + * this method allows precise control over the runtime type of the + * output array, and may, under certain circumstances, be used to + * save allocation costs. + * + *

Suppose {@code x} is a deque known to contain only strings. + * The following code can be used to dump the deque into a newly + * allocated array of {@code String}: + * + *

+     *     String[] y = x.toArray(new String[0]);
+ * + * Note that {@code toArray(new Object[0])} is identical in function to + * {@code toArray()}. + * + * @param a the array into which the elements of the deque are to + * be stored, if it is big enough; otherwise, a new array of the + * same runtime type is allocated for this purpose + * @return an array containing all of the elements in this deque + * @throws ArrayStoreException if the runtime type of the specified array + * is not a supertype of the runtime type of every element in + * this deque + * @throws NullPointerException if the specified array is null + */ + public T[] toArray(T[] a) { + return toArrayList().toArray(a); + } + + /** + * Returns an iterator over the elements in this deque in proper sequence. + * The elements will be returned in order from first (head) to last (tail). + * + *

The returned iterator is a "weakly consistent" iterator that + * will never throw {@link java.util.ConcurrentModificationException + * ConcurrentModificationException}, and guarantees to traverse + * elements as they existed upon construction of the iterator, and + * may (but is not guaranteed to) reflect any modifications + * subsequent to construction. + * + * @return an iterator over the elements in this deque in proper sequence + */ + public Iterator iterator() { + return new Itr(); + } + + /** + * Returns an iterator over the elements in this deque in reverse + * sequential order. The elements will be returned in order from + * last (tail) to first (head). + * + *

The returned iterator is a "weakly consistent" iterator that + * will never throw {@link java.util.ConcurrentModificationException + * ConcurrentModificationException}, and guarantees to traverse + * elements as they existed upon construction of the iterator, and + * may (but is not guaranteed to) reflect any modifications + * subsequent to construction. + * + * @return an iterator over the elements in this deque in reverse order + */ + public Iterator descendingIterator() { + return new DescendingItr(); + } + + private abstract class AbstractItr implements Iterator { + /** + * Next node to return item for. + */ + private Node nextNode; + + /** + * nextItem holds on to item fields because once we claim + * that an element exists in hasNext(), we must return it in + * the following next() call even if it was in the process of + * being removed when hasNext() was called. + */ + private E nextItem; + + /** + * Node returned by most recent call to next. Needed by remove. + * Reset to null if this element is deleted by a call to remove. + */ + private Node lastRet; + + abstract Node startNode(); + abstract Node nextNode(Node p); + + AbstractItr() { + advance(); + } + + /** + * Sets nextNode and nextItem to next valid node, or to null + * if no such. + */ + private void advance() { + lastRet = nextNode; + + Node p = (nextNode == null) ? startNode() : nextNode(nextNode); + for (;; p = nextNode(p)) { + if (p == null) { + // p might be active end or TERMINATOR node; both are OK + nextNode = null; + nextItem = null; + break; + } + E item = p.item; + if (item != null) { + nextNode = p; + nextItem = item; + break; + } + } + } + + public boolean hasNext() { + return nextItem != null; + } + + public E next() { + E item = nextItem; + if (item == null) throw new NoSuchElementException(); + advance(); + return item; + } + + public void remove() { + Node l = lastRet; + if (l == null) throw new IllegalStateException(); + l.item = null; + unlink(l); + lastRet = null; + } + } + + /** Forward iterator */ + private class Itr extends AbstractItr { + Node startNode() { return first(); } + Node nextNode(Node p) { return succ(p); } + } + + /** Descending iterator */ + private class DescendingItr extends AbstractItr { + Node startNode() { return last(); } + Node nextNode(Node p) { return pred(p); } + } + + /** + * Saves the state to a stream (that is, serializes it). + * + * @serialData All of the elements (each an {@code E}) in + * the proper order, followed by a null + * @param s the stream + */ + private void writeObject(java.io.ObjectOutputStream s) + throws java.io.IOException { + + // Write out any hidden stuff + s.defaultWriteObject(); + + // Write out all elements in the proper order. + for (Node p = first(); p != null; p = succ(p)) { + E item = p.item; + if (item != null) + s.writeObject(item); + } + + // Use trailing null as sentinel + s.writeObject(null); + } + + /** + * Reconstitutes the instance from a stream (that is, deserializes it). + * @param s the stream + */ + private void readObject(java.io.ObjectInputStream s) + throws java.io.IOException, ClassNotFoundException { + s.defaultReadObject(); + + // Read in elements until trailing null sentinel found + Node h = null, t = null; + Object item; + while ((item = s.readObject()) != null) { + @SuppressWarnings("unchecked") + Node newNode = new Node((E) item); + if (h == null) + h = t = newNode; + else { + t.lazySetNext(newNode); + newNode.lazySetPrev(t); + t = newNode; + } + } + initHeadTail(h, t); + } + + + private boolean casHead(Node cmp, Node val) { + return UNSAFE.compareAndSwapObject(this, headOffset, cmp, val); + } + + private boolean casTail(Node cmp, Node val) { + return UNSAFE.compareAndSwapObject(this, tailOffset, cmp, val); + } + + // Unsafe mechanics + + private static final sun.misc.Unsafe UNSAFE; + private static final long headOffset; + private static final long tailOffset; + static { + PREV_TERMINATOR = new Node(); + PREV_TERMINATOR.next = PREV_TERMINATOR; + NEXT_TERMINATOR = new Node(); + NEXT_TERMINATOR.prev = NEXT_TERMINATOR; + try { + UNSAFE = sun.misc.Unsafe.getUnsafe(); + Class k = ConcurrentLinkedDeque.class; + headOffset = UNSAFE.objectFieldOffset + (k.getDeclaredField("head")); + tailOffset = UNSAFE.objectFieldOffset + (k.getDeclaredField("tail")); + } catch (Exception e) { + throw new Error(e); + } + } +} diff -r e1953d8b8338 -r c8af252ea9eb rt/emul/compact/src/main/java/java/util/concurrent/ConcurrentLinkedQueue.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/ConcurrentLinkedQueue.java Sat Mar 19 10:48:29 2016 +0100 @@ -0,0 +1,835 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea and Martin Buchholz with assistance from members of + * JCP JSR-166 Expert Group and released to the public domain, as explained + * at http://creativecommons.org/publicdomain/zero/1.0/ + */ + +package java.util.concurrent; + +import java.util.AbstractQueue; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.NoSuchElementException; +import java.util.Queue; + +/** + * An unbounded thread-safe {@linkplain Queue queue} based on linked nodes. + * This queue orders elements FIFO (first-in-first-out). + * The head of the queue is that element that has been on the + * queue the longest time. + * The tail of the queue is that element that has been on the + * queue the shortest time. New elements + * are inserted at the tail of the queue, and the queue retrieval + * operations obtain elements at the head of the queue. + * A {@code ConcurrentLinkedQueue} is an appropriate choice when + * many threads will share access to a common collection. + * Like most other concurrent collection implementations, this class + * does not permit the use of {@code null} elements. + * + *

This implementation employs an efficient "wait-free" + * algorithm based on one described in Simple, + * Fast, and Practical Non-Blocking and Blocking Concurrent Queue + * Algorithms by Maged M. Michael and Michael L. Scott. + * + *

Iterators are weakly consistent, returning elements + * reflecting the state of the queue at some point at or since the + * creation of the iterator. They do not throw {@link + * java.util.ConcurrentModificationException}, and may proceed concurrently + * with other operations. Elements contained in the queue since the creation + * of the iterator will be returned exactly once. + * + *

Beware that, unlike in most collections, the {@code size} method + * is NOT a constant-time operation. Because of the + * asynchronous nature of these queues, determining the current number + * of elements requires a traversal of the elements, and so may report + * inaccurate results if this collection is modified during traversal. + * Additionally, the bulk operations {@code addAll}, + * {@code removeAll}, {@code retainAll}, {@code containsAll}, + * {@code equals}, and {@code toArray} are not guaranteed + * to be performed atomically. For example, an iterator operating + * concurrently with an {@code addAll} operation might view only some + * of the added elements. + * + *

This class and its iterator implement all of the optional + * methods of the {@link Queue} and {@link Iterator} interfaces. + * + *

Memory consistency effects: As with other concurrent + * collections, actions in a thread prior to placing an object into a + * {@code ConcurrentLinkedQueue} + * happen-before + * actions subsequent to the access or removal of that element from + * the {@code ConcurrentLinkedQueue} in another thread. + * + *

This class is a member of the + * + * Java Collections Framework. + * + * @since 1.5 + * @author Doug Lea + * @param the type of elements held in this collection + * + */ +public class ConcurrentLinkedQueue extends AbstractQueue + implements Queue, java.io.Serializable { + private static final long serialVersionUID = 196745693267521676L; + + /* + * This is a modification of the Michael & Scott algorithm, + * adapted for a garbage-collected environment, with support for + * interior node deletion (to support remove(Object)). For + * explanation, read the paper. + * + * Note that like most non-blocking algorithms in this package, + * this implementation relies on the fact that in garbage + * collected systems, there is no possibility of ABA problems due + * to recycled nodes, so there is no need to use "counted + * pointers" or related techniques seen in versions used in + * non-GC'ed settings. + * + * The fundamental invariants are: + * - There is exactly one (last) Node with a null next reference, + * which is CASed when enqueueing. This last Node can be + * reached in O(1) time from tail, but tail is merely an + * optimization - it can always be reached in O(N) time from + * head as well. + * - The elements contained in the queue are the non-null items in + * Nodes that are reachable from head. CASing the item + * reference of a Node to null atomically removes it from the + * queue. Reachability of all elements from head must remain + * true even in the case of concurrent modifications that cause + * head to advance. A dequeued Node may remain in use + * indefinitely due to creation of an Iterator or simply a + * poll() that has lost its time slice. + * + * The above might appear to imply that all Nodes are GC-reachable + * from a predecessor dequeued Node. That would cause two problems: + * - allow a rogue Iterator to cause unbounded memory retention + * - cause cross-generational linking of old Nodes to new Nodes if + * a Node was tenured while live, which generational GCs have a + * hard time dealing with, causing repeated major collections. + * However, only non-deleted Nodes need to be reachable from + * dequeued Nodes, and reachability does not necessarily have to + * be of the kind understood by the GC. We use the trick of + * linking a Node that has just been dequeued to itself. Such a + * self-link implicitly means to advance to head. + * + * Both head and tail are permitted to lag. In fact, failing to + * update them every time one could is a significant optimization + * (fewer CASes). As with LinkedTransferQueue (see the internal + * documentation for that class), we use a slack threshold of two; + * that is, we update head/tail when the current pointer appears + * to be two or more steps away from the first/last node. + * + * Since head and tail are updated concurrently and independently, + * it is possible for tail to lag behind head (why not)? + * + * CASing a Node's item reference to null atomically removes the + * element from the queue. Iterators skip over Nodes with null + * items. Prior implementations of this class had a race between + * poll() and remove(Object) where the same element would appear + * to be successfully removed by two concurrent operations. The + * method remove(Object) also lazily unlinks deleted Nodes, but + * this is merely an optimization. + * + * When constructing a Node (before enqueuing it) we avoid paying + * for a volatile write to item by using Unsafe.putObject instead + * of a normal write. This allows the cost of enqueue to be + * "one-and-a-half" CASes. + * + * Both head and tail may or may not point to a Node with a + * non-null item. If the queue is empty, all items must of course + * be null. Upon creation, both head and tail refer to a dummy + * Node with null item. Both head and tail are only updated using + * CAS, so they never regress, although again this is merely an + * optimization. + */ + + private static class Node { + volatile E item; + volatile Node next; + + /** + * Constructs a new node. Uses relaxed write because item can + * only be seen after publication via casNext. + */ + Node(E item) { + UNSAFE.putObject(this, itemOffset, item); + } + + boolean casItem(E cmp, E val) { + return UNSAFE.compareAndSwapObject(this, itemOffset, cmp, val); + } + + void lazySetNext(Node val) { + UNSAFE.putOrderedObject(this, nextOffset, val); + } + + boolean casNext(Node cmp, Node val) { + return UNSAFE.compareAndSwapObject(this, nextOffset, cmp, val); + } + + // Unsafe mechanics + + private static final sun.misc.Unsafe UNSAFE; + private static final long itemOffset; + private static final long nextOffset; + + static { + try { + UNSAFE = sun.misc.Unsafe.getUnsafe(); + Class k = Node.class; + itemOffset = UNSAFE.objectFieldOffset + (k.getDeclaredField("item")); + nextOffset = UNSAFE.objectFieldOffset + (k.getDeclaredField("next")); + } catch (Exception e) { + throw new Error(e); + } + } + } + + /** + * A node from which the first live (non-deleted) node (if any) + * can be reached in O(1) time. + * Invariants: + * - all live nodes are reachable from head via succ() + * - head != null + * - (tmp = head).next != tmp || tmp != head + * Non-invariants: + * - head.item may or may not be null. + * - it is permitted for tail to lag behind head, that is, for tail + * to not be reachable from head! + */ + private transient volatile Node head; + + /** + * A node from which the last node on list (that is, the unique + * node with node.next == null) can be reached in O(1) time. + * Invariants: + * - the last node is always reachable from tail via succ() + * - tail != null + * Non-invariants: + * - tail.item may or may not be null. + * - it is permitted for tail to lag behind head, that is, for tail + * to not be reachable from head! + * - tail.next may or may not be self-pointing to tail. + */ + private transient volatile Node tail; + + + /** + * Creates a {@code ConcurrentLinkedQueue} that is initially empty. + */ + public ConcurrentLinkedQueue() { + head = tail = new Node(null); + } + + /** + * Creates a {@code ConcurrentLinkedQueue} + * initially containing the elements of the given collection, + * added in traversal order of the collection's iterator. + * + * @param c the collection of elements to initially contain + * @throws NullPointerException if the specified collection or any + * of its elements are null + */ + public ConcurrentLinkedQueue(Collection c) { + Node h = null, t = null; + for (E e : c) { + checkNotNull(e); + Node newNode = new Node(e); + if (h == null) + h = t = newNode; + else { + t.lazySetNext(newNode); + t = newNode; + } + } + if (h == null) + h = t = new Node(null); + head = h; + tail = t; + } + + // Have to override just to update the javadoc + + /** + * Inserts the specified element at the tail of this queue. + * As the queue is unbounded, this method will never throw + * {@link IllegalStateException} or return {@code false}. + * + * @return {@code true} (as specified by {@link Collection#add}) + * @throws NullPointerException if the specified element is null + */ + public boolean add(E e) { + return offer(e); + } + + /** + * Try to CAS head to p. If successful, repoint old head to itself + * as sentinel for succ(), below. + */ + final void updateHead(Node h, Node p) { + if (h != p && casHead(h, p)) + h.lazySetNext(h); + } + + /** + * Returns the successor of p, or the head node if p.next has been + * linked to self, which will only be true if traversing with a + * stale pointer that is now off the list. + */ + final Node succ(Node p) { + Node next = p.next; + return (p == next) ? head : next; + } + + /** + * Inserts the specified element at the tail of this queue. + * As the queue is unbounded, this method will never return {@code false}. + * + * @return {@code true} (as specified by {@link Queue#offer}) + * @throws NullPointerException if the specified element is null + */ + public boolean offer(E e) { + checkNotNull(e); + final Node newNode = new Node(e); + + for (Node t = tail, p = t;;) { + Node q = p.next; + if (q == null) { + // p is last node + if (p.casNext(null, newNode)) { + // Successful CAS is the linearization point + // for e to become an element of this queue, + // and for newNode to become "live". + if (p != t) // hop two nodes at a time + casTail(t, newNode); // Failure is OK. + return true; + } + // Lost CAS race to another thread; re-read next + } + else if (p == q) + // We have fallen off list. If tail is unchanged, it + // will also be off-list, in which case we need to + // jump to head, from which all live nodes are always + // reachable. Else the new tail is a better bet. + p = (t != (t = tail)) ? t : head; + else + // Check for tail updates after two hops. + p = (p != t && t != (t = tail)) ? t : q; + } + } + + public E poll() { + restartFromHead: + for (;;) { + for (Node h = head, p = h, q;;) { + E item = p.item; + + if (item != null && p.casItem(item, null)) { + // Successful CAS is the linearization point + // for item to be removed from this queue. + if (p != h) // hop two nodes at a time + updateHead(h, ((q = p.next) != null) ? q : p); + return item; + } + else if ((q = p.next) == null) { + updateHead(h, p); + return null; + } + else if (p == q) + continue restartFromHead; + else + p = q; + } + } + } + + public E peek() { + restartFromHead: + for (;;) { + for (Node h = head, p = h, q;;) { + E item = p.item; + if (item != null || (q = p.next) == null) { + updateHead(h, p); + return item; + } + else if (p == q) + continue restartFromHead; + else + p = q; + } + } + } + + /** + * Returns the first live (non-deleted) node on list, or null if none. + * This is yet another variant of poll/peek; here returning the + * first node, not element. We could make peek() a wrapper around + * first(), but that would cost an extra volatile read of item, + * and the need to add a retry loop to deal with the possibility + * of losing a race to a concurrent poll(). + */ + Node first() { + restartFromHead: + for (;;) { + for (Node h = head, p = h, q;;) { + boolean hasItem = (p.item != null); + if (hasItem || (q = p.next) == null) { + updateHead(h, p); + return hasItem ? p : null; + } + else if (p == q) + continue restartFromHead; + else + p = q; + } + } + } + + /** + * Returns {@code true} if this queue contains no elements. + * + * @return {@code true} if this queue contains no elements + */ + public boolean isEmpty() { + return first() == null; + } + + /** + * Returns the number of elements in this queue. If this queue + * contains more than {@code Integer.MAX_VALUE} elements, returns + * {@code Integer.MAX_VALUE}. + * + *

Beware that, unlike in most collections, this method is + * NOT a constant-time operation. Because of the + * asynchronous nature of these queues, determining the current + * number of elements requires an O(n) traversal. + * Additionally, if elements are added or removed during execution + * of this method, the returned result may be inaccurate. Thus, + * this method is typically not very useful in concurrent + * applications. + * + * @return the number of elements in this queue + */ + public int size() { + int count = 0; + for (Node p = first(); p != null; p = succ(p)) + if (p.item != null) + // Collection.size() spec says to max out + if (++count == Integer.MAX_VALUE) + break; + return count; + } + + /** + * Returns {@code true} if this queue contains the specified element. + * More formally, returns {@code true} if and only if this queue contains + * at least one element {@code e} such that {@code o.equals(e)}. + * + * @param o object to be checked for containment in this queue + * @return {@code true} if this queue contains the specified element + */ + public boolean contains(Object o) { + if (o == null) return false; + for (Node p = first(); p != null; p = succ(p)) { + E item = p.item; + if (item != null && o.equals(item)) + return true; + } + return false; + } + + /** + * Removes a single instance of the specified element from this queue, + * if it is present. More formally, removes an element {@code e} such + * that {@code o.equals(e)}, if this queue contains one or more such + * elements. + * Returns {@code true} if this queue contained the specified element + * (or equivalently, if this queue changed as a result of the call). + * + * @param o element to be removed from this queue, if present + * @return {@code true} if this queue changed as a result of the call + */ + public boolean remove(Object o) { + if (o == null) return false; + Node pred = null; + for (Node p = first(); p != null; p = succ(p)) { + E item = p.item; + if (item != null && + o.equals(item) && + p.casItem(item, null)) { + Node next = succ(p); + if (pred != null && next != null) + pred.casNext(p, next); + return true; + } + pred = p; + } + return false; + } + + /** + * Appends all of the elements in the specified collection to the end of + * this queue, in the order that they are returned by the specified + * collection's iterator. Attempts to {@code addAll} of a queue to + * itself result in {@code IllegalArgumentException}. + * + * @param c the elements to be inserted into this queue + * @return {@code true} if this queue changed as a result of the call + * @throws NullPointerException if the specified collection or any + * of its elements are null + * @throws IllegalArgumentException if the collection is this queue + */ + public boolean addAll(Collection c) { + if (c == this) + // As historically specified in AbstractQueue#addAll + throw new IllegalArgumentException(); + + // Copy c into a private chain of Nodes + Node beginningOfTheEnd = null, last = null; + for (E e : c) { + checkNotNull(e); + Node newNode = new Node(e); + if (beginningOfTheEnd == null) + beginningOfTheEnd = last = newNode; + else { + last.lazySetNext(newNode); + last = newNode; + } + } + if (beginningOfTheEnd == null) + return false; + + // Atomically append the chain at the tail of this collection + for (Node t = tail, p = t;;) { + Node q = p.next; + if (q == null) { + // p is last node + if (p.casNext(null, beginningOfTheEnd)) { + // Successful CAS is the linearization point + // for all elements to be added to this queue. + if (!casTail(t, last)) { + // Try a little harder to update tail, + // since we may be adding many elements. + t = tail; + if (last.next == null) + casTail(t, last); + } + return true; + } + // Lost CAS race to another thread; re-read next + } + else if (p == q) + // We have fallen off list. If tail is unchanged, it + // will also be off-list, in which case we need to + // jump to head, from which all live nodes are always + // reachable. Else the new tail is a better bet. + p = (t != (t = tail)) ? t : head; + else + // Check for tail updates after two hops. + p = (p != t && t != (t = tail)) ? t : q; + } + } + + /** + * Returns an array containing all of the elements in this queue, in + * proper sequence. + * + *

The returned array will be "safe" in that no references to it are + * maintained by this queue. (In other words, this method must allocate + * a new array). The caller is thus free to modify the returned array. + * + *

This method acts as bridge between array-based and collection-based + * APIs. + * + * @return an array containing all of the elements in this queue + */ + public Object[] toArray() { + // Use ArrayList to deal with resizing. + ArrayList al = new ArrayList(); + for (Node p = first(); p != null; p = succ(p)) { + E item = p.item; + if (item != null) + al.add(item); + } + return al.toArray(); + } + + /** + * Returns an array containing all of the elements in this queue, in + * proper sequence; the runtime type of the returned array is that of + * the specified array. If the queue fits in the specified array, it + * is returned therein. Otherwise, a new array is allocated with the + * runtime type of the specified array and the size of this queue. + * + *

If this queue fits in the specified array with room to spare + * (i.e., the array has more elements than this queue), the element in + * the array immediately following the end of the queue is set to + * {@code null}. + * + *

Like the {@link #toArray()} method, this method acts as bridge between + * array-based and collection-based APIs. Further, this method allows + * precise control over the runtime type of the output array, and may, + * under certain circumstances, be used to save allocation costs. + * + *

Suppose {@code x} is a queue known to contain only strings. + * The following code can be used to dump the queue into a newly + * allocated array of {@code String}: + * + *

+     *     String[] y = x.toArray(new String[0]);
+ * + * Note that {@code toArray(new Object[0])} is identical in function to + * {@code toArray()}. + * + * @param a the array into which the elements of the queue are to + * be stored, if it is big enough; otherwise, a new array of the + * same runtime type is allocated for this purpose + * @return an array containing all of the elements in this queue + * @throws ArrayStoreException if the runtime type of the specified array + * is not a supertype of the runtime type of every element in + * this queue + * @throws NullPointerException if the specified array is null + */ + @SuppressWarnings("unchecked") + public T[] toArray(T[] a) { + // try to use sent-in array + int k = 0; + Node p; + for (p = first(); p != null && k < a.length; p = succ(p)) { + E item = p.item; + if (item != null) + a[k++] = (T)item; + } + if (p == null) { + if (k < a.length) + a[k] = null; + return a; + } + + // If won't fit, use ArrayList version + ArrayList al = new ArrayList(); + for (Node q = first(); q != null; q = succ(q)) { + E item = q.item; + if (item != null) + al.add(item); + } + return al.toArray(a); + } + + /** + * Returns an iterator over the elements in this queue in proper sequence. + * The elements will be returned in order from first (head) to last (tail). + * + *

The returned iterator is a "weakly consistent" iterator that + * will never throw {@link java.util.ConcurrentModificationException + * ConcurrentModificationException}, and guarantees to traverse + * elements as they existed upon construction of the iterator, and + * may (but is not guaranteed to) reflect any modifications + * subsequent to construction. + * + * @return an iterator over the elements in this queue in proper sequence + */ + public Iterator iterator() { + return new Itr(); + } + + private class Itr implements Iterator { + /** + * Next node to return item for. + */ + private Node nextNode; + + /** + * nextItem holds on to item fields because once we claim + * that an element exists in hasNext(), we must return it in + * the following next() call even if it was in the process of + * being removed when hasNext() was called. + */ + private E nextItem; + + /** + * Node of the last returned item, to support remove. + */ + private Node lastRet; + + Itr() { + advance(); + } + + /** + * Moves to next valid node and returns item to return for + * next(), or null if no such. + */ + private E advance() { + lastRet = nextNode; + E x = nextItem; + + Node pred, p; + if (nextNode == null) { + p = first(); + pred = null; + } else { + pred = nextNode; + p = succ(nextNode); + } + + for (;;) { + if (p == null) { + nextNode = null; + nextItem = null; + return x; + } + E item = p.item; + if (item != null) { + nextNode = p; + nextItem = item; + return x; + } else { + // skip over nulls + Node next = succ(p); + if (pred != null && next != null) + pred.casNext(p, next); + p = next; + } + } + } + + public boolean hasNext() { + return nextNode != null; + } + + public E next() { + if (nextNode == null) throw new NoSuchElementException(); + return advance(); + } + + public void remove() { + Node l = lastRet; + if (l == null) throw new IllegalStateException(); + // rely on a future traversal to relink. + l.item = null; + lastRet = null; + } + } + + /** + * Saves the state to a stream (that is, serializes it). + * + * @serialData All of the elements (each an {@code E}) in + * the proper order, followed by a null + * @param s the stream + */ + private void writeObject(java.io.ObjectOutputStream s) + throws java.io.IOException { + + // Write out any hidden stuff + s.defaultWriteObject(); + + // Write out all elements in the proper order. + for (Node p = first(); p != null; p = succ(p)) { + Object item = p.item; + if (item != null) + s.writeObject(item); + } + + // Use trailing null as sentinel + s.writeObject(null); + } + + /** + * Reconstitutes the instance from a stream (that is, deserializes it). + * @param s the stream + */ + private void readObject(java.io.ObjectInputStream s) + throws java.io.IOException, ClassNotFoundException { + s.defaultReadObject(); + + // Read in elements until trailing null sentinel found + Node h = null, t = null; + Object item; + while ((item = s.readObject()) != null) { + @SuppressWarnings("unchecked") + Node newNode = new Node((E) item); + if (h == null) + h = t = newNode; + else { + t.lazySetNext(newNode); + t = newNode; + } + } + if (h == null) + h = t = new Node(null); + head = h; + tail = t; + } + + /** + * Throws NullPointerException if argument is null. + * + * @param v the element + */ + private static void checkNotNull(Object v) { + if (v == null) + throw new NullPointerException(); + } + + private boolean casTail(Node cmp, Node val) { + return UNSAFE.compareAndSwapObject(this, tailOffset, cmp, val); + } + + private boolean casHead(Node cmp, Node val) { + return UNSAFE.compareAndSwapObject(this, headOffset, cmp, val); + } + + // Unsafe mechanics + + private static final sun.misc.Unsafe UNSAFE; + private static final long headOffset; + private static final long tailOffset; + static { + try { + UNSAFE = sun.misc.Unsafe.getUnsafe(); + Class k = ConcurrentLinkedQueue.class; + headOffset = UNSAFE.objectFieldOffset + (k.getDeclaredField("head")); + tailOffset = UNSAFE.objectFieldOffset + (k.getDeclaredField("tail")); + } catch (Exception e) { + throw new Error(e); + } + } +} diff -r e1953d8b8338 -r c8af252ea9eb rt/emul/compact/src/main/java/java/util/concurrent/ConcurrentNavigableMap.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/ConcurrentNavigableMap.java Sat Mar 19 10:48:29 2016 +0100 @@ -0,0 +1,177 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +package java.util.concurrent; +import java.util.*; + +/** + * A {@link ConcurrentMap} supporting {@link NavigableMap} operations, + * and recursively so for its navigable sub-maps. + * + *

This interface is a member of the + * + * Java Collections Framework. + * + * @author Doug Lea + * @param the type of keys maintained by this map + * @param the type of mapped values + * @since 1.6 + */ +public interface ConcurrentNavigableMap + extends ConcurrentMap, NavigableMap +{ + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + * @throws IllegalArgumentException {@inheritDoc} + */ + ConcurrentNavigableMap subMap(K fromKey, boolean fromInclusive, + K toKey, boolean toInclusive); + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + * @throws IllegalArgumentException {@inheritDoc} + */ + ConcurrentNavigableMap headMap(K toKey, boolean inclusive); + + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + * @throws IllegalArgumentException {@inheritDoc} + */ + ConcurrentNavigableMap tailMap(K fromKey, boolean inclusive); + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + * @throws IllegalArgumentException {@inheritDoc} + */ + ConcurrentNavigableMap subMap(K fromKey, K toKey); + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + * @throws IllegalArgumentException {@inheritDoc} + */ + ConcurrentNavigableMap headMap(K toKey); + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + * @throws IllegalArgumentException {@inheritDoc} + */ + ConcurrentNavigableMap tailMap(K fromKey); + + /** + * Returns a reverse order view of the mappings contained in this map. + * The descending map is backed by this map, so changes to the map are + * reflected in the descending map, and vice-versa. + * + *

The returned map has an ordering equivalent to + * {@link Collections#reverseOrder(Comparator) Collections.reverseOrder}(comparator()). + * The expression {@code m.descendingMap().descendingMap()} returns a + * view of {@code m} essentially equivalent to {@code m}. + * + * @return a reverse order view of this map + */ + ConcurrentNavigableMap descendingMap(); + + /** + * Returns a {@link NavigableSet} view of the keys contained in this map. + * The set's iterator returns the keys in ascending order. + * The set is backed by the map, so changes to the map are + * reflected in the set, and vice-versa. The set supports element + * removal, which removes the corresponding mapping from the map, + * via the {@code Iterator.remove}, {@code Set.remove}, + * {@code removeAll}, {@code retainAll}, and {@code clear} + * operations. It does not support the {@code add} or {@code addAll} + * operations. + * + *

The view's {@code iterator} is a "weakly consistent" iterator + * that will never throw {@link ConcurrentModificationException}, + * and guarantees to traverse elements as they existed upon + * construction of the iterator, and may (but is not guaranteed to) + * reflect any modifications subsequent to construction. + * + * @return a navigable set view of the keys in this map + */ + public NavigableSet navigableKeySet(); + + /** + * Returns a {@link NavigableSet} view of the keys contained in this map. + * The set's iterator returns the keys in ascending order. + * The set is backed by the map, so changes to the map are + * reflected in the set, and vice-versa. The set supports element + * removal, which removes the corresponding mapping from the map, + * via the {@code Iterator.remove}, {@code Set.remove}, + * {@code removeAll}, {@code retainAll}, and {@code clear} + * operations. It does not support the {@code add} or {@code addAll} + * operations. + * + *

The view's {@code iterator} is a "weakly consistent" iterator + * that will never throw {@link ConcurrentModificationException}, + * and guarantees to traverse elements as they existed upon + * construction of the iterator, and may (but is not guaranteed to) + * reflect any modifications subsequent to construction. + * + *

This method is equivalent to method {@code navigableKeySet}. + * + * @return a navigable set view of the keys in this map + */ + NavigableSet keySet(); + + /** + * Returns a reverse order {@link NavigableSet} view of the keys contained in this map. + * The set's iterator returns the keys in descending order. + * The set is backed by the map, so changes to the map are + * reflected in the set, and vice-versa. The set supports element + * removal, which removes the corresponding mapping from the map, + * via the {@code Iterator.remove}, {@code Set.remove}, + * {@code removeAll}, {@code retainAll}, and {@code clear} + * operations. It does not support the {@code add} or {@code addAll} + * operations. + * + *

The view's {@code iterator} is a "weakly consistent" iterator + * that will never throw {@link ConcurrentModificationException}, + * and guarantees to traverse elements as they existed upon + * construction of the iterator, and may (but is not guaranteed to) + * reflect any modifications subsequent to construction. + * + * @return a reverse order navigable set view of the keys in this map + */ + public NavigableSet descendingKeySet(); +} diff -r e1953d8b8338 -r c8af252ea9eb rt/emul/compact/src/main/java/java/util/concurrent/ConcurrentSkipListMap.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/ConcurrentSkipListMap.java Sat Mar 19 10:48:29 2016 +0100 @@ -0,0 +1,3119 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +package java.util.concurrent; +import java.util.*; +import java.util.concurrent.atomic.*; + +/** + * A scalable concurrent {@link ConcurrentNavigableMap} implementation. + * The map is sorted according to the {@linkplain Comparable natural + * ordering} of its keys, or by a {@link Comparator} provided at map + * creation time, depending on which constructor is used. + * + *

This class implements a concurrent variant of SkipLists + * providing expected average log(n) time cost for the + * containsKey, get, put and + * remove operations and their variants. Insertion, removal, + * update, and access operations safely execute concurrently by + * multiple threads. Iterators are weakly consistent, returning + * elements reflecting the state of the map at some point at or since + * the creation of the iterator. They do not throw {@link + * ConcurrentModificationException}, and may proceed concurrently with + * other operations. Ascending key ordered views and their iterators + * are faster than descending ones. + * + *

All Map.Entry pairs returned by methods in this class + * and its views represent snapshots of mappings at the time they were + * produced. They do not support the Entry.setValue + * method. (Note however that it is possible to change mappings in the + * associated map using put, putIfAbsent, or + * replace, depending on exactly which effect you need.) + * + *

Beware that, unlike in most collections, the size + * method is not a constant-time operation. Because of the + * asynchronous nature of these maps, determining the current number + * of elements requires a traversal of the elements, and so may report + * inaccurate results if this collection is modified during traversal. + * Additionally, the bulk operations putAll, equals, + * toArray, containsValue, and clear are + * not guaranteed to be performed atomically. For example, an + * iterator operating concurrently with a putAll operation + * might view only some of the added elements. + * + *

This class and its views and iterators implement all of the + * optional methods of the {@link Map} and {@link Iterator} + * interfaces. Like most other concurrent collections, this class does + * not permit the use of null keys or values because some + * null return values cannot be reliably distinguished from the absence of + * elements. + * + *

This class is a member of the + * + * Java Collections Framework. + * + * @author Doug Lea + * @param the type of keys maintained by this map + * @param the type of mapped values + * @since 1.6 + */ +public class ConcurrentSkipListMap extends AbstractMap + implements ConcurrentNavigableMap, + Cloneable, + java.io.Serializable { + /* + * This class implements a tree-like two-dimensionally linked skip + * list in which the index levels are represented in separate + * nodes from the base nodes holding data. There are two reasons + * for taking this approach instead of the usual array-based + * structure: 1) Array based implementations seem to encounter + * more complexity and overhead 2) We can use cheaper algorithms + * for the heavily-traversed index lists than can be used for the + * base lists. Here's a picture of some of the basics for a + * possible list with 2 levels of index: + * + * Head nodes Index nodes + * +-+ right +-+ +-+ + * |2|---------------->| |--------------------->| |->null + * +-+ +-+ +-+ + * | down | | + * v v v + * +-+ +-+ +-+ +-+ +-+ +-+ + * |1|----------->| |->| |------>| |----------->| |------>| |->null + * +-+ +-+ +-+ +-+ +-+ +-+ + * v | | | | | + * Nodes next v v v v v + * +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ + * | |->|A|->|B|->|C|->|D|->|E|->|F|->|G|->|H|->|I|->|J|->|K|->null + * +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ + * + * The base lists use a variant of the HM linked ordered set + * algorithm. See Tim Harris, "A pragmatic implementation of + * non-blocking linked lists" + * http://www.cl.cam.ac.uk/~tlh20/publications.html and Maged + * Michael "High Performance Dynamic Lock-Free Hash Tables and + * List-Based Sets" + * http://www.research.ibm.com/people/m/michael/pubs.htm. The + * basic idea in these lists is to mark the "next" pointers of + * deleted nodes when deleting to avoid conflicts with concurrent + * insertions, and when traversing to keep track of triples + * (predecessor, node, successor) in order to detect when and how + * to unlink these deleted nodes. + * + * Rather than using mark-bits to mark list deletions (which can + * be slow and space-intensive using AtomicMarkedReference), nodes + * use direct CAS'able next pointers. On deletion, instead of + * marking a pointer, they splice in another node that can be + * thought of as standing for a marked pointer (indicating this by + * using otherwise impossible field values). Using plain nodes + * acts roughly like "boxed" implementations of marked pointers, + * but uses new nodes only when nodes are deleted, not for every + * link. This requires less space and supports faster + * traversal. Even if marked references were better supported by + * JVMs, traversal using this technique might still be faster + * because any search need only read ahead one more node than + * otherwise required (to check for trailing marker) rather than + * unmasking mark bits or whatever on each read. + * + * This approach maintains the essential property needed in the HM + * algorithm of changing the next-pointer of a deleted node so + * that any other CAS of it will fail, but implements the idea by + * changing the pointer to point to a different node, not by + * marking it. While it would be possible to further squeeze + * space by defining marker nodes not to have key/value fields, it + * isn't worth the extra type-testing overhead. The deletion + * markers are rarely encountered during traversal and are + * normally quickly garbage collected. (Note that this technique + * would not work well in systems without garbage collection.) + * + * In addition to using deletion markers, the lists also use + * nullness of value fields to indicate deletion, in a style + * similar to typical lazy-deletion schemes. If a node's value is + * null, then it is considered logically deleted and ignored even + * though it is still reachable. This maintains proper control of + * concurrent replace vs delete operations -- an attempted replace + * must fail if a delete beat it by nulling field, and a delete + * must return the last non-null value held in the field. (Note: + * Null, rather than some special marker, is used for value fields + * here because it just so happens to mesh with the Map API + * requirement that method get returns null if there is no + * mapping, which allows nodes to remain concurrently readable + * even when deleted. Using any other marker value here would be + * messy at best.) + * + * Here's the sequence of events for a deletion of node n with + * predecessor b and successor f, initially: + * + * +------+ +------+ +------+ + * ... | b |------>| n |----->| f | ... + * +------+ +------+ +------+ + * + * 1. CAS n's value field from non-null to null. + * From this point on, no public operations encountering + * the node consider this mapping to exist. However, other + * ongoing insertions and deletions might still modify + * n's next pointer. + * + * 2. CAS n's next pointer to point to a new marker node. + * From this point on, no other nodes can be appended to n. + * which avoids deletion errors in CAS-based linked lists. + * + * +------+ +------+ +------+ +------+ + * ... | b |------>| n |----->|marker|------>| f | ... + * +------+ +------+ +------+ +------+ + * + * 3. CAS b's next pointer over both n and its marker. + * From this point on, no new traversals will encounter n, + * and it can eventually be GCed. + * +------+ +------+ + * ... | b |----------------------------------->| f | ... + * +------+ +------+ + * + * A failure at step 1 leads to simple retry due to a lost race + * with another operation. Steps 2-3 can fail because some other + * thread noticed during a traversal a node with null value and + * helped out by marking and/or unlinking. This helping-out + * ensures that no thread can become stuck waiting for progress of + * the deleting thread. The use of marker nodes slightly + * complicates helping-out code because traversals must track + * consistent reads of up to four nodes (b, n, marker, f), not + * just (b, n, f), although the next field of a marker is + * immutable, and once a next field is CAS'ed to point to a + * marker, it never again changes, so this requires less care. + * + * Skip lists add indexing to this scheme, so that the base-level + * traversals start close to the locations being found, inserted + * or deleted -- usually base level traversals only traverse a few + * nodes. This doesn't change the basic algorithm except for the + * need to make sure base traversals start at predecessors (here, + * b) that are not (structurally) deleted, otherwise retrying + * after processing the deletion. + * + * Index levels are maintained as lists with volatile next fields, + * using CAS to link and unlink. Races are allowed in index-list + * operations that can (rarely) fail to link in a new index node + * or delete one. (We can't do this of course for data nodes.) + * However, even when this happens, the index lists remain sorted, + * so correctly serve as indices. This can impact performance, + * but since skip lists are probabilistic anyway, the net result + * is that under contention, the effective "p" value may be lower + * than its nominal value. And race windows are kept small enough + * that in practice these failures are rare, even under a lot of + * contention. + * + * The fact that retries (for both base and index lists) are + * relatively cheap due to indexing allows some minor + * simplifications of retry logic. Traversal restarts are + * performed after most "helping-out" CASes. This isn't always + * strictly necessary, but the implicit backoffs tend to help + * reduce other downstream failed CAS's enough to outweigh restart + * cost. This worsens the worst case, but seems to improve even + * highly contended cases. + * + * Unlike most skip-list implementations, index insertion and + * deletion here require a separate traversal pass occuring after + * the base-level action, to add or remove index nodes. This adds + * to single-threaded overhead, but improves contended + * multithreaded performance by narrowing interference windows, + * and allows deletion to ensure that all index nodes will be made + * unreachable upon return from a public remove operation, thus + * avoiding unwanted garbage retention. This is more important + * here than in some other data structures because we cannot null + * out node fields referencing user keys since they might still be + * read by other ongoing traversals. + * + * Indexing uses skip list parameters that maintain good search + * performance while using sparser-than-usual indices: The + * hardwired parameters k=1, p=0.5 (see method randomLevel) mean + * that about one-quarter of the nodes have indices. Of those that + * do, half have one level, a quarter have two, and so on (see + * Pugh's Skip List Cookbook, sec 3.4). The expected total space + * requirement for a map is slightly less than for the current + * implementation of java.util.TreeMap. + * + * Changing the level of the index (i.e, the height of the + * tree-like structure) also uses CAS. The head index has initial + * level/height of one. Creation of an index with height greater + * than the current level adds a level to the head index by + * CAS'ing on a new top-most head. To maintain good performance + * after a lot of removals, deletion methods heuristically try to + * reduce the height if the topmost levels appear to be empty. + * This may encounter races in which it possible (but rare) to + * reduce and "lose" a level just as it is about to contain an + * index (that will then never be encountered). This does no + * structural harm, and in practice appears to be a better option + * than allowing unrestrained growth of levels. + * + * The code for all this is more verbose than you'd like. Most + * operations entail locating an element (or position to insert an + * element). The code to do this can't be nicely factored out + * because subsequent uses require a snapshot of predecessor + * and/or successor and/or value fields which can't be returned + * all at once, at least not without creating yet another object + * to hold them -- creating such little objects is an especially + * bad idea for basic internal search operations because it adds + * to GC overhead. (This is one of the few times I've wished Java + * had macros.) Instead, some traversal code is interleaved within + * insertion and removal operations. The control logic to handle + * all the retry conditions is sometimes twisty. Most search is + * broken into 2 parts. findPredecessor() searches index nodes + * only, returning a base-level predecessor of the key. findNode() + * finishes out the base-level search. Even with this factoring, + * there is a fair amount of near-duplication of code to handle + * variants. + * + * For explanation of algorithms sharing at least a couple of + * features with this one, see Mikhail Fomitchev's thesis + * (http://www.cs.yorku.ca/~mikhail/), Keir Fraser's thesis + * (http://www.cl.cam.ac.uk/users/kaf24/), and Hakan Sundell's + * thesis (http://www.cs.chalmers.se/~phs/). + * + * Given the use of tree-like index nodes, you might wonder why + * this doesn't use some kind of search tree instead, which would + * support somewhat faster search operations. The reason is that + * there are no known efficient lock-free insertion and deletion + * algorithms for search trees. The immutability of the "down" + * links of index nodes (as opposed to mutable "left" fields in + * true trees) makes this tractable using only CAS operations. + * + * Notation guide for local variables + * Node: b, n, f for predecessor, node, successor + * Index: q, r, d for index node, right, down. + * t for another index node + * Head: h + * Levels: j + * Keys: k, key + * Values: v, value + * Comparisons: c + */ + + private static final long serialVersionUID = -8627078645895051609L; + + /** + * Generates the initial random seed for the cheaper per-instance + * random number generators used in randomLevel. + */ + private static final Random seedGenerator = new Random(); + + /** + * Special value used to identify base-level header + */ + private static final Object BASE_HEADER = new Object(); + + /** + * The topmost head index of the skiplist. + */ + private transient volatile HeadIndex head; + + /** + * The comparator used to maintain order in this map, or null + * if using natural ordering. + * @serial + */ + private final Comparator comparator; + + /** + * Seed for simple random number generator. Not volatile since it + * doesn't matter too much if different threads don't see updates. + */ + private transient int randomSeed; + + /** Lazily initialized key set */ + private transient KeySet keySet; + /** Lazily initialized entry set */ + private transient EntrySet entrySet; + /** Lazily initialized values collection */ + private transient Values values; + /** Lazily initialized descending key set */ + private transient ConcurrentNavigableMap descendingMap; + + /** + * Initializes or resets state. Needed by constructors, clone, + * clear, readObject. and ConcurrentSkipListSet.clone. + * (Note that comparator must be separately initialized.) + */ + final void initialize() { + keySet = null; + entrySet = null; + values = null; + descendingMap = null; + randomSeed = seedGenerator.nextInt() | 0x0100; // ensure nonzero + head = new HeadIndex(new Node(null, BASE_HEADER, null), + null, null, 1); + } + + /** + * compareAndSet head node + */ + private boolean casHead(HeadIndex cmp, HeadIndex val) { + return UNSAFE.compareAndSwapObject(this, headOffset, cmp, val); + } + + /* ---------------- Nodes -------------- */ + + /** + * Nodes hold keys and values, and are singly linked in sorted + * order, possibly with some intervening marker nodes. The list is + * headed by a dummy node accessible as head.node. The value field + * is declared only as Object because it takes special non-V + * values for marker and header nodes. + */ + static final class Node { + final K key; + volatile Object value; + volatile Node next; + + /** + * Creates a new regular node. + */ + Node(K key, Object value, Node next) { + this.key = key; + this.value = value; + this.next = next; + } + + /** + * Creates a new marker node. A marker is distinguished by + * having its value field point to itself. Marker nodes also + * have null keys, a fact that is exploited in a few places, + * but this doesn't distinguish markers from the base-level + * header node (head.node), which also has a null key. + */ + Node(Node next) { + this.key = null; + this.value = this; + this.next = next; + } + + /** + * compareAndSet value field + */ + boolean casValue(Object cmp, Object val) { + return UNSAFE.compareAndSwapObject(this, valueOffset, cmp, val); + } + + /** + * compareAndSet next field + */ + boolean casNext(Node cmp, Node val) { + return UNSAFE.compareAndSwapObject(this, nextOffset, cmp, val); + } + + /** + * Returns true if this node is a marker. This method isn't + * actually called in any current code checking for markers + * because callers will have already read value field and need + * to use that read (not another done here) and so directly + * test if value points to node. + * @param n a possibly null reference to a node + * @return true if this node is a marker node + */ + boolean isMarker() { + return value == this; + } + + /** + * Returns true if this node is the header of base-level list. + * @return true if this node is header node + */ + boolean isBaseHeader() { + return value == BASE_HEADER; + } + + /** + * Tries to append a deletion marker to this node. + * @param f the assumed current successor of this node + * @return true if successful + */ + boolean appendMarker(Node f) { + return casNext(f, new Node(f)); + } + + /** + * Helps out a deletion by appending marker or unlinking from + * predecessor. This is called during traversals when value + * field seen to be null. + * @param b predecessor + * @param f successor + */ + void helpDelete(Node b, Node f) { + /* + * Rechecking links and then doing only one of the + * help-out stages per call tends to minimize CAS + * interference among helping threads. + */ + if (f == next && this == b.next) { + if (f == null || f.value != f) // not already marked + appendMarker(f); + else + b.casNext(this, f.next); + } + } + + /** + * Returns value if this node contains a valid key-value pair, + * else null. + * @return this node's value if it isn't a marker or header or + * is deleted, else null. + */ + V getValidValue() { + Object v = value; + if (v == this || v == BASE_HEADER) + return null; + return (V)v; + } + + /** + * Creates and returns a new SimpleImmutableEntry holding current + * mapping if this node holds a valid value, else null. + * @return new entry or null + */ + AbstractMap.SimpleImmutableEntry createSnapshot() { + V v = getValidValue(); + if (v == null) + return null; + return new AbstractMap.SimpleImmutableEntry(key, v); + } + + // UNSAFE mechanics + + private static final sun.misc.Unsafe UNSAFE; + private static final long valueOffset; + private static final long nextOffset; + + static { + try { + UNSAFE = sun.misc.Unsafe.getUnsafe(); + Class k = Node.class; + valueOffset = UNSAFE.objectFieldOffset + (k.getDeclaredField("value")); + nextOffset = UNSAFE.objectFieldOffset + (k.getDeclaredField("next")); + } catch (Exception e) { + throw new Error(e); + } + } + } + + /* ---------------- Indexing -------------- */ + + /** + * Index nodes represent the levels of the skip list. Note that + * even though both Nodes and Indexes have forward-pointing + * fields, they have different types and are handled in different + * ways, that can't nicely be captured by placing field in a + * shared abstract class. + */ + static class Index { + final Node node; + final Index down; + volatile Index right; + + /** + * Creates index node with given values. + */ + Index(Node node, Index down, Index right) { + this.node = node; + this.down = down; + this.right = right; + } + + /** + * compareAndSet right field + */ + final boolean casRight(Index cmp, Index val) { + return UNSAFE.compareAndSwapObject(this, rightOffset, cmp, val); + } + + /** + * Returns true if the node this indexes has been deleted. + * @return true if indexed node is known to be deleted + */ + final boolean indexesDeletedNode() { + return node.value == null; + } + + /** + * Tries to CAS newSucc as successor. To minimize races with + * unlink that may lose this index node, if the node being + * indexed is known to be deleted, it doesn't try to link in. + * @param succ the expected current successor + * @param newSucc the new successor + * @return true if successful + */ + final boolean link(Index succ, Index newSucc) { + Node n = node; + newSucc.right = succ; + return n.value != null && casRight(succ, newSucc); + } + + /** + * Tries to CAS right field to skip over apparent successor + * succ. Fails (forcing a retraversal by caller) if this node + * is known to be deleted. + * @param succ the expected current successor + * @return true if successful + */ + final boolean unlink(Index succ) { + return !indexesDeletedNode() && casRight(succ, succ.right); + } + + // Unsafe mechanics + private static final sun.misc.Unsafe UNSAFE; + private static final long rightOffset; + static { + try { + UNSAFE = sun.misc.Unsafe.getUnsafe(); + Class k = Index.class; + rightOffset = UNSAFE.objectFieldOffset + (k.getDeclaredField("right")); + } catch (Exception e) { + throw new Error(e); + } + } + } + + /* ---------------- Head nodes -------------- */ + + /** + * Nodes heading each level keep track of their level. + */ + static final class HeadIndex extends Index { + final int level; + HeadIndex(Node node, Index down, Index right, int level) { + super(node, down, right); + this.level = level; + } + } + + /* ---------------- Comparison utilities -------------- */ + + /** + * Represents a key with a comparator as a Comparable. + * + * Because most sorted collections seem to use natural ordering on + * Comparables (Strings, Integers, etc), most internal methods are + * geared to use them. This is generally faster than checking + * per-comparison whether to use comparator or comparable because + * it doesn't require a (Comparable) cast for each comparison. + * (Optimizers can only sometimes remove such redundant checks + * themselves.) When Comparators are used, + * ComparableUsingComparators are created so that they act in the + * same way as natural orderings. This penalizes use of + * Comparators vs Comparables, which seems like the right + * tradeoff. + */ + static final class ComparableUsingComparator implements Comparable { + final K actualKey; + final Comparator cmp; + ComparableUsingComparator(K key, Comparator cmp) { + this.actualKey = key; + this.cmp = cmp; + } + public int compareTo(K k2) { + return cmp.compare(actualKey, k2); + } + } + + /** + * If using comparator, return a ComparableUsingComparator, else + * cast key as Comparable, which may cause ClassCastException, + * which is propagated back to caller. + */ + private Comparable comparable(Object key) + throws ClassCastException { + if (key == null) + throw new NullPointerException(); + if (comparator != null) + return new ComparableUsingComparator((K)key, comparator); + else + return (Comparable)key; + } + + /** + * Compares using comparator or natural ordering. Used when the + * ComparableUsingComparator approach doesn't apply. + */ + int compare(K k1, K k2) throws ClassCastException { + Comparator cmp = comparator; + if (cmp != null) + return cmp.compare(k1, k2); + else + return ((Comparable)k1).compareTo(k2); + } + + /** + * Returns true if given key greater than or equal to least and + * strictly less than fence, bypassing either test if least or + * fence are null. Needed mainly in submap operations. + */ + boolean inHalfOpenRange(K key, K least, K fence) { + if (key == null) + throw new NullPointerException(); + return ((least == null || compare(key, least) >= 0) && + (fence == null || compare(key, fence) < 0)); + } + + /** + * Returns true if given key greater than or equal to least and less + * or equal to fence. Needed mainly in submap operations. + */ + boolean inOpenRange(K key, K least, K fence) { + if (key == null) + throw new NullPointerException(); + return ((least == null || compare(key, least) >= 0) && + (fence == null || compare(key, fence) <= 0)); + } + + /* ---------------- Traversal -------------- */ + + /** + * Returns a base-level node with key strictly less than given key, + * or the base-level header if there is no such node. Also + * unlinks indexes to deleted nodes found along the way. Callers + * rely on this side-effect of clearing indices to deleted nodes. + * @param key the key + * @return a predecessor of key + */ + private Node findPredecessor(Comparable key) { + if (key == null) + throw new NullPointerException(); // don't postpone errors + for (;;) { + Index q = head; + Index r = q.right; + for (;;) { + if (r != null) { + Node n = r.node; + K k = n.key; + if (n.value == null) { + if (!q.unlink(r)) + break; // restart + r = q.right; // reread r + continue; + } + if (key.compareTo(k) > 0) { + q = r; + r = r.right; + continue; + } + } + Index d = q.down; + if (d != null) { + q = d; + r = d.right; + } else + return q.node; + } + } + } + + /** + * Returns node holding key or null if no such, clearing out any + * deleted nodes seen along the way. Repeatedly traverses at + * base-level looking for key starting at predecessor returned + * from findPredecessor, processing base-level deletions as + * encountered. Some callers rely on this side-effect of clearing + * deleted nodes. + * + * Restarts occur, at traversal step centered on node n, if: + * + * (1) After reading n's next field, n is no longer assumed + * predecessor b's current successor, which means that + * we don't have a consistent 3-node snapshot and so cannot + * unlink any subsequent deleted nodes encountered. + * + * (2) n's value field is null, indicating n is deleted, in + * which case we help out an ongoing structural deletion + * before retrying. Even though there are cases where such + * unlinking doesn't require restart, they aren't sorted out + * here because doing so would not usually outweigh cost of + * restarting. + * + * (3) n is a marker or n's predecessor's value field is null, + * indicating (among other possibilities) that + * findPredecessor returned a deleted node. We can't unlink + * the node because we don't know its predecessor, so rely + * on another call to findPredecessor to notice and return + * some earlier predecessor, which it will do. This check is + * only strictly needed at beginning of loop, (and the + * b.value check isn't strictly needed at all) but is done + * each iteration to help avoid contention with other + * threads by callers that will fail to be able to change + * links, and so will retry anyway. + * + * The traversal loops in doPut, doRemove, and findNear all + * include the same three kinds of checks. And specialized + * versions appear in findFirst, and findLast and their + * variants. They can't easily share code because each uses the + * reads of fields held in locals occurring in the orders they + * were performed. + * + * @param key the key + * @return node holding key, or null if no such + */ + private Node findNode(Comparable key) { + for (;;) { + Node b = findPredecessor(key); + Node n = b.next; + for (;;) { + if (n == null) + return null; + Node f = n.next; + if (n != b.next) // inconsistent read + break; + Object v = n.value; + if (v == null) { // n is deleted + n.helpDelete(b, f); + break; + } + if (v == n || b.value == null) // b is deleted + break; + int c = key.compareTo(n.key); + if (c == 0) + return n; + if (c < 0) + return null; + b = n; + n = f; + } + } + } + + /** + * Gets value for key using findNode. + * @param okey the key + * @return the value, or null if absent + */ + private V doGet(Object okey) { + Comparable key = comparable(okey); + /* + * Loop needed here and elsewhere in case value field goes + * null just as it is about to be returned, in which case we + * lost a race with a deletion, so must retry. + */ + for (;;) { + Node n = findNode(key); + if (n == null) + return null; + Object v = n.value; + if (v != null) + return (V)v; + } + } + + /* ---------------- Insertion -------------- */ + + /** + * Main insertion method. Adds element if not present, or + * replaces value if present and onlyIfAbsent is false. + * @param kkey the key + * @param value the value that must be associated with key + * @param onlyIfAbsent if should not insert if already present + * @return the old value, or null if newly inserted + */ + private V doPut(K kkey, V value, boolean onlyIfAbsent) { + Comparable key = comparable(kkey); + for (;;) { + Node b = findPredecessor(key); + Node n = b.next; + for (;;) { + if (n != null) { + Node f = n.next; + if (n != b.next) // inconsistent read + break; + Object v = n.value; + if (v == null) { // n is deleted + n.helpDelete(b, f); + break; + } + if (v == n || b.value == null) // b is deleted + break; + int c = key.compareTo(n.key); + if (c > 0) { + b = n; + n = f; + continue; + } + if (c == 0) { + if (onlyIfAbsent || n.casValue(v, value)) + return (V)v; + else + break; // restart if lost race to replace value + } + // else c < 0; fall through + } + + Node z = new Node(kkey, value, n); + if (!b.casNext(n, z)) + break; // restart if lost race to append to b + int level = randomLevel(); + if (level > 0) + insertIndex(z, level); + return null; + } + } + } + + /** + * Returns a random level for inserting a new node. + * Hardwired to k=1, p=0.5, max 31 (see above and + * Pugh's "Skip List Cookbook", sec 3.4). + * + * This uses the simplest of the generators described in George + * Marsaglia's "Xorshift RNGs" paper. This is not a high-quality + * generator but is acceptable here. + */ + private int randomLevel() { + int x = randomSeed; + x ^= x << 13; + x ^= x >>> 17; + randomSeed = x ^= x << 5; + if ((x & 0x80000001) != 0) // test highest and lowest bits + return 0; + int level = 1; + while (((x >>>= 1) & 1) != 0) ++level; + return level; + } + + /** + * Creates and adds index nodes for the given node. + * @param z the node + * @param level the level of the index + */ + private void insertIndex(Node z, int level) { + HeadIndex h = head; + int max = h.level; + + if (level <= max) { + Index idx = null; + for (int i = 1; i <= level; ++i) + idx = new Index(z, idx, null); + addIndex(idx, h, level); + + } else { // Add a new level + /* + * To reduce interference by other threads checking for + * empty levels in tryReduceLevel, new levels are added + * with initialized right pointers. Which in turn requires + * keeping levels in an array to access them while + * creating new head index nodes from the opposite + * direction. + */ + level = max + 1; + Index[] idxs = (Index[])new Index[level+1]; + Index idx = null; + for (int i = 1; i <= level; ++i) + idxs[i] = idx = new Index(z, idx, null); + + HeadIndex oldh; + int k; + for (;;) { + oldh = head; + int oldLevel = oldh.level; + if (level <= oldLevel) { // lost race to add level + k = level; + break; + } + HeadIndex newh = oldh; + Node oldbase = oldh.node; + for (int j = oldLevel+1; j <= level; ++j) + newh = new HeadIndex(oldbase, newh, idxs[j], j); + if (casHead(oldh, newh)) { + k = oldLevel; + break; + } + } + addIndex(idxs[k], oldh, k); + } + } + + /** + * Adds given index nodes from given level down to 1. + * @param idx the topmost index node being inserted + * @param h the value of head to use to insert. This must be + * snapshotted by callers to provide correct insertion level + * @param indexLevel the level of the index + */ + private void addIndex(Index idx, HeadIndex h, int indexLevel) { + // Track next level to insert in case of retries + int insertionLevel = indexLevel; + Comparable key = comparable(idx.node.key); + if (key == null) throw new NullPointerException(); + + // Similar to findPredecessor, but adding index nodes along + // path to key. + for (;;) { + int j = h.level; + Index q = h; + Index r = q.right; + Index t = idx; + for (;;) { + if (r != null) { + Node n = r.node; + // compare before deletion check avoids needing recheck + int c = key.compareTo(n.key); + if (n.value == null) { + if (!q.unlink(r)) + break; + r = q.right; + continue; + } + if (c > 0) { + q = r; + r = r.right; + continue; + } + } + + if (j == insertionLevel) { + // Don't insert index if node already deleted + if (t.indexesDeletedNode()) { + findNode(key); // cleans up + return; + } + if (!q.link(r, t)) + break; // restart + if (--insertionLevel == 0) { + // need final deletion check before return + if (t.indexesDeletedNode()) + findNode(key); + return; + } + } + + if (--j >= insertionLevel && j < indexLevel) + t = t.down; + q = q.down; + r = q.right; + } + } + } + + /* ---------------- Deletion -------------- */ + + /** + * Main deletion method. Locates node, nulls value, appends a + * deletion marker, unlinks predecessor, removes associated index + * nodes, and possibly reduces head index level. + * + * Index nodes are cleared out simply by calling findPredecessor. + * which unlinks indexes to deleted nodes found along path to key, + * which will include the indexes to this node. This is done + * unconditionally. We can't check beforehand whether there are + * index nodes because it might be the case that some or all + * indexes hadn't been inserted yet for this node during initial + * search for it, and we'd like to ensure lack of garbage + * retention, so must call to be sure. + * + * @param okey the key + * @param value if non-null, the value that must be + * associated with key + * @return the node, or null if not found + */ + final V doRemove(Object okey, Object value) { + Comparable key = comparable(okey); + for (;;) { + Node b = findPredecessor(key); + Node n = b.next; + for (;;) { + if (n == null) + return null; + Node f = n.next; + if (n != b.next) // inconsistent read + break; + Object v = n.value; + if (v == null) { // n is deleted + n.helpDelete(b, f); + break; + } + if (v == n || b.value == null) // b is deleted + break; + int c = key.compareTo(n.key); + if (c < 0) + return null; + if (c > 0) { + b = n; + n = f; + continue; + } + if (value != null && !value.equals(v)) + return null; + if (!n.casValue(v, null)) + break; + if (!n.appendMarker(f) || !b.casNext(n, f)) + findNode(key); // Retry via findNode + else { + findPredecessor(key); // Clean index + if (head.right == null) + tryReduceLevel(); + } + return (V)v; + } + } + } + + /** + * Possibly reduce head level if it has no nodes. This method can + * (rarely) make mistakes, in which case levels can disappear even + * though they are about to contain index nodes. This impacts + * performance, not correctness. To minimize mistakes as well as + * to reduce hysteresis, the level is reduced by one only if the + * topmost three levels look empty. Also, if the removed level + * looks non-empty after CAS, we try to change it back quick + * before anyone notices our mistake! (This trick works pretty + * well because this method will practically never make mistakes + * unless current thread stalls immediately before first CAS, in + * which case it is very unlikely to stall again immediately + * afterwards, so will recover.) + * + * We put up with all this rather than just let levels grow + * because otherwise, even a small map that has undergone a large + * number of insertions and removals will have a lot of levels, + * slowing down access more than would an occasional unwanted + * reduction. + */ + private void tryReduceLevel() { + HeadIndex h = head; + HeadIndex d; + HeadIndex e; + if (h.level > 3 && + (d = (HeadIndex)h.down) != null && + (e = (HeadIndex)d.down) != null && + e.right == null && + d.right == null && + h.right == null && + casHead(h, d) && // try to set + h.right != null) // recheck + casHead(d, h); // try to backout + } + + /* ---------------- Finding and removing first element -------------- */ + + /** + * Specialized variant of findNode to get first valid node. + * @return first node or null if empty + */ + Node findFirst() { + for (;;) { + Node b = head.node; + Node n = b.next; + if (n == null) + return null; + if (n.value != null) + return n; + n.helpDelete(b, n.next); + } + } + + /** + * Removes first entry; returns its snapshot. + * @return null if empty, else snapshot of first entry + */ + Map.Entry doRemoveFirstEntry() { + for (;;) { + Node b = head.node; + Node n = b.next; + if (n == null) + return null; + Node f = n.next; + if (n != b.next) + continue; + Object v = n.value; + if (v == null) { + n.helpDelete(b, f); + continue; + } + if (!n.casValue(v, null)) + continue; + if (!n.appendMarker(f) || !b.casNext(n, f)) + findFirst(); // retry + clearIndexToFirst(); + return new AbstractMap.SimpleImmutableEntry(n.key, (V)v); + } + } + + /** + * Clears out index nodes associated with deleted first entry. + */ + private void clearIndexToFirst() { + for (;;) { + Index q = head; + for (;;) { + Index r = q.right; + if (r != null && r.indexesDeletedNode() && !q.unlink(r)) + break; + if ((q = q.down) == null) { + if (head.right == null) + tryReduceLevel(); + return; + } + } + } + } + + + /* ---------------- Finding and removing last element -------------- */ + + /** + * Specialized version of find to get last valid node. + * @return last node or null if empty + */ + Node findLast() { + /* + * findPredecessor can't be used to traverse index level + * because this doesn't use comparisons. So traversals of + * both levels are folded together. + */ + Index q = head; + for (;;) { + Index d, r; + if ((r = q.right) != null) { + if (r.indexesDeletedNode()) { + q.unlink(r); + q = head; // restart + } + else + q = r; + } else if ((d = q.down) != null) { + q = d; + } else { + Node b = q.node; + Node n = b.next; + for (;;) { + if (n == null) + return b.isBaseHeader() ? null : b; + Node f = n.next; // inconsistent read + if (n != b.next) + break; + Object v = n.value; + if (v == null) { // n is deleted + n.helpDelete(b, f); + break; + } + if (v == n || b.value == null) // b is deleted + break; + b = n; + n = f; + } + q = head; // restart + } + } + } + + /** + * Specialized variant of findPredecessor to get predecessor of last + * valid node. Needed when removing the last entry. It is possible + * that all successors of returned node will have been deleted upon + * return, in which case this method can be retried. + * @return likely predecessor of last node + */ + private Node findPredecessorOfLast() { + for (;;) { + Index q = head; + for (;;) { + Index d, r; + if ((r = q.right) != null) { + if (r.indexesDeletedNode()) { + q.unlink(r); + break; // must restart + } + // proceed as far across as possible without overshooting + if (r.node.next != null) { + q = r; + continue; + } + } + if ((d = q.down) != null) + q = d; + else + return q.node; + } + } + } + + /** + * Removes last entry; returns its snapshot. + * Specialized variant of doRemove. + * @return null if empty, else snapshot of last entry + */ + Map.Entry doRemoveLastEntry() { + for (;;) { + Node b = findPredecessorOfLast(); + Node n = b.next; + if (n == null) { + if (b.isBaseHeader()) // empty + return null; + else + continue; // all b's successors are deleted; retry + } + for (;;) { + Node f = n.next; + if (n != b.next) // inconsistent read + break; + Object v = n.value; + if (v == null) { // n is deleted + n.helpDelete(b, f); + break; + } + if (v == n || b.value == null) // b is deleted + break; + if (f != null) { + b = n; + n = f; + continue; + } + if (!n.casValue(v, null)) + break; + K key = n.key; + Comparable ck = comparable(key); + if (!n.appendMarker(f) || !b.casNext(n, f)) + findNode(ck); // Retry via findNode + else { + findPredecessor(ck); // Clean index + if (head.right == null) + tryReduceLevel(); + } + return new AbstractMap.SimpleImmutableEntry(key, (V)v); + } + } + } + + /* ---------------- Relational operations -------------- */ + + // Control values OR'ed as arguments to findNear + + private static final int EQ = 1; + private static final int LT = 2; + private static final int GT = 0; // Actually checked as !LT + + /** + * Utility for ceiling, floor, lower, higher methods. + * @param kkey the key + * @param rel the relation -- OR'ed combination of EQ, LT, GT + * @return nearest node fitting relation, or null if no such + */ + Node findNear(K kkey, int rel) { + Comparable key = comparable(kkey); + for (;;) { + Node b = findPredecessor(key); + Node n = b.next; + for (;;) { + if (n == null) + return ((rel & LT) == 0 || b.isBaseHeader()) ? null : b; + Node f = n.next; + if (n != b.next) // inconsistent read + break; + Object v = n.value; + if (v == null) { // n is deleted + n.helpDelete(b, f); + break; + } + if (v == n || b.value == null) // b is deleted + break; + int c = key.compareTo(n.key); + if ((c == 0 && (rel & EQ) != 0) || + (c < 0 && (rel & LT) == 0)) + return n; + if ( c <= 0 && (rel & LT) != 0) + return b.isBaseHeader() ? null : b; + b = n; + n = f; + } + } + } + + /** + * Returns SimpleImmutableEntry for results of findNear. + * @param key the key + * @param rel the relation -- OR'ed combination of EQ, LT, GT + * @return Entry fitting relation, or null if no such + */ + AbstractMap.SimpleImmutableEntry getNear(K key, int rel) { + for (;;) { + Node n = findNear(key, rel); + if (n == null) + return null; + AbstractMap.SimpleImmutableEntry e = n.createSnapshot(); + if (e != null) + return e; + } + } + + + /* ---------------- Constructors -------------- */ + + /** + * Constructs a new, empty map, sorted according to the + * {@linkplain Comparable natural ordering} of the keys. + */ + public ConcurrentSkipListMap() { + this.comparator = null; + initialize(); + } + + /** + * Constructs a new, empty map, sorted according to the specified + * comparator. + * + * @param comparator the comparator that will be used to order this map. + * If null, the {@linkplain Comparable natural + * ordering} of the keys will be used. + */ + public ConcurrentSkipListMap(Comparator comparator) { + this.comparator = comparator; + initialize(); + } + + /** + * Constructs a new map containing the same mappings as the given map, + * sorted according to the {@linkplain Comparable natural ordering} of + * the keys. + * + * @param m the map whose mappings are to be placed in this map + * @throws ClassCastException if the keys in m are not + * {@link Comparable}, or are not mutually comparable + * @throws NullPointerException if the specified map or any of its keys + * or values are null + */ + public ConcurrentSkipListMap(Map m) { + this.comparator = null; + initialize(); + putAll(m); + } + + /** + * Constructs a new map containing the same mappings and using the + * same ordering as the specified sorted map. + * + * @param m the sorted map whose mappings are to be placed in this + * map, and whose comparator is to be used to sort this map + * @throws NullPointerException if the specified sorted map or any of + * its keys or values are null + */ + public ConcurrentSkipListMap(SortedMap m) { + this.comparator = m.comparator(); + initialize(); + buildFromSorted(m); + } + + /** + * Returns a shallow copy of this ConcurrentSkipListMap + * instance. (The keys and values themselves are not cloned.) + * + * @return a shallow copy of this map + */ + public ConcurrentSkipListMap clone() { + ConcurrentSkipListMap clone = null; + try { + clone = (ConcurrentSkipListMap) super.clone(); + } catch (CloneNotSupportedException e) { + throw new InternalError(); + } + + clone.initialize(); + clone.buildFromSorted(this); + return clone; + } + + /** + * Streamlined bulk insertion to initialize from elements of + * given sorted map. Call only from constructor or clone + * method. + */ + private void buildFromSorted(SortedMap map) { + if (map == null) + throw new NullPointerException(); + + HeadIndex h = head; + Node basepred = h.node; + + // Track the current rightmost node at each level. Uses an + // ArrayList to avoid committing to initial or maximum level. + ArrayList> preds = new ArrayList>(); + + // initialize + for (int i = 0; i <= h.level; ++i) + preds.add(null); + Index q = h; + for (int i = h.level; i > 0; --i) { + preds.set(i, q); + q = q.down; + } + + Iterator> it = + map.entrySet().iterator(); + while (it.hasNext()) { + Map.Entry e = it.next(); + int j = randomLevel(); + if (j > h.level) j = h.level + 1; + K k = e.getKey(); + V v = e.getValue(); + if (k == null || v == null) + throw new NullPointerException(); + Node z = new Node(k, v, null); + basepred.next = z; + basepred = z; + if (j > 0) { + Index idx = null; + for (int i = 1; i <= j; ++i) { + idx = new Index(z, idx, null); + if (i > h.level) + h = new HeadIndex(h.node, h, idx, i); + + if (i < preds.size()) { + preds.get(i).right = idx; + preds.set(i, idx); + } else + preds.add(idx); + } + } + } + head = h; + } + + /* ---------------- Serialization -------------- */ + + /** + * Save the state of this map to a stream. + * + * @serialData The key (Object) and value (Object) for each + * key-value mapping represented by the map, followed by + * null. The key-value mappings are emitted in key-order + * (as determined by the Comparator, or by the keys' natural + * ordering if no Comparator). + */ + private void writeObject(java.io.ObjectOutputStream s) + throws java.io.IOException { + // Write out the Comparator and any hidden stuff + s.defaultWriteObject(); + + // Write out keys and values (alternating) + for (Node n = findFirst(); n != null; n = n.next) { + V v = n.getValidValue(); + if (v != null) { + s.writeObject(n.key); + s.writeObject(v); + } + } + s.writeObject(null); + } + + /** + * Reconstitute the map from a stream. + */ + private void readObject(final java.io.ObjectInputStream s) + throws java.io.IOException, ClassNotFoundException { + // Read in the Comparator and any hidden stuff + s.defaultReadObject(); + // Reset transients + initialize(); + + /* + * This is nearly identical to buildFromSorted, but is + * distinct because readObject calls can't be nicely adapted + * as the kind of iterator needed by buildFromSorted. (They + * can be, but doing so requires type cheats and/or creation + * of adaptor classes.) It is simpler to just adapt the code. + */ + + HeadIndex h = head; + Node basepred = h.node; + ArrayList> preds = new ArrayList>(); + for (int i = 0; i <= h.level; ++i) + preds.add(null); + Index q = h; + for (int i = h.level; i > 0; --i) { + preds.set(i, q); + q = q.down; + } + + for (;;) { + Object k = s.readObject(); + if (k == null) + break; + Object v = s.readObject(); + if (v == null) + throw new NullPointerException(); + K key = (K) k; + V val = (V) v; + int j = randomLevel(); + if (j > h.level) j = h.level + 1; + Node z = new Node(key, val, null); + basepred.next = z; + basepred = z; + if (j > 0) { + Index idx = null; + for (int i = 1; i <= j; ++i) { + idx = new Index(z, idx, null); + if (i > h.level) + h = new HeadIndex(h.node, h, idx, i); + + if (i < preds.size()) { + preds.get(i).right = idx; + preds.set(i, idx); + } else + preds.add(idx); + } + } + } + head = h; + } + + /* ------ Map API methods ------ */ + + /** + * Returns true if this map contains a mapping for the specified + * key. + * + * @param key key whose presence in this map is to be tested + * @return true if this map contains a mapping for the specified key + * @throws ClassCastException if the specified key cannot be compared + * with the keys currently in the map + * @throws NullPointerException if the specified key is null + */ + public boolean containsKey(Object key) { + return doGet(key) != null; + } + + /** + * Returns the value to which the specified key is mapped, + * or {@code null} if this map contains no mapping for the key. + * + *

More formally, if this map contains a mapping from a key + * {@code k} to a value {@code v} such that {@code key} compares + * equal to {@code k} according to the map's ordering, then this + * method returns {@code v}; otherwise it returns {@code null}. + * (There can be at most one such mapping.) + * + * @throws ClassCastException if the specified key cannot be compared + * with the keys currently in the map + * @throws NullPointerException if the specified key is null + */ + public V get(Object key) { + return doGet(key); + } + + /** + * Associates the specified value with the specified key in this map. + * If the map previously contained a mapping for the key, the old + * value is replaced. + * + * @param key key with which the specified value is to be associated + * @param value value to be associated with the specified key + * @return the previous value associated with the specified key, or + * null if there was no mapping for the key + * @throws ClassCastException if the specified key cannot be compared + * with the keys currently in the map + * @throws NullPointerException if the specified key or value is null + */ + public V put(K key, V value) { + if (value == null) + throw new NullPointerException(); + return doPut(key, value, false); + } + + /** + * Removes the mapping for the specified key from this map if present. + * + * @param key key for which mapping should be removed + * @return the previous value associated with the specified key, or + * null if there was no mapping for the key + * @throws ClassCastException if the specified key cannot be compared + * with the keys currently in the map + * @throws NullPointerException if the specified key is null + */ + public V remove(Object key) { + return doRemove(key, null); + } + + /** + * Returns true if this map maps one or more keys to the + * specified value. This operation requires time linear in the + * map size. Additionally, it is possible for the map to change + * during execution of this method, in which case the returned + * result may be inaccurate. + * + * @param value value whose presence in this map is to be tested + * @return true if a mapping to value exists; + * false otherwise + * @throws NullPointerException if the specified value is null + */ + public boolean containsValue(Object value) { + if (value == null) + throw new NullPointerException(); + for (Node n = findFirst(); n != null; n = n.next) { + V v = n.getValidValue(); + if (v != null && value.equals(v)) + return true; + } + return false; + } + + /** + * Returns the number of key-value mappings in this map. If this map + * contains more than Integer.MAX_VALUE elements, it + * returns Integer.MAX_VALUE. + * + *

Beware that, unlike in most collections, this method is + * NOT a constant-time operation. Because of the + * asynchronous nature of these maps, determining the current + * number of elements requires traversing them all to count them. + * Additionally, it is possible for the size to change during + * execution of this method, in which case the returned result + * will be inaccurate. Thus, this method is typically not very + * useful in concurrent applications. + * + * @return the number of elements in this map + */ + public int size() { + long count = 0; + for (Node n = findFirst(); n != null; n = n.next) { + if (n.getValidValue() != null) + ++count; + } + return (count >= Integer.MAX_VALUE) ? Integer.MAX_VALUE : (int) count; + } + + /** + * Returns true if this map contains no key-value mappings. + * @return true if this map contains no key-value mappings + */ + public boolean isEmpty() { + return findFirst() == null; + } + + /** + * Removes all of the mappings from this map. + */ + public void clear() { + initialize(); + } + + /* ---------------- View methods -------------- */ + + /* + * Note: Lazy initialization works for views because view classes + * are stateless/immutable so it doesn't matter wrt correctness if + * more than one is created (which will only rarely happen). Even + * so, the following idiom conservatively ensures that the method + * returns the one it created if it does so, not one created by + * another racing thread. + */ + + /** + * Returns a {@link NavigableSet} view of the keys contained in this map. + * The set's iterator returns the keys in ascending order. + * The set is backed by the map, so changes to the map are + * reflected in the set, and vice-versa. The set supports element + * removal, which removes the corresponding mapping from the map, + * via the {@code Iterator.remove}, {@code Set.remove}, + * {@code removeAll}, {@code retainAll}, and {@code clear} + * operations. It does not support the {@code add} or {@code addAll} + * operations. + * + *

The view's {@code iterator} is a "weakly consistent" iterator + * that will never throw {@link ConcurrentModificationException}, + * and guarantees to traverse elements as they existed upon + * construction of the iterator, and may (but is not guaranteed to) + * reflect any modifications subsequent to construction. + * + *

This method is equivalent to method {@code navigableKeySet}. + * + * @return a navigable set view of the keys in this map + */ + public NavigableSet keySet() { + KeySet ks = keySet; + return (ks != null) ? ks : (keySet = new KeySet(this)); + } + + public NavigableSet navigableKeySet() { + KeySet ks = keySet; + return (ks != null) ? ks : (keySet = new KeySet(this)); + } + + /** + * Returns a {@link Collection} view of the values contained in this map. + * The collection's iterator returns the values in ascending order + * of the corresponding keys. + * The collection is backed by the map, so changes to the map are + * reflected in the collection, and vice-versa. The collection + * supports element removal, which removes the corresponding + * mapping from the map, via the Iterator.remove, + * Collection.remove, removeAll, + * retainAll and clear operations. It does not + * support the add or addAll operations. + * + *

The view's iterator is a "weakly consistent" iterator + * that will never throw {@link ConcurrentModificationException}, + * and guarantees to traverse elements as they existed upon + * construction of the iterator, and may (but is not guaranteed to) + * reflect any modifications subsequent to construction. + */ + public Collection values() { + Values vs = values; + return (vs != null) ? vs : (values = new Values(this)); + } + + /** + * Returns a {@link Set} view of the mappings contained in this map. + * The set's iterator returns the entries in ascending key order. + * The set is backed by the map, so changes to the map are + * reflected in the set, and vice-versa. The set supports element + * removal, which removes the corresponding mapping from the map, + * via the Iterator.remove, Set.remove, + * removeAll, retainAll and clear + * operations. It does not support the add or + * addAll operations. + * + *

The view's iterator is a "weakly consistent" iterator + * that will never throw {@link ConcurrentModificationException}, + * and guarantees to traverse elements as they existed upon + * construction of the iterator, and may (but is not guaranteed to) + * reflect any modifications subsequent to construction. + * + *

The Map.Entry elements returned by + * iterator.next() do not support the + * setValue operation. + * + * @return a set view of the mappings contained in this map, + * sorted in ascending key order + */ + public Set> entrySet() { + EntrySet es = entrySet; + return (es != null) ? es : (entrySet = new EntrySet(this)); + } + + public ConcurrentNavigableMap descendingMap() { + ConcurrentNavigableMap dm = descendingMap; + return (dm != null) ? dm : (descendingMap = new SubMap + (this, null, false, null, false, true)); + } + + public NavigableSet descendingKeySet() { + return descendingMap().navigableKeySet(); + } + + /* ---------------- AbstractMap Overrides -------------- */ + + /** + * Compares the specified object with this map for equality. + * Returns true if the given object is also a map and the + * two maps represent the same mappings. More formally, two maps + * m1 and m2 represent the same mappings if + * m1.entrySet().equals(m2.entrySet()). This + * operation may return misleading results if either map is + * concurrently modified during execution of this method. + * + * @param o object to be compared for equality with this map + * @return true if the specified object is equal to this map + */ + public boolean equals(Object o) { + if (o == this) + return true; + if (!(o instanceof Map)) + return false; + Map m = (Map) o; + try { + for (Map.Entry e : this.entrySet()) + if (! e.getValue().equals(m.get(e.getKey()))) + return false; + for (Map.Entry e : m.entrySet()) { + Object k = e.getKey(); + Object v = e.getValue(); + if (k == null || v == null || !v.equals(get(k))) + return false; + } + return true; + } catch (ClassCastException unused) { + return false; + } catch (NullPointerException unused) { + return false; + } + } + + /* ------ ConcurrentMap API methods ------ */ + + /** + * {@inheritDoc} + * + * @return the previous value associated with the specified key, + * or null if there was no mapping for the key + * @throws ClassCastException if the specified key cannot be compared + * with the keys currently in the map + * @throws NullPointerException if the specified key or value is null + */ + public V putIfAbsent(K key, V value) { + if (value == null) + throw new NullPointerException(); + return doPut(key, value, true); + } + + /** + * {@inheritDoc} + * + * @throws ClassCastException if the specified key cannot be compared + * with the keys currently in the map + * @throws NullPointerException if the specified key is null + */ + public boolean remove(Object key, Object value) { + if (key == null) + throw new NullPointerException(); + if (value == null) + return false; + return doRemove(key, value) != null; + } + + /** + * {@inheritDoc} + * + * @throws ClassCastException if the specified key cannot be compared + * with the keys currently in the map + * @throws NullPointerException if any of the arguments are null + */ + public boolean replace(K key, V oldValue, V newValue) { + if (oldValue == null || newValue == null) + throw new NullPointerException(); + Comparable k = comparable(key); + for (;;) { + Node n = findNode(k); + if (n == null) + return false; + Object v = n.value; + if (v != null) { + if (!oldValue.equals(v)) + return false; + if (n.casValue(v, newValue)) + return true; + } + } + } + + /** + * {@inheritDoc} + * + * @return the previous value associated with the specified key, + * or null if there was no mapping for the key + * @throws ClassCastException if the specified key cannot be compared + * with the keys currently in the map + * @throws NullPointerException if the specified key or value is null + */ + public V replace(K key, V value) { + if (value == null) + throw new NullPointerException(); + Comparable k = comparable(key); + for (;;) { + Node n = findNode(k); + if (n == null) + return null; + Object v = n.value; + if (v != null && n.casValue(v, value)) + return (V)v; + } + } + + /* ------ SortedMap API methods ------ */ + + public Comparator comparator() { + return comparator; + } + + /** + * @throws NoSuchElementException {@inheritDoc} + */ + public K firstKey() { + Node n = findFirst(); + if (n == null) + throw new NoSuchElementException(); + return n.key; + } + + /** + * @throws NoSuchElementException {@inheritDoc} + */ + public K lastKey() { + Node n = findLast(); + if (n == null) + throw new NoSuchElementException(); + return n.key; + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if {@code fromKey} or {@code toKey} is null + * @throws IllegalArgumentException {@inheritDoc} + */ + public ConcurrentNavigableMap subMap(K fromKey, + boolean fromInclusive, + K toKey, + boolean toInclusive) { + if (fromKey == null || toKey == null) + throw new NullPointerException(); + return new SubMap + (this, fromKey, fromInclusive, toKey, toInclusive, false); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if {@code toKey} is null + * @throws IllegalArgumentException {@inheritDoc} + */ + public ConcurrentNavigableMap headMap(K toKey, + boolean inclusive) { + if (toKey == null) + throw new NullPointerException(); + return new SubMap + (this, null, false, toKey, inclusive, false); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if {@code fromKey} is null + * @throws IllegalArgumentException {@inheritDoc} + */ + public ConcurrentNavigableMap tailMap(K fromKey, + boolean inclusive) { + if (fromKey == null) + throw new NullPointerException(); + return new SubMap + (this, fromKey, inclusive, null, false, false); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if {@code fromKey} or {@code toKey} is null + * @throws IllegalArgumentException {@inheritDoc} + */ + public ConcurrentNavigableMap subMap(K fromKey, K toKey) { + return subMap(fromKey, true, toKey, false); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if {@code toKey} is null + * @throws IllegalArgumentException {@inheritDoc} + */ + public ConcurrentNavigableMap headMap(K toKey) { + return headMap(toKey, false); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if {@code fromKey} is null + * @throws IllegalArgumentException {@inheritDoc} + */ + public ConcurrentNavigableMap tailMap(K fromKey) { + return tailMap(fromKey, true); + } + + /* ---------------- Relational operations -------------- */ + + /** + * Returns a key-value mapping associated with the greatest key + * strictly less than the given key, or null if there is + * no such key. The returned entry does not support the + * Entry.setValue method. + * + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if the specified key is null + */ + public Map.Entry lowerEntry(K key) { + return getNear(key, LT); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if the specified key is null + */ + public K lowerKey(K key) { + Node n = findNear(key, LT); + return (n == null) ? null : n.key; + } + + /** + * Returns a key-value mapping associated with the greatest key + * less than or equal to the given key, or null if there + * is no such key. The returned entry does not support + * the Entry.setValue method. + * + * @param key the key + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if the specified key is null + */ + public Map.Entry floorEntry(K key) { + return getNear(key, LT|EQ); + } + + /** + * @param key the key + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if the specified key is null + */ + public K floorKey(K key) { + Node n = findNear(key, LT|EQ); + return (n == null) ? null : n.key; + } + + /** + * Returns a key-value mapping associated with the least key + * greater than or equal to the given key, or null if + * there is no such entry. The returned entry does not + * support the Entry.setValue method. + * + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if the specified key is null + */ + public Map.Entry ceilingEntry(K key) { + return getNear(key, GT|EQ); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if the specified key is null + */ + public K ceilingKey(K key) { + Node n = findNear(key, GT|EQ); + return (n == null) ? null : n.key; + } + + /** + * Returns a key-value mapping associated with the least key + * strictly greater than the given key, or null if there + * is no such key. The returned entry does not support + * the Entry.setValue method. + * + * @param key the key + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if the specified key is null + */ + public Map.Entry higherEntry(K key) { + return getNear(key, GT); + } + + /** + * @param key the key + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if the specified key is null + */ + public K higherKey(K key) { + Node n = findNear(key, GT); + return (n == null) ? null : n.key; + } + + /** + * Returns a key-value mapping associated with the least + * key in this map, or null if the map is empty. + * The returned entry does not support + * the Entry.setValue method. + */ + public Map.Entry firstEntry() { + for (;;) { + Node n = findFirst(); + if (n == null) + return null; + AbstractMap.SimpleImmutableEntry e = n.createSnapshot(); + if (e != null) + return e; + } + } + + /** + * Returns a key-value mapping associated with the greatest + * key in this map, or null if the map is empty. + * The returned entry does not support + * the Entry.setValue method. + */ + public Map.Entry lastEntry() { + for (;;) { + Node n = findLast(); + if (n == null) + return null; + AbstractMap.SimpleImmutableEntry e = n.createSnapshot(); + if (e != null) + return e; + } + } + + /** + * Removes and returns a key-value mapping associated with + * the least key in this map, or null if the map is empty. + * The returned entry does not support + * the Entry.setValue method. + */ + public Map.Entry pollFirstEntry() { + return doRemoveFirstEntry(); + } + + /** + * Removes and returns a key-value mapping associated with + * the greatest key in this map, or null if the map is empty. + * The returned entry does not support + * the Entry.setValue method. + */ + public Map.Entry pollLastEntry() { + return doRemoveLastEntry(); + } + + + /* ---------------- Iterators -------------- */ + + /** + * Base of iterator classes: + */ + abstract class Iter implements Iterator { + /** the last node returned by next() */ + Node lastReturned; + /** the next node to return from next(); */ + Node next; + /** Cache of next value field to maintain weak consistency */ + V nextValue; + + /** Initializes ascending iterator for entire range. */ + Iter() { + for (;;) { + next = findFirst(); + if (next == null) + break; + Object x = next.value; + if (x != null && x != next) { + nextValue = (V) x; + break; + } + } + } + + public final boolean hasNext() { + return next != null; + } + + /** Advances next to higher entry. */ + final void advance() { + if (next == null) + throw new NoSuchElementException(); + lastReturned = next; + for (;;) { + next = next.next; + if (next == null) + break; + Object x = next.value; + if (x != null && x != next) { + nextValue = (V) x; + break; + } + } + } + + public void remove() { + Node l = lastReturned; + if (l == null) + throw new IllegalStateException(); + // It would not be worth all of the overhead to directly + // unlink from here. Using remove is fast enough. + ConcurrentSkipListMap.this.remove(l.key); + lastReturned = null; + } + + } + + final class ValueIterator extends Iter { + public V next() { + V v = nextValue; + advance(); + return v; + } + } + + final class KeyIterator extends Iter { + public K next() { + Node n = next; + advance(); + return n.key; + } + } + + final class EntryIterator extends Iter> { + public Map.Entry next() { + Node n = next; + V v = nextValue; + advance(); + return new AbstractMap.SimpleImmutableEntry(n.key, v); + } + } + + // Factory methods for iterators needed by ConcurrentSkipListSet etc + + Iterator keyIterator() { + return new KeyIterator(); + } + + Iterator valueIterator() { + return new ValueIterator(); + } + + Iterator> entryIterator() { + return new EntryIterator(); + } + + /* ---------------- View Classes -------------- */ + + /* + * View classes are static, delegating to a ConcurrentNavigableMap + * to allow use by SubMaps, which outweighs the ugliness of + * needing type-tests for Iterator methods. + */ + + static final List toList(Collection c) { + // Using size() here would be a pessimization. + List list = new ArrayList(); + for (E e : c) + list.add(e); + return list; + } + + static final class KeySet + extends AbstractSet implements NavigableSet { + private final ConcurrentNavigableMap m; + KeySet(ConcurrentNavigableMap map) { m = map; } + public int size() { return m.size(); } + public boolean isEmpty() { return m.isEmpty(); } + public boolean contains(Object o) { return m.containsKey(o); } + public boolean remove(Object o) { return m.remove(o) != null; } + public void clear() { m.clear(); } + public E lower(E e) { return m.lowerKey(e); } + public E floor(E e) { return m.floorKey(e); } + public E ceiling(E e) { return m.ceilingKey(e); } + public E higher(E e) { return m.higherKey(e); } + public Comparator comparator() { return m.comparator(); } + public E first() { return m.firstKey(); } + public E last() { return m.lastKey(); } + public E pollFirst() { + Map.Entry e = m.pollFirstEntry(); + return (e == null) ? null : e.getKey(); + } + public E pollLast() { + Map.Entry e = m.pollLastEntry(); + return (e == null) ? null : e.getKey(); + } + public Iterator iterator() { + if (m instanceof ConcurrentSkipListMap) + return ((ConcurrentSkipListMap)m).keyIterator(); + else + return ((ConcurrentSkipListMap.SubMap)m).keyIterator(); + } + public boolean equals(Object o) { + if (o == this) + return true; + if (!(o instanceof Set)) + return false; + Collection c = (Collection) o; + try { + return containsAll(c) && c.containsAll(this); + } catch (ClassCastException unused) { + return false; + } catch (NullPointerException unused) { + return false; + } + } + public Object[] toArray() { return toList(this).toArray(); } + public T[] toArray(T[] a) { return toList(this).toArray(a); } + public Iterator descendingIterator() { + return descendingSet().iterator(); + } + public NavigableSet subSet(E fromElement, + boolean fromInclusive, + E toElement, + boolean toInclusive) { + return new KeySet(m.subMap(fromElement, fromInclusive, + toElement, toInclusive)); + } + public NavigableSet headSet(E toElement, boolean inclusive) { + return new KeySet(m.headMap(toElement, inclusive)); + } + public NavigableSet tailSet(E fromElement, boolean inclusive) { + return new KeySet(m.tailMap(fromElement, inclusive)); + } + public NavigableSet subSet(E fromElement, E toElement) { + return subSet(fromElement, true, toElement, false); + } + public NavigableSet headSet(E toElement) { + return headSet(toElement, false); + } + public NavigableSet tailSet(E fromElement) { + return tailSet(fromElement, true); + } + public NavigableSet descendingSet() { + return new KeySet(m.descendingMap()); + } + } + + static final class Values extends AbstractCollection { + private final ConcurrentNavigableMap m; + Values(ConcurrentNavigableMap map) { + m = map; + } + public Iterator iterator() { + if (m instanceof ConcurrentSkipListMap) + return ((ConcurrentSkipListMap)m).valueIterator(); + else + return ((SubMap)m).valueIterator(); + } + public boolean isEmpty() { + return m.isEmpty(); + } + public int size() { + return m.size(); + } + public boolean contains(Object o) { + return m.containsValue(o); + } + public void clear() { + m.clear(); + } + public Object[] toArray() { return toList(this).toArray(); } + public T[] toArray(T[] a) { return toList(this).toArray(a); } + } + + static final class EntrySet extends AbstractSet> { + private final ConcurrentNavigableMap m; + EntrySet(ConcurrentNavigableMap map) { + m = map; + } + + public Iterator> iterator() { + if (m instanceof ConcurrentSkipListMap) + return ((ConcurrentSkipListMap)m).entryIterator(); + else + return ((SubMap)m).entryIterator(); + } + + public boolean contains(Object o) { + if (!(o instanceof Map.Entry)) + return false; + Map.Entry e = (Map.Entry)o; + V1 v = m.get(e.getKey()); + return v != null && v.equals(e.getValue()); + } + public boolean remove(Object o) { + if (!(o instanceof Map.Entry)) + return false; + Map.Entry e = (Map.Entry)o; + return m.remove(e.getKey(), + e.getValue()); + } + public boolean isEmpty() { + return m.isEmpty(); + } + public int size() { + return m.size(); + } + public void clear() { + m.clear(); + } + public boolean equals(Object o) { + if (o == this) + return true; + if (!(o instanceof Set)) + return false; + Collection c = (Collection) o; + try { + return containsAll(c) && c.containsAll(this); + } catch (ClassCastException unused) { + return false; + } catch (NullPointerException unused) { + return false; + } + } + public Object[] toArray() { return toList(this).toArray(); } + public T[] toArray(T[] a) { return toList(this).toArray(a); } + } + + /** + * Submaps returned by {@link ConcurrentSkipListMap} submap operations + * represent a subrange of mappings of their underlying + * maps. Instances of this class support all methods of their + * underlying maps, differing in that mappings outside their range are + * ignored, and attempts to add mappings outside their ranges result + * in {@link IllegalArgumentException}. Instances of this class are + * constructed only using the subMap, headMap, and + * tailMap methods of their underlying maps. + * + * @serial include + */ + static final class SubMap extends AbstractMap + implements ConcurrentNavigableMap, Cloneable, + java.io.Serializable { + private static final long serialVersionUID = -7647078645895051609L; + + /** Underlying map */ + private final ConcurrentSkipListMap m; + /** lower bound key, or null if from start */ + private final K lo; + /** upper bound key, or null if to end */ + private final K hi; + /** inclusion flag for lo */ + private final boolean loInclusive; + /** inclusion flag for hi */ + private final boolean hiInclusive; + /** direction */ + private final boolean isDescending; + + // Lazily initialized view holders + private transient KeySet keySetView; + private transient Set> entrySetView; + private transient Collection valuesView; + + /** + * Creates a new submap, initializing all fields + */ + SubMap(ConcurrentSkipListMap map, + K fromKey, boolean fromInclusive, + K toKey, boolean toInclusive, + boolean isDescending) { + if (fromKey != null && toKey != null && + map.compare(fromKey, toKey) > 0) + throw new IllegalArgumentException("inconsistent range"); + this.m = map; + this.lo = fromKey; + this.hi = toKey; + this.loInclusive = fromInclusive; + this.hiInclusive = toInclusive; + this.isDescending = isDescending; + } + + /* ---------------- Utilities -------------- */ + + private boolean tooLow(K key) { + if (lo != null) { + int c = m.compare(key, lo); + if (c < 0 || (c == 0 && !loInclusive)) + return true; + } + return false; + } + + private boolean tooHigh(K key) { + if (hi != null) { + int c = m.compare(key, hi); + if (c > 0 || (c == 0 && !hiInclusive)) + return true; + } + return false; + } + + private boolean inBounds(K key) { + return !tooLow(key) && !tooHigh(key); + } + + private void checkKeyBounds(K key) throws IllegalArgumentException { + if (key == null) + throw new NullPointerException(); + if (!inBounds(key)) + throw new IllegalArgumentException("key out of range"); + } + + /** + * Returns true if node key is less than upper bound of range + */ + private boolean isBeforeEnd(ConcurrentSkipListMap.Node n) { + if (n == null) + return false; + if (hi == null) + return true; + K k = n.key; + if (k == null) // pass by markers and headers + return true; + int c = m.compare(k, hi); + if (c > 0 || (c == 0 && !hiInclusive)) + return false; + return true; + } + + /** + * Returns lowest node. This node might not be in range, so + * most usages need to check bounds + */ + private ConcurrentSkipListMap.Node loNode() { + if (lo == null) + return m.findFirst(); + else if (loInclusive) + return m.findNear(lo, m.GT|m.EQ); + else + return m.findNear(lo, m.GT); + } + + /** + * Returns highest node. This node might not be in range, so + * most usages need to check bounds + */ + private ConcurrentSkipListMap.Node hiNode() { + if (hi == null) + return m.findLast(); + else if (hiInclusive) + return m.findNear(hi, m.LT|m.EQ); + else + return m.findNear(hi, m.LT); + } + + /** + * Returns lowest absolute key (ignoring directonality) + */ + private K lowestKey() { + ConcurrentSkipListMap.Node n = loNode(); + if (isBeforeEnd(n)) + return n.key; + else + throw new NoSuchElementException(); + } + + /** + * Returns highest absolute key (ignoring directonality) + */ + private K highestKey() { + ConcurrentSkipListMap.Node n = hiNode(); + if (n != null) { + K last = n.key; + if (inBounds(last)) + return last; + } + throw new NoSuchElementException(); + } + + private Map.Entry lowestEntry() { + for (;;) { + ConcurrentSkipListMap.Node n = loNode(); + if (!isBeforeEnd(n)) + return null; + Map.Entry e = n.createSnapshot(); + if (e != null) + return e; + } + } + + private Map.Entry highestEntry() { + for (;;) { + ConcurrentSkipListMap.Node n = hiNode(); + if (n == null || !inBounds(n.key)) + return null; + Map.Entry e = n.createSnapshot(); + if (e != null) + return e; + } + } + + private Map.Entry removeLowest() { + for (;;) { + Node n = loNode(); + if (n == null) + return null; + K k = n.key; + if (!inBounds(k)) + return null; + V v = m.doRemove(k, null); + if (v != null) + return new AbstractMap.SimpleImmutableEntry(k, v); + } + } + + private Map.Entry removeHighest() { + for (;;) { + Node n = hiNode(); + if (n == null) + return null; + K k = n.key; + if (!inBounds(k)) + return null; + V v = m.doRemove(k, null); + if (v != null) + return new AbstractMap.SimpleImmutableEntry(k, v); + } + } + + /** + * Submap version of ConcurrentSkipListMap.getNearEntry + */ + private Map.Entry getNearEntry(K key, int rel) { + if (isDescending) { // adjust relation for direction + if ((rel & m.LT) == 0) + rel |= m.LT; + else + rel &= ~m.LT; + } + if (tooLow(key)) + return ((rel & m.LT) != 0) ? null : lowestEntry(); + if (tooHigh(key)) + return ((rel & m.LT) != 0) ? highestEntry() : null; + for (;;) { + Node n = m.findNear(key, rel); + if (n == null || !inBounds(n.key)) + return null; + K k = n.key; + V v = n.getValidValue(); + if (v != null) + return new AbstractMap.SimpleImmutableEntry(k, v); + } + } + + // Almost the same as getNearEntry, except for keys + private K getNearKey(K key, int rel) { + if (isDescending) { // adjust relation for direction + if ((rel & m.LT) == 0) + rel |= m.LT; + else + rel &= ~m.LT; + } + if (tooLow(key)) { + if ((rel & m.LT) == 0) { + ConcurrentSkipListMap.Node n = loNode(); + if (isBeforeEnd(n)) + return n.key; + } + return null; + } + if (tooHigh(key)) { + if ((rel & m.LT) != 0) { + ConcurrentSkipListMap.Node n = hiNode(); + if (n != null) { + K last = n.key; + if (inBounds(last)) + return last; + } + } + return null; + } + for (;;) { + Node n = m.findNear(key, rel); + if (n == null || !inBounds(n.key)) + return null; + K k = n.key; + V v = n.getValidValue(); + if (v != null) + return k; + } + } + + /* ---------------- Map API methods -------------- */ + + public boolean containsKey(Object key) { + if (key == null) throw new NullPointerException(); + K k = (K)key; + return inBounds(k) && m.containsKey(k); + } + + public V get(Object key) { + if (key == null) throw new NullPointerException(); + K k = (K)key; + return ((!inBounds(k)) ? null : m.get(k)); + } + + public V put(K key, V value) { + checkKeyBounds(key); + return m.put(key, value); + } + + public V remove(Object key) { + K k = (K)key; + return (!inBounds(k)) ? null : m.remove(k); + } + + public int size() { + long count = 0; + for (ConcurrentSkipListMap.Node n = loNode(); + isBeforeEnd(n); + n = n.next) { + if (n.getValidValue() != null) + ++count; + } + return count >= Integer.MAX_VALUE ? Integer.MAX_VALUE : (int)count; + } + + public boolean isEmpty() { + return !isBeforeEnd(loNode()); + } + + public boolean containsValue(Object value) { + if (value == null) + throw new NullPointerException(); + for (ConcurrentSkipListMap.Node n = loNode(); + isBeforeEnd(n); + n = n.next) { + V v = n.getValidValue(); + if (v != null && value.equals(v)) + return true; + } + return false; + } + + public void clear() { + for (ConcurrentSkipListMap.Node n = loNode(); + isBeforeEnd(n); + n = n.next) { + if (n.getValidValue() != null) + m.remove(n.key); + } + } + + /* ---------------- ConcurrentMap API methods -------------- */ + + public V putIfAbsent(K key, V value) { + checkKeyBounds(key); + return m.putIfAbsent(key, value); + } + + public boolean remove(Object key, Object value) { + K k = (K)key; + return inBounds(k) && m.remove(k, value); + } + + public boolean replace(K key, V oldValue, V newValue) { + checkKeyBounds(key); + return m.replace(key, oldValue, newValue); + } + + public V replace(K key, V value) { + checkKeyBounds(key); + return m.replace(key, value); + } + + /* ---------------- SortedMap API methods -------------- */ + + public Comparator comparator() { + Comparator cmp = m.comparator(); + if (isDescending) + return Collections.reverseOrder(cmp); + else + return cmp; + } + + /** + * Utility to create submaps, where given bounds override + * unbounded(null) ones and/or are checked against bounded ones. + */ + private SubMap newSubMap(K fromKey, + boolean fromInclusive, + K toKey, + boolean toInclusive) { + if (isDescending) { // flip senses + K tk = fromKey; + fromKey = toKey; + toKey = tk; + boolean ti = fromInclusive; + fromInclusive = toInclusive; + toInclusive = ti; + } + if (lo != null) { + if (fromKey == null) { + fromKey = lo; + fromInclusive = loInclusive; + } + else { + int c = m.compare(fromKey, lo); + if (c < 0 || (c == 0 && !loInclusive && fromInclusive)) + throw new IllegalArgumentException("key out of range"); + } + } + if (hi != null) { + if (toKey == null) { + toKey = hi; + toInclusive = hiInclusive; + } + else { + int c = m.compare(toKey, hi); + if (c > 0 || (c == 0 && !hiInclusive && toInclusive)) + throw new IllegalArgumentException("key out of range"); + } + } + return new SubMap(m, fromKey, fromInclusive, + toKey, toInclusive, isDescending); + } + + public SubMap subMap(K fromKey, + boolean fromInclusive, + K toKey, + boolean toInclusive) { + if (fromKey == null || toKey == null) + throw new NullPointerException(); + return newSubMap(fromKey, fromInclusive, toKey, toInclusive); + } + + public SubMap headMap(K toKey, + boolean inclusive) { + if (toKey == null) + throw new NullPointerException(); + return newSubMap(null, false, toKey, inclusive); + } + + public SubMap tailMap(K fromKey, + boolean inclusive) { + if (fromKey == null) + throw new NullPointerException(); + return newSubMap(fromKey, inclusive, null, false); + } + + public SubMap subMap(K fromKey, K toKey) { + return subMap(fromKey, true, toKey, false); + } + + public SubMap headMap(K toKey) { + return headMap(toKey, false); + } + + public SubMap tailMap(K fromKey) { + return tailMap(fromKey, true); + } + + public SubMap descendingMap() { + return new SubMap(m, lo, loInclusive, + hi, hiInclusive, !isDescending); + } + + /* ---------------- Relational methods -------------- */ + + public Map.Entry ceilingEntry(K key) { + return getNearEntry(key, (m.GT|m.EQ)); + } + + public K ceilingKey(K key) { + return getNearKey(key, (m.GT|m.EQ)); + } + + public Map.Entry lowerEntry(K key) { + return getNearEntry(key, (m.LT)); + } + + public K lowerKey(K key) { + return getNearKey(key, (m.LT)); + } + + public Map.Entry floorEntry(K key) { + return getNearEntry(key, (m.LT|m.EQ)); + } + + public K floorKey(K key) { + return getNearKey(key, (m.LT|m.EQ)); + } + + public Map.Entry higherEntry(K key) { + return getNearEntry(key, (m.GT)); + } + + public K higherKey(K key) { + return getNearKey(key, (m.GT)); + } + + public K firstKey() { + return isDescending ? highestKey() : lowestKey(); + } + + public K lastKey() { + return isDescending ? lowestKey() : highestKey(); + } + + public Map.Entry firstEntry() { + return isDescending ? highestEntry() : lowestEntry(); + } + + public Map.Entry lastEntry() { + return isDescending ? lowestEntry() : highestEntry(); + } + + public Map.Entry pollFirstEntry() { + return isDescending ? removeHighest() : removeLowest(); + } + + public Map.Entry pollLastEntry() { + return isDescending ? removeLowest() : removeHighest(); + } + + /* ---------------- Submap Views -------------- */ + + public NavigableSet keySet() { + KeySet ks = keySetView; + return (ks != null) ? ks : (keySetView = new KeySet(this)); + } + + public NavigableSet navigableKeySet() { + KeySet ks = keySetView; + return (ks != null) ? ks : (keySetView = new KeySet(this)); + } + + public Collection values() { + Collection vs = valuesView; + return (vs != null) ? vs : (valuesView = new Values(this)); + } + + public Set> entrySet() { + Set> es = entrySetView; + return (es != null) ? es : (entrySetView = new EntrySet(this)); + } + + public NavigableSet descendingKeySet() { + return descendingMap().navigableKeySet(); + } + + Iterator keyIterator() { + return new SubMapKeyIterator(); + } + + Iterator valueIterator() { + return new SubMapValueIterator(); + } + + Iterator> entryIterator() { + return new SubMapEntryIterator(); + } + + /** + * Variant of main Iter class to traverse through submaps. + */ + abstract class SubMapIter implements Iterator { + /** the last node returned by next() */ + Node lastReturned; + /** the next node to return from next(); */ + Node next; + /** Cache of next value field to maintain weak consistency */ + V nextValue; + + SubMapIter() { + for (;;) { + next = isDescending ? hiNode() : loNode(); + if (next == null) + break; + Object x = next.value; + if (x != null && x != next) { + if (! inBounds(next.key)) + next = null; + else + nextValue = (V) x; + break; + } + } + } + + public final boolean hasNext() { + return next != null; + } + + final void advance() { + if (next == null) + throw new NoSuchElementException(); + lastReturned = next; + if (isDescending) + descend(); + else + ascend(); + } + + private void ascend() { + for (;;) { + next = next.next; + if (next == null) + break; + Object x = next.value; + if (x != null && x != next) { + if (tooHigh(next.key)) + next = null; + else + nextValue = (V) x; + break; + } + } + } + + private void descend() { + for (;;) { + next = m.findNear(lastReturned.key, LT); + if (next == null) + break; + Object x = next.value; + if (x != null && x != next) { + if (tooLow(next.key)) + next = null; + else + nextValue = (V) x; + break; + } + } + } + + public void remove() { + Node l = lastReturned; + if (l == null) + throw new IllegalStateException(); + m.remove(l.key); + lastReturned = null; + } + + } + + final class SubMapValueIterator extends SubMapIter { + public V next() { + V v = nextValue; + advance(); + return v; + } + } + + final class SubMapKeyIterator extends SubMapIter { + public K next() { + Node n = next; + advance(); + return n.key; + } + } + + final class SubMapEntryIterator extends SubMapIter> { + public Map.Entry next() { + Node n = next; + V v = nextValue; + advance(); + return new AbstractMap.SimpleImmutableEntry(n.key, v); + } + } + } + + // Unsafe mechanics + private static final sun.misc.Unsafe UNSAFE; + private static final long headOffset; + static { + try { + UNSAFE = sun.misc.Unsafe.getUnsafe(); + Class k = ConcurrentSkipListMap.class; + headOffset = UNSAFE.objectFieldOffset + (k.getDeclaredField("head")); + } catch (Exception e) { + throw new Error(e); + } + } +} diff -r e1953d8b8338 -r c8af252ea9eb rt/emul/compact/src/main/java/java/util/concurrent/ConcurrentSkipListSet.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/ConcurrentSkipListSet.java Sat Mar 19 10:48:29 2016 +0100 @@ -0,0 +1,491 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +package java.util.concurrent; +import java.util.*; +import sun.misc.Unsafe; + +/** + * A scalable concurrent {@link NavigableSet} implementation based on + * a {@link ConcurrentSkipListMap}. The elements of the set are kept + * sorted according to their {@linkplain Comparable natural ordering}, + * or by a {@link Comparator} provided at set creation time, depending + * on which constructor is used. + * + *

This implementation provides expected average log(n) time + * cost for the contains, add, and remove + * operations and their variants. Insertion, removal, and access + * operations safely execute concurrently by multiple threads. + * Iterators are weakly consistent, returning elements + * reflecting the state of the set at some point at or since the + * creation of the iterator. They do not throw {@link + * ConcurrentModificationException}, and may proceed concurrently with + * other operations. Ascending ordered views and their iterators are + * faster than descending ones. + * + *

Beware that, unlike in most collections, the size + * method is not a constant-time operation. Because of the + * asynchronous nature of these sets, determining the current number + * of elements requires a traversal of the elements, and so may report + * inaccurate results if this collection is modified during traversal. + * Additionally, the bulk operations addAll, + * removeAll, retainAll, containsAll, + * equals, and toArray are not guaranteed + * to be performed atomically. For example, an iterator operating + * concurrently with an addAll operation might view only some + * of the added elements. + * + *

This class and its iterators implement all of the + * optional methods of the {@link Set} and {@link Iterator} + * interfaces. Like most other concurrent collection implementations, + * this class does not permit the use of null elements, + * because null arguments and return values cannot be reliably + * distinguished from the absence of elements. + * + *

This class is a member of the + * + * Java Collections Framework. + * + * @author Doug Lea + * @param the type of elements maintained by this set + * @since 1.6 + */ +public class ConcurrentSkipListSet + extends AbstractSet + implements NavigableSet, Cloneable, java.io.Serializable { + + private static final long serialVersionUID = -2479143111061671589L; + + /** + * The underlying map. Uses Boolean.TRUE as value for each + * element. This field is declared final for the sake of thread + * safety, which entails some ugliness in clone() + */ + private final ConcurrentNavigableMap m; + + /** + * Constructs a new, empty set that orders its elements according to + * their {@linkplain Comparable natural ordering}. + */ + public ConcurrentSkipListSet() { + m = new ConcurrentSkipListMap(); + } + + /** + * Constructs a new, empty set that orders its elements according to + * the specified comparator. + * + * @param comparator the comparator that will be used to order this set. + * If null, the {@linkplain Comparable natural + * ordering} of the elements will be used. + */ + public ConcurrentSkipListSet(Comparator comparator) { + m = new ConcurrentSkipListMap(comparator); + } + + /** + * Constructs a new set containing the elements in the specified + * collection, that orders its elements according to their + * {@linkplain Comparable natural ordering}. + * + * @param c The elements that will comprise the new set + * @throws ClassCastException if the elements in c are + * not {@link Comparable}, or are not mutually comparable + * @throws NullPointerException if the specified collection or any + * of its elements are null + */ + public ConcurrentSkipListSet(Collection c) { + m = new ConcurrentSkipListMap(); + addAll(c); + } + + /** + * Constructs a new set containing the same elements and using the + * same ordering as the specified sorted set. + * + * @param s sorted set whose elements will comprise the new set + * @throws NullPointerException if the specified sorted set or any + * of its elements are null + */ + public ConcurrentSkipListSet(SortedSet s) { + m = new ConcurrentSkipListMap(s.comparator()); + addAll(s); + } + + /** + * For use by submaps + */ + ConcurrentSkipListSet(ConcurrentNavigableMap m) { + this.m = m; + } + + /** + * Returns a shallow copy of this ConcurrentSkipListSet + * instance. (The elements themselves are not cloned.) + * + * @return a shallow copy of this set + */ + public ConcurrentSkipListSet clone() { + ConcurrentSkipListSet clone = null; + try { + clone = (ConcurrentSkipListSet) super.clone(); + clone.setMap(new ConcurrentSkipListMap(m)); + } catch (CloneNotSupportedException e) { + throw new InternalError(); + } + + return clone; + } + + /* ---------------- Set operations -------------- */ + + /** + * Returns the number of elements in this set. If this set + * contains more than Integer.MAX_VALUE elements, it + * returns Integer.MAX_VALUE. + * + *

Beware that, unlike in most collections, this method is + * NOT a constant-time operation. Because of the + * asynchronous nature of these sets, determining the current + * number of elements requires traversing them all to count them. + * Additionally, it is possible for the size to change during + * execution of this method, in which case the returned result + * will be inaccurate. Thus, this method is typically not very + * useful in concurrent applications. + * + * @return the number of elements in this set + */ + public int size() { + return m.size(); + } + + /** + * Returns true if this set contains no elements. + * @return true if this set contains no elements + */ + public boolean isEmpty() { + return m.isEmpty(); + } + + /** + * Returns true if this set contains the specified element. + * More formally, returns true if and only if this set + * contains an element e such that o.equals(e). + * + * @param o object to be checked for containment in this set + * @return true if this set contains the specified element + * @throws ClassCastException if the specified element cannot be + * compared with the elements currently in this set + * @throws NullPointerException if the specified element is null + */ + public boolean contains(Object o) { + return m.containsKey(o); + } + + /** + * Adds the specified element to this set if it is not already present. + * More formally, adds the specified element e to this set if + * the set contains no element e2 such that e.equals(e2). + * If this set already contains the element, the call leaves the set + * unchanged and returns false. + * + * @param e element to be added to this set + * @return true if this set did not already contain the + * specified element + * @throws ClassCastException if e cannot be compared + * with the elements currently in this set + * @throws NullPointerException if the specified element is null + */ + public boolean add(E e) { + return m.putIfAbsent(e, Boolean.TRUE) == null; + } + + /** + * Removes the specified element from this set if it is present. + * More formally, removes an element e such that + * o.equals(e), if this set contains such an element. + * Returns true if this set contained the element (or + * equivalently, if this set changed as a result of the call). + * (This set will not contain the element once the call returns.) + * + * @param o object to be removed from this set, if present + * @return true if this set contained the specified element + * @throws ClassCastException if o cannot be compared + * with the elements currently in this set + * @throws NullPointerException if the specified element is null + */ + public boolean remove(Object o) { + return m.remove(o, Boolean.TRUE); + } + + /** + * Removes all of the elements from this set. + */ + public void clear() { + m.clear(); + } + + /** + * Returns an iterator over the elements in this set in ascending order. + * + * @return an iterator over the elements in this set in ascending order + */ + public Iterator iterator() { + return m.navigableKeySet().iterator(); + } + + /** + * Returns an iterator over the elements in this set in descending order. + * + * @return an iterator over the elements in this set in descending order + */ + public Iterator descendingIterator() { + return m.descendingKeySet().iterator(); + } + + + /* ---------------- AbstractSet Overrides -------------- */ + + /** + * Compares the specified object with this set for equality. Returns + * true if the specified object is also a set, the two sets + * have the same size, and every member of the specified set is + * contained in this set (or equivalently, every member of this set is + * contained in the specified set). This definition ensures that the + * equals method works properly across different implementations of the + * set interface. + * + * @param o the object to be compared for equality with this set + * @return true if the specified object is equal to this set + */ + public boolean equals(Object o) { + // Override AbstractSet version to avoid calling size() + if (o == this) + return true; + if (!(o instanceof Set)) + return false; + Collection c = (Collection) o; + try { + return containsAll(c) && c.containsAll(this); + } catch (ClassCastException unused) { + return false; + } catch (NullPointerException unused) { + return false; + } + } + + /** + * Removes from this set all of its elements that are contained in + * the specified collection. If the specified collection is also + * a set, this operation effectively modifies this set so that its + * value is the asymmetric set difference of the two sets. + * + * @param c collection containing elements to be removed from this set + * @return true if this set changed as a result of the call + * @throws ClassCastException if the types of one or more elements in this + * set are incompatible with the specified collection + * @throws NullPointerException if the specified collection or any + * of its elements are null + */ + public boolean removeAll(Collection c) { + // Override AbstractSet version to avoid unnecessary call to size() + boolean modified = false; + for (Iterator i = c.iterator(); i.hasNext(); ) + if (remove(i.next())) + modified = true; + return modified; + } + + /* ---------------- Relational operations -------------- */ + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if the specified element is null + */ + public E lower(E e) { + return m.lowerKey(e); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if the specified element is null + */ + public E floor(E e) { + return m.floorKey(e); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if the specified element is null + */ + public E ceiling(E e) { + return m.ceilingKey(e); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if the specified element is null + */ + public E higher(E e) { + return m.higherKey(e); + } + + public E pollFirst() { + Map.Entry e = m.pollFirstEntry(); + return (e == null) ? null : e.getKey(); + } + + public E pollLast() { + Map.Entry e = m.pollLastEntry(); + return (e == null) ? null : e.getKey(); + } + + + /* ---------------- SortedSet operations -------------- */ + + + public Comparator comparator() { + return m.comparator(); + } + + /** + * @throws NoSuchElementException {@inheritDoc} + */ + public E first() { + return m.firstKey(); + } + + /** + * @throws NoSuchElementException {@inheritDoc} + */ + public E last() { + return m.lastKey(); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if {@code fromElement} or + * {@code toElement} is null + * @throws IllegalArgumentException {@inheritDoc} + */ + public NavigableSet subSet(E fromElement, + boolean fromInclusive, + E toElement, + boolean toInclusive) { + return new ConcurrentSkipListSet + (m.subMap(fromElement, fromInclusive, + toElement, toInclusive)); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if {@code toElement} is null + * @throws IllegalArgumentException {@inheritDoc} + */ + public NavigableSet headSet(E toElement, boolean inclusive) { + return new ConcurrentSkipListSet(m.headMap(toElement, inclusive)); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if {@code fromElement} is null + * @throws IllegalArgumentException {@inheritDoc} + */ + public NavigableSet tailSet(E fromElement, boolean inclusive) { + return new ConcurrentSkipListSet(m.tailMap(fromElement, inclusive)); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if {@code fromElement} or + * {@code toElement} is null + * @throws IllegalArgumentException {@inheritDoc} + */ + public NavigableSet subSet(E fromElement, E toElement) { + return subSet(fromElement, true, toElement, false); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if {@code toElement} is null + * @throws IllegalArgumentException {@inheritDoc} + */ + public NavigableSet headSet(E toElement) { + return headSet(toElement, false); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if {@code fromElement} is null + * @throws IllegalArgumentException {@inheritDoc} + */ + public NavigableSet tailSet(E fromElement) { + return tailSet(fromElement, true); + } + + /** + * Returns a reverse order view of the elements contained in this set. + * The descending set is backed by this set, so changes to the set are + * reflected in the descending set, and vice-versa. + * + *

The returned set has an ordering equivalent to + * {@link Collections#reverseOrder(Comparator) Collections.reverseOrder}(comparator()). + * The expression {@code s.descendingSet().descendingSet()} returns a + * view of {@code s} essentially equivalent to {@code s}. + * + * @return a reverse order view of this set + */ + public NavigableSet descendingSet() { + return new ConcurrentSkipListSet(m.descendingMap()); + } + + // Support for resetting map in clone + private void setMap(ConcurrentNavigableMap map) { + UNSAFE.putObjectVolatile(this, mapOffset, map); + } + + private static final sun.misc.Unsafe UNSAFE; + private static final long mapOffset; + static { + try { + UNSAFE = sun.misc.Unsafe.getUnsafe(); + Class k = ConcurrentSkipListSet.class; + mapOffset = UNSAFE.objectFieldOffset + (k.getDeclaredField("m")); + } catch (Exception e) { + throw new Error(e); + } + } +} diff -r e1953d8b8338 -r c8af252ea9eb rt/emul/compact/src/main/java/java/util/concurrent/CopyOnWriteArrayList.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/CopyOnWriteArrayList.java Sat Mar 19 10:48:29 2016 +0100 @@ -0,0 +1,1340 @@ +/* + * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group. Adapted and released, under explicit permission, + * from JDK ArrayList.java which carries the following copyright: + * + * Copyright 1997 by Sun Microsystems, Inc., + * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A. + * All rights reserved. + */ + +package java.util.concurrent; +import java.util.*; +import java.util.concurrent.locks.*; +import sun.misc.Unsafe; + +/** + * A thread-safe variant of {@link java.util.ArrayList} in which all mutative + * operations (add, set, and so on) are implemented by + * making a fresh copy of the underlying array. + * + *

This is ordinarily too costly, but may be more efficient + * than alternatives when traversal operations vastly outnumber + * mutations, and is useful when you cannot or don't want to + * synchronize traversals, yet need to preclude interference among + * concurrent threads. The "snapshot" style iterator method uses a + * reference to the state of the array at the point that the iterator + * was created. This array never changes during the lifetime of the + * iterator, so interference is impossible and the iterator is + * guaranteed not to throw ConcurrentModificationException. + * The iterator will not reflect additions, removals, or changes to + * the list since the iterator was created. Element-changing + * operations on iterators themselves (remove, set, and + * add) are not supported. These methods throw + * UnsupportedOperationException. + * + *

All elements are permitted, including null. + * + *

Memory consistency effects: As with other concurrent + * collections, actions in a thread prior to placing an object into a + * {@code CopyOnWriteArrayList} + * happen-before + * actions subsequent to the access or removal of that element from + * the {@code CopyOnWriteArrayList} in another thread. + * + *

This class is a member of the + * + * Java Collections Framework. + * + * @since 1.5 + * @author Doug Lea + * @param the type of elements held in this collection + */ +public class CopyOnWriteArrayList + implements List, RandomAccess, Cloneable, java.io.Serializable { + private static final long serialVersionUID = 8673264195747942595L; + + /** The lock protecting all mutators */ + transient final ReentrantLock lock = new ReentrantLock(); + + /** The array, accessed only via getArray/setArray. */ + private volatile transient Object[] array; + + /** + * Gets the array. Non-private so as to also be accessible + * from CopyOnWriteArraySet class. + */ + final Object[] getArray() { + return array; + } + + /** + * Sets the array. + */ + final void setArray(Object[] a) { + array = a; + } + + /** + * Creates an empty list. + */ + public CopyOnWriteArrayList() { + setArray(new Object[0]); + } + + /** + * Creates a list containing the elements of the specified + * collection, in the order they are returned by the collection's + * iterator. + * + * @param c the collection of initially held elements + * @throws NullPointerException if the specified collection is null + */ + public CopyOnWriteArrayList(Collection c) { + Object[] elements = c.toArray(); + // c.toArray might (incorrectly) not return Object[] (see 6260652) + if (elements.getClass() != Object[].class) + elements = Arrays.copyOf(elements, elements.length, Object[].class); + setArray(elements); + } + + /** + * Creates a list holding a copy of the given array. + * + * @param toCopyIn the array (a copy of this array is used as the + * internal array) + * @throws NullPointerException if the specified array is null + */ + public CopyOnWriteArrayList(E[] toCopyIn) { + setArray(Arrays.copyOf(toCopyIn, toCopyIn.length, Object[].class)); + } + + /** + * Returns the number of elements in this list. + * + * @return the number of elements in this list + */ + public int size() { + return getArray().length; + } + + /** + * Returns true if this list contains no elements. + * + * @return true if this list contains no elements + */ + public boolean isEmpty() { + return size() == 0; + } + + /** + * Test for equality, coping with nulls. + */ + private static boolean eq(Object o1, Object o2) { + return (o1 == null ? o2 == null : o1.equals(o2)); + } + + /** + * static version of indexOf, to allow repeated calls without + * needing to re-acquire array each time. + * @param o element to search for + * @param elements the array + * @param index first index to search + * @param fence one past last index to search + * @return index of element, or -1 if absent + */ + private static int indexOf(Object o, Object[] elements, + int index, int fence) { + if (o == null) { + for (int i = index; i < fence; i++) + if (elements[i] == null) + return i; + } else { + for (int i = index; i < fence; i++) + if (o.equals(elements[i])) + return i; + } + return -1; + } + + /** + * static version of lastIndexOf. + * @param o element to search for + * @param elements the array + * @param index first index to search + * @return index of element, or -1 if absent + */ + private static int lastIndexOf(Object o, Object[] elements, int index) { + if (o == null) { + for (int i = index; i >= 0; i--) + if (elements[i] == null) + return i; + } else { + for (int i = index; i >= 0; i--) + if (o.equals(elements[i])) + return i; + } + return -1; + } + + /** + * Returns true if this list contains the specified element. + * More formally, returns true if and only if this list contains + * at least one element e such that + * (o==null ? e==null : o.equals(e)). + * + * @param o element whose presence in this list is to be tested + * @return true if this list contains the specified element + */ + public boolean contains(Object o) { + Object[] elements = getArray(); + return indexOf(o, elements, 0, elements.length) >= 0; + } + + /** + * {@inheritDoc} + */ + public int indexOf(Object o) { + Object[] elements = getArray(); + return indexOf(o, elements, 0, elements.length); + } + + /** + * Returns the index of the first occurrence of the specified element in + * this list, searching forwards from index, or returns -1 if + * the element is not found. + * More formally, returns the lowest index i such that + * (i >= index && (e==null ? get(i)==null : e.equals(get(i)))), + * or -1 if there is no such index. + * + * @param e element to search for + * @param index index to start searching from + * @return the index of the first occurrence of the element in + * this list at position index or later in the list; + * -1 if the element is not found. + * @throws IndexOutOfBoundsException if the specified index is negative + */ + public int indexOf(E e, int index) { + Object[] elements = getArray(); + return indexOf(e, elements, index, elements.length); + } + + /** + * {@inheritDoc} + */ + public int lastIndexOf(Object o) { + Object[] elements = getArray(); + return lastIndexOf(o, elements, elements.length - 1); + } + + /** + * Returns the index of the last occurrence of the specified element in + * this list, searching backwards from index, or returns -1 if + * the element is not found. + * More formally, returns the highest index i such that + * (i <= index && (e==null ? get(i)==null : e.equals(get(i)))), + * or -1 if there is no such index. + * + * @param e element to search for + * @param index index to start searching backwards from + * @return the index of the last occurrence of the element at position + * less than or equal to index in this list; + * -1 if the element is not found. + * @throws IndexOutOfBoundsException if the specified index is greater + * than or equal to the current size of this list + */ + public int lastIndexOf(E e, int index) { + Object[] elements = getArray(); + return lastIndexOf(e, elements, index); + } + + /** + * Returns a shallow copy of this list. (The elements themselves + * are not copied.) + * + * @return a clone of this list + */ + public Object clone() { + try { + CopyOnWriteArrayList c = (CopyOnWriteArrayList)(super.clone()); + c.resetLock(); + return c; + } catch (CloneNotSupportedException e) { + // this shouldn't happen, since we are Cloneable + throw new InternalError(); + } + } + + /** + * Returns an array containing all of the elements in this list + * in proper sequence (from first to last element). + * + *

The returned array will be "safe" in that no references to it are + * maintained by this list. (In other words, this method must allocate + * a new array). The caller is thus free to modify the returned array. + * + *

This method acts as bridge between array-based and collection-based + * APIs. + * + * @return an array containing all the elements in this list + */ + public Object[] toArray() { + Object[] elements = getArray(); + return Arrays.copyOf(elements, elements.length); + } + + /** + * Returns an array containing all of the elements in this list in + * proper sequence (from first to last element); the runtime type of + * the returned array is that of the specified array. If the list fits + * in the specified array, it is returned therein. Otherwise, a new + * array is allocated with the runtime type of the specified array and + * the size of this list. + * + *

If this list fits in the specified array with room to spare + * (i.e., the array has more elements than this list), the element in + * the array immediately following the end of the list is set to + * null. (This is useful in determining the length of this + * list only if the caller knows that this list does not contain + * any null elements.) + * + *

Like the {@link #toArray()} method, this method acts as bridge between + * array-based and collection-based APIs. Further, this method allows + * precise control over the runtime type of the output array, and may, + * under certain circumstances, be used to save allocation costs. + * + *

Suppose x is a list known to contain only strings. + * The following code can be used to dump the list into a newly + * allocated array of String: + * + *

+     *     String[] y = x.toArray(new String[0]);
+ * + * Note that toArray(new Object[0]) is identical in function to + * toArray(). + * + * @param a the array into which the elements of the list are to + * be stored, if it is big enough; otherwise, a new array of the + * same runtime type is allocated for this purpose. + * @return an array containing all the elements in this list + * @throws ArrayStoreException if the runtime type of the specified array + * is not a supertype of the runtime type of every element in + * this list + * @throws NullPointerException if the specified array is null + */ + @SuppressWarnings("unchecked") + public T[] toArray(T a[]) { + Object[] elements = getArray(); + int len = elements.length; + if (a.length < len) + return (T[]) Arrays.copyOf(elements, len, a.getClass()); + else { + System.arraycopy(elements, 0, a, 0, len); + if (a.length > len) + a[len] = null; + return a; + } + } + + // Positional Access Operations + + @SuppressWarnings("unchecked") + private E get(Object[] a, int index) { + return (E) a[index]; + } + + /** + * {@inheritDoc} + * + * @throws IndexOutOfBoundsException {@inheritDoc} + */ + public E get(int index) { + return get(getArray(), index); + } + + /** + * Replaces the element at the specified position in this list with the + * specified element. + * + * @throws IndexOutOfBoundsException {@inheritDoc} + */ + public E set(int index, E element) { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + Object[] elements = getArray(); + E oldValue = get(elements, index); + + if (oldValue != element) { + int len = elements.length; + Object[] newElements = Arrays.copyOf(elements, len); + newElements[index] = element; + setArray(newElements); + } else { + // Not quite a no-op; ensures volatile write semantics + setArray(elements); + } + return oldValue; + } finally { + lock.unlock(); + } + } + + /** + * Appends the specified element to the end of this list. + * + * @param e element to be appended to this list + * @return true (as specified by {@link Collection#add}) + */ + public boolean add(E e) { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + Object[] elements = getArray(); + int len = elements.length; + Object[] newElements = Arrays.copyOf(elements, len + 1); + newElements[len] = e; + setArray(newElements); + return true; + } finally { + lock.unlock(); + } + } + + /** + * Inserts the specified element at the specified position in this + * list. Shifts the element currently at that position (if any) and + * any subsequent elements to the right (adds one to their indices). + * + * @throws IndexOutOfBoundsException {@inheritDoc} + */ + public void add(int index, E element) { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + Object[] elements = getArray(); + int len = elements.length; + if (index > len || index < 0) + throw new IndexOutOfBoundsException("Index: "+index+ + ", Size: "+len); + Object[] newElements; + int numMoved = len - index; + if (numMoved == 0) + newElements = Arrays.copyOf(elements, len + 1); + else { + newElements = new Object[len + 1]; + System.arraycopy(elements, 0, newElements, 0, index); + System.arraycopy(elements, index, newElements, index + 1, + numMoved); + } + newElements[index] = element; + setArray(newElements); + } finally { + lock.unlock(); + } + } + + /** + * Removes the element at the specified position in this list. + * Shifts any subsequent elements to the left (subtracts one from their + * indices). Returns the element that was removed from the list. + * + * @throws IndexOutOfBoundsException {@inheritDoc} + */ + public E remove(int index) { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + Object[] elements = getArray(); + int len = elements.length; + E oldValue = get(elements, index); + int numMoved = len - index - 1; + if (numMoved == 0) + setArray(Arrays.copyOf(elements, len - 1)); + else { + Object[] newElements = new Object[len - 1]; + System.arraycopy(elements, 0, newElements, 0, index); + System.arraycopy(elements, index + 1, newElements, index, + numMoved); + setArray(newElements); + } + return oldValue; + } finally { + lock.unlock(); + } + } + + /** + * Removes the first occurrence of the specified element from this list, + * if it is present. If this list does not contain the element, it is + * unchanged. More formally, removes the element with the lowest index + * i such that + * (o==null ? get(i)==null : o.equals(get(i))) + * (if such an element exists). Returns true if this list + * contained the specified element (or equivalently, if this list + * changed as a result of the call). + * + * @param o element to be removed from this list, if present + * @return true if this list contained the specified element + */ + public boolean remove(Object o) { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + Object[] elements = getArray(); + int len = elements.length; + if (len != 0) { + // Copy while searching for element to remove + // This wins in the normal case of element being present + int newlen = len - 1; + Object[] newElements = new Object[newlen]; + + for (int i = 0; i < newlen; ++i) { + if (eq(o, elements[i])) { + // found one; copy remaining and exit + for (int k = i + 1; k < len; ++k) + newElements[k-1] = elements[k]; + setArray(newElements); + return true; + } else + newElements[i] = elements[i]; + } + + // special handling for last cell + if (eq(o, elements[newlen])) { + setArray(newElements); + return true; + } + } + return false; + } finally { + lock.unlock(); + } + } + + /** + * Removes from this list all of the elements whose index is between + * fromIndex, inclusive, and toIndex, exclusive. + * Shifts any succeeding elements to the left (reduces their index). + * This call shortens the list by (toIndex - fromIndex) elements. + * (If toIndex==fromIndex, this operation has no effect.) + * + * @param fromIndex index of first element to be removed + * @param toIndex index after last element to be removed + * @throws IndexOutOfBoundsException if fromIndex or toIndex out of range + * ({@code{fromIndex < 0 || toIndex > size() || toIndex < fromIndex}) + */ + private void removeRange(int fromIndex, int toIndex) { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + Object[] elements = getArray(); + int len = elements.length; + + if (fromIndex < 0 || toIndex > len || toIndex < fromIndex) + throw new IndexOutOfBoundsException(); + int newlen = len - (toIndex - fromIndex); + int numMoved = len - toIndex; + if (numMoved == 0) + setArray(Arrays.copyOf(elements, newlen)); + else { + Object[] newElements = new Object[newlen]; + System.arraycopy(elements, 0, newElements, 0, fromIndex); + System.arraycopy(elements, toIndex, newElements, + fromIndex, numMoved); + setArray(newElements); + } + } finally { + lock.unlock(); + } + } + + /** + * Append the element if not present. + * + * @param e element to be added to this list, if absent + * @return true if the element was added + */ + public boolean addIfAbsent(E e) { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + // Copy while checking if already present. + // This wins in the most common case where it is not present + Object[] elements = getArray(); + int len = elements.length; + Object[] newElements = new Object[len + 1]; + for (int i = 0; i < len; ++i) { + if (eq(e, elements[i])) + return false; // exit, throwing away copy + else + newElements[i] = elements[i]; + } + newElements[len] = e; + setArray(newElements); + return true; + } finally { + lock.unlock(); + } + } + + /** + * Returns true if this list contains all of the elements of the + * specified collection. + * + * @param c collection to be checked for containment in this list + * @return true if this list contains all of the elements of the + * specified collection + * @throws NullPointerException if the specified collection is null + * @see #contains(Object) + */ + public boolean containsAll(Collection c) { + Object[] elements = getArray(); + int len = elements.length; + for (Object e : c) { + if (indexOf(e, elements, 0, len) < 0) + return false; + } + return true; + } + + /** + * Removes from this list all of its elements that are contained in + * the specified collection. This is a particularly expensive operation + * in this class because of the need for an internal temporary array. + * + * @param c collection containing elements to be removed from this list + * @return true if this list changed as a result of the call + * @throws ClassCastException if the class of an element of this list + * is incompatible with the specified collection + * (optional) + * @throws NullPointerException if this list contains a null element and the + * specified collection does not permit null elements + * (optional), + * or if the specified collection is null + * @see #remove(Object) + */ + public boolean removeAll(Collection c) { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + Object[] elements = getArray(); + int len = elements.length; + if (len != 0) { + // temp array holds those elements we know we want to keep + int newlen = 0; + Object[] temp = new Object[len]; + for (int i = 0; i < len; ++i) { + Object element = elements[i]; + if (!c.contains(element)) + temp[newlen++] = element; + } + if (newlen != len) { + setArray(Arrays.copyOf(temp, newlen)); + return true; + } + } + return false; + } finally { + lock.unlock(); + } + } + + /** + * Retains only the elements in this list that are contained in the + * specified collection. In other words, removes from this list all of + * its elements that are not contained in the specified collection. + * + * @param c collection containing elements to be retained in this list + * @return true if this list changed as a result of the call + * @throws ClassCastException if the class of an element of this list + * is incompatible with the specified collection + * (optional) + * @throws NullPointerException if this list contains a null element and the + * specified collection does not permit null elements + * (optional), + * or if the specified collection is null + * @see #remove(Object) + */ + public boolean retainAll(Collection c) { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + Object[] elements = getArray(); + int len = elements.length; + if (len != 0) { + // temp array holds those elements we know we want to keep + int newlen = 0; + Object[] temp = new Object[len]; + for (int i = 0; i < len; ++i) { + Object element = elements[i]; + if (c.contains(element)) + temp[newlen++] = element; + } + if (newlen != len) { + setArray(Arrays.copyOf(temp, newlen)); + return true; + } + } + return false; + } finally { + lock.unlock(); + } + } + + /** + * Appends all of the elements in the specified collection that + * are not already contained in this list, to the end of + * this list, in the order that they are returned by the + * specified collection's iterator. + * + * @param c collection containing elements to be added to this list + * @return the number of elements added + * @throws NullPointerException if the specified collection is null + * @see #addIfAbsent(Object) + */ + public int addAllAbsent(Collection c) { + Object[] cs = c.toArray(); + if (cs.length == 0) + return 0; + Object[] uniq = new Object[cs.length]; + final ReentrantLock lock = this.lock; + lock.lock(); + try { + Object[] elements = getArray(); + int len = elements.length; + int added = 0; + for (int i = 0; i < cs.length; ++i) { // scan for duplicates + Object e = cs[i]; + if (indexOf(e, elements, 0, len) < 0 && + indexOf(e, uniq, 0, added) < 0) + uniq[added++] = e; + } + if (added > 0) { + Object[] newElements = Arrays.copyOf(elements, len + added); + System.arraycopy(uniq, 0, newElements, len, added); + setArray(newElements); + } + return added; + } finally { + lock.unlock(); + } + } + + /** + * Removes all of the elements from this list. + * The list will be empty after this call returns. + */ + public void clear() { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + setArray(new Object[0]); + } finally { + lock.unlock(); + } + } + + /** + * Appends all of the elements in the specified collection to the end + * of this list, in the order that they are returned by the specified + * collection's iterator. + * + * @param c collection containing elements to be added to this list + * @return true if this list changed as a result of the call + * @throws NullPointerException if the specified collection is null + * @see #add(Object) + */ + public boolean addAll(Collection c) { + Object[] cs = c.toArray(); + if (cs.length == 0) + return false; + final ReentrantLock lock = this.lock; + lock.lock(); + try { + Object[] elements = getArray(); + int len = elements.length; + Object[] newElements = Arrays.copyOf(elements, len + cs.length); + System.arraycopy(cs, 0, newElements, len, cs.length); + setArray(newElements); + return true; + } finally { + lock.unlock(); + } + } + + /** + * Inserts all of the elements in the specified collection into this + * list, starting at the specified position. Shifts the element + * currently at that position (if any) and any subsequent elements to + * the right (increases their indices). The new elements will appear + * in this list in the order that they are returned by the + * specified collection's iterator. + * + * @param index index at which to insert the first element + * from the specified collection + * @param c collection containing elements to be added to this list + * @return true if this list changed as a result of the call + * @throws IndexOutOfBoundsException {@inheritDoc} + * @throws NullPointerException if the specified collection is null + * @see #add(int,Object) + */ + public boolean addAll(int index, Collection c) { + Object[] cs = c.toArray(); + final ReentrantLock lock = this.lock; + lock.lock(); + try { + Object[] elements = getArray(); + int len = elements.length; + if (index > len || index < 0) + throw new IndexOutOfBoundsException("Index: "+index+ + ", Size: "+len); + if (cs.length == 0) + return false; + int numMoved = len - index; + Object[] newElements; + if (numMoved == 0) + newElements = Arrays.copyOf(elements, len + cs.length); + else { + newElements = new Object[len + cs.length]; + System.arraycopy(elements, 0, newElements, 0, index); + System.arraycopy(elements, index, + newElements, index + cs.length, + numMoved); + } + System.arraycopy(cs, 0, newElements, index, cs.length); + setArray(newElements); + return true; + } finally { + lock.unlock(); + } + } + + /** + * Saves the state of the list to a stream (that is, serializes it). + * + * @serialData The length of the array backing the list is emitted + * (int), followed by all of its elements (each an Object) + * in the proper order. + * @param s the stream + */ + private void writeObject(java.io.ObjectOutputStream s) + throws java.io.IOException{ + + s.defaultWriteObject(); + + Object[] elements = getArray(); + // Write out array length + s.writeInt(elements.length); + + // Write out all elements in the proper order. + for (Object element : elements) + s.writeObject(element); + } + + /** + * Reconstitutes the list from a stream (that is, deserializes it). + * + * @param s the stream + */ + private void readObject(java.io.ObjectInputStream s) + throws java.io.IOException, ClassNotFoundException { + + s.defaultReadObject(); + + // bind to new lock + resetLock(); + + // Read in array length and allocate array + int len = s.readInt(); + Object[] elements = new Object[len]; + + // Read in all elements in the proper order. + for (int i = 0; i < len; i++) + elements[i] = s.readObject(); + setArray(elements); + } + + /** + * Returns a string representation of this list. The string + * representation consists of the string representations of the list's + * elements in the order they are returned by its iterator, enclosed in + * square brackets ("[]"). Adjacent elements are separated by + * the characters ", " (comma and space). Elements are + * converted to strings as by {@link String#valueOf(Object)}. + * + * @return a string representation of this list + */ + public String toString() { + return Arrays.toString(getArray()); + } + + /** + * Compares the specified object with this list for equality. + * Returns {@code true} if the specified object is the same object + * as this object, or if it is also a {@link List} and the sequence + * of elements returned by an {@linkplain List#iterator() iterator} + * over the specified list is the same as the sequence returned by + * an iterator over this list. The two sequences are considered to + * be the same if they have the same length and corresponding + * elements at the same position in the sequence are equal. + * Two elements {@code e1} and {@code e2} are considered + * equal if {@code (e1==null ? e2==null : e1.equals(e2))}. + * + * @param o the object to be compared for equality with this list + * @return {@code true} if the specified object is equal to this list + */ + public boolean equals(Object o) { + if (o == this) + return true; + if (!(o instanceof List)) + return false; + + List list = (List)(o); + Iterator it = list.iterator(); + Object[] elements = getArray(); + int len = elements.length; + for (int i = 0; i < len; ++i) + if (!it.hasNext() || !eq(elements[i], it.next())) + return false; + if (it.hasNext()) + return false; + return true; + } + + /** + * Returns the hash code value for this list. + * + *

This implementation uses the definition in {@link List#hashCode}. + * + * @return the hash code value for this list + */ + public int hashCode() { + int hashCode = 1; + Object[] elements = getArray(); + int len = elements.length; + for (int i = 0; i < len; ++i) { + Object obj = elements[i]; + hashCode = 31*hashCode + (obj==null ? 0 : obj.hashCode()); + } + return hashCode; + } + + /** + * Returns an iterator over the elements in this list in proper sequence. + * + *

The returned iterator provides a snapshot of the state of the list + * when the iterator was constructed. No synchronization is needed while + * traversing the iterator. The iterator does NOT support the + * remove method. + * + * @return an iterator over the elements in this list in proper sequence + */ + public Iterator iterator() { + return new COWIterator(getArray(), 0); + } + + /** + * {@inheritDoc} + * + *

The returned iterator provides a snapshot of the state of the list + * when the iterator was constructed. No synchronization is needed while + * traversing the iterator. The iterator does NOT support the + * remove, set or add methods. + */ + public ListIterator listIterator() { + return new COWIterator(getArray(), 0); + } + + /** + * {@inheritDoc} + * + *

The returned iterator provides a snapshot of the state of the list + * when the iterator was constructed. No synchronization is needed while + * traversing the iterator. The iterator does NOT support the + * remove, set or add methods. + * + * @throws IndexOutOfBoundsException {@inheritDoc} + */ + public ListIterator listIterator(final int index) { + Object[] elements = getArray(); + int len = elements.length; + if (index<0 || index>len) + throw new IndexOutOfBoundsException("Index: "+index); + + return new COWIterator(elements, index); + } + + private static class COWIterator implements ListIterator { + /** Snapshot of the array */ + private final Object[] snapshot; + /** Index of element to be returned by subsequent call to next. */ + private int cursor; + + private COWIterator(Object[] elements, int initialCursor) { + cursor = initialCursor; + snapshot = elements; + } + + public boolean hasNext() { + return cursor < snapshot.length; + } + + public boolean hasPrevious() { + return cursor > 0; + } + + @SuppressWarnings("unchecked") + public E next() { + if (! hasNext()) + throw new NoSuchElementException(); + return (E) snapshot[cursor++]; + } + + @SuppressWarnings("unchecked") + public E previous() { + if (! hasPrevious()) + throw new NoSuchElementException(); + return (E) snapshot[--cursor]; + } + + public int nextIndex() { + return cursor; + } + + public int previousIndex() { + return cursor-1; + } + + /** + * Not supported. Always throws UnsupportedOperationException. + * @throws UnsupportedOperationException always; remove + * is not supported by this iterator. + */ + public void remove() { + throw new UnsupportedOperationException(); + } + + /** + * Not supported. Always throws UnsupportedOperationException. + * @throws UnsupportedOperationException always; set + * is not supported by this iterator. + */ + public void set(E e) { + throw new UnsupportedOperationException(); + } + + /** + * Not supported. Always throws UnsupportedOperationException. + * @throws UnsupportedOperationException always; add + * is not supported by this iterator. + */ + public void add(E e) { + throw new UnsupportedOperationException(); + } + } + + /** + * Returns a view of the portion of this list between + * fromIndex, inclusive, and toIndex, exclusive. + * The returned list is backed by this list, so changes in the + * returned list are reflected in this list. + * + *

The semantics of the list returned by this method become + * undefined if the backing list (i.e., this list) is modified in + * any way other than via the returned list. + * + * @param fromIndex low endpoint (inclusive) of the subList + * @param toIndex high endpoint (exclusive) of the subList + * @return a view of the specified range within this list + * @throws IndexOutOfBoundsException {@inheritDoc} + */ + public List subList(int fromIndex, int toIndex) { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + Object[] elements = getArray(); + int len = elements.length; + if (fromIndex < 0 || toIndex > len || fromIndex > toIndex) + throw new IndexOutOfBoundsException(); + return new COWSubList(this, fromIndex, toIndex); + } finally { + lock.unlock(); + } + } + + /** + * Sublist for CopyOnWriteArrayList. + * This class extends AbstractList merely for convenience, to + * avoid having to define addAll, etc. This doesn't hurt, but + * is wasteful. This class does not need or use modCount + * mechanics in AbstractList, but does need to check for + * concurrent modification using similar mechanics. On each + * operation, the array that we expect the backing list to use + * is checked and updated. Since we do this for all of the + * base operations invoked by those defined in AbstractList, + * all is well. While inefficient, this is not worth + * improving. The kinds of list operations inherited from + * AbstractList are already so slow on COW sublists that + * adding a bit more space/time doesn't seem even noticeable. + */ + private static class COWSubList + extends AbstractList + implements RandomAccess + { + private final CopyOnWriteArrayList l; + private final int offset; + private int size; + private Object[] expectedArray; + + // only call this holding l's lock + COWSubList(CopyOnWriteArrayList list, + int fromIndex, int toIndex) { + l = list; + expectedArray = l.getArray(); + offset = fromIndex; + size = toIndex - fromIndex; + } + + // only call this holding l's lock + private void checkForComodification() { + if (l.getArray() != expectedArray) + throw new ConcurrentModificationException(); + } + + // only call this holding l's lock + private void rangeCheck(int index) { + if (index<0 || index>=size) + throw new IndexOutOfBoundsException("Index: "+index+ + ",Size: "+size); + } + + public E set(int index, E element) { + final ReentrantLock lock = l.lock; + lock.lock(); + try { + rangeCheck(index); + checkForComodification(); + E x = l.set(index+offset, element); + expectedArray = l.getArray(); + return x; + } finally { + lock.unlock(); + } + } + + public E get(int index) { + final ReentrantLock lock = l.lock; + lock.lock(); + try { + rangeCheck(index); + checkForComodification(); + return l.get(index+offset); + } finally { + lock.unlock(); + } + } + + public int size() { + final ReentrantLock lock = l.lock; + lock.lock(); + try { + checkForComodification(); + return size; + } finally { + lock.unlock(); + } + } + + public void add(int index, E element) { + final ReentrantLock lock = l.lock; + lock.lock(); + try { + checkForComodification(); + if (index<0 || index>size) + throw new IndexOutOfBoundsException(); + l.add(index+offset, element); + expectedArray = l.getArray(); + size++; + } finally { + lock.unlock(); + } + } + + public void clear() { + final ReentrantLock lock = l.lock; + lock.lock(); + try { + checkForComodification(); + l.removeRange(offset, offset+size); + expectedArray = l.getArray(); + size = 0; + } finally { + lock.unlock(); + } + } + + public E remove(int index) { + final ReentrantLock lock = l.lock; + lock.lock(); + try { + rangeCheck(index); + checkForComodification(); + E result = l.remove(index+offset); + expectedArray = l.getArray(); + size--; + return result; + } finally { + lock.unlock(); + } + } + + public boolean remove(Object o) { + int index = indexOf(o); + if (index == -1) + return false; + remove(index); + return true; + } + + public Iterator iterator() { + final ReentrantLock lock = l.lock; + lock.lock(); + try { + checkForComodification(); + return new COWSubListIterator(l, 0, offset, size); + } finally { + lock.unlock(); + } + } + + public ListIterator listIterator(final int index) { + final ReentrantLock lock = l.lock; + lock.lock(); + try { + checkForComodification(); + if (index<0 || index>size) + throw new IndexOutOfBoundsException("Index: "+index+ + ", Size: "+size); + return new COWSubListIterator(l, index, offset, size); + } finally { + lock.unlock(); + } + } + + public List subList(int fromIndex, int toIndex) { + final ReentrantLock lock = l.lock; + lock.lock(); + try { + checkForComodification(); + if (fromIndex<0 || toIndex>size) + throw new IndexOutOfBoundsException(); + return new COWSubList(l, fromIndex + offset, + toIndex + offset); + } finally { + lock.unlock(); + } + } + + } + + + private static class COWSubListIterator implements ListIterator { + private final ListIterator i; + private final int index; + private final int offset; + private final int size; + + COWSubListIterator(List l, int index, int offset, + int size) { + this.index = index; + this.offset = offset; + this.size = size; + i = l.listIterator(index+offset); + } + + public boolean hasNext() { + return nextIndex() < size; + } + + public E next() { + if (hasNext()) + return i.next(); + else + throw new NoSuchElementException(); + } + + public boolean hasPrevious() { + return previousIndex() >= 0; + } + + public E previous() { + if (hasPrevious()) + return i.previous(); + else + throw new NoSuchElementException(); + } + + public int nextIndex() { + return i.nextIndex() - offset; + } + + public int previousIndex() { + return i.previousIndex() - offset; + } + + public void remove() { + throw new UnsupportedOperationException(); + } + + public void set(E e) { + throw new UnsupportedOperationException(); + } + + public void add(E e) { + throw new UnsupportedOperationException(); + } + } + + // Support for resetting lock while deserializing + private void resetLock() { + UNSAFE.putObjectVolatile(this, lockOffset, new ReentrantLock()); + } + private static final sun.misc.Unsafe UNSAFE; + private static final long lockOffset; + static { + try { + UNSAFE = sun.misc.Unsafe.getUnsafe(); + Class k = CopyOnWriteArrayList.class; + lockOffset = UNSAFE.objectFieldOffset + (k.getDeclaredField("lock")); + } catch (Exception e) { + throw new Error(e); + } + } +} diff -r e1953d8b8338 -r c8af252ea9eb rt/emul/compact/src/main/java/java/util/concurrent/CopyOnWriteArraySet.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/CopyOnWriteArraySet.java Sat Mar 19 10:48:29 2016 +0100 @@ -0,0 +1,392 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +package java.util.concurrent; +import java.util.*; + +/** + * A {@link java.util.Set} that uses an internal {@link CopyOnWriteArrayList} + * for all of its operations. Thus, it shares the same basic properties: + *

    + *
  • It is best suited for applications in which set sizes generally + * stay small, read-only operations + * vastly outnumber mutative operations, and you need + * to prevent interference among threads during traversal. + *
  • It is thread-safe. + *
  • Mutative operations (add, set, remove, etc.) + * are expensive since they usually entail copying the entire underlying + * array. + *
  • Iterators do not support the mutative remove operation. + *
  • Traversal via iterators is fast and cannot encounter + * interference from other threads. Iterators rely on + * unchanging snapshots of the array at the time the iterators were + * constructed. + *
+ * + *

Sample Usage. The following code sketch uses a + * copy-on-write set to maintain a set of Handler objects that + * perform some action upon state updates. + * + *

 {@code
+ * class Handler { void handle(); ... }
+ *
+ * class X {
+ *   private final CopyOnWriteArraySet handlers
+ *     = new CopyOnWriteArraySet();
+ *   public void addHandler(Handler h) { handlers.add(h); }
+ *
+ *   private long internalState;
+ *   private synchronized void changeState() { internalState = ...; }
+ *
+ *   public void update() {
+ *     changeState();
+ *     for (Handler handler : handlers)
+ *        handler.handle();
+ *   }
+ * }}
+ * + *

This class is a member of the + * + * Java Collections Framework. + * + * @see CopyOnWriteArrayList + * @since 1.5 + * @author Doug Lea + * @param the type of elements held in this collection + */ +public class CopyOnWriteArraySet extends AbstractSet + implements java.io.Serializable { + private static final long serialVersionUID = 5457747651344034263L; + + private final CopyOnWriteArrayList al; + + /** + * Creates an empty set. + */ + public CopyOnWriteArraySet() { + al = new CopyOnWriteArrayList(); + } + + /** + * Creates a set containing all of the elements of the specified + * collection. + * + * @param c the collection of elements to initially contain + * @throws NullPointerException if the specified collection is null + */ + public CopyOnWriteArraySet(Collection c) { + al = new CopyOnWriteArrayList(); + al.addAllAbsent(c); + } + + /** + * Returns the number of elements in this set. + * + * @return the number of elements in this set + */ + public int size() { + return al.size(); + } + + /** + * Returns true if this set contains no elements. + * + * @return true if this set contains no elements + */ + public boolean isEmpty() { + return al.isEmpty(); + } + + /** + * Returns true if this set contains the specified element. + * More formally, returns true if and only if this set + * contains an element e such that + * (o==null ? e==null : o.equals(e)). + * + * @param o element whose presence in this set is to be tested + * @return true if this set contains the specified element + */ + public boolean contains(Object o) { + return al.contains(o); + } + + /** + * Returns an array containing all of the elements in this set. + * If this set makes any guarantees as to what order its elements + * are returned by its iterator, this method must return the + * elements in the same order. + * + *

The returned array will be "safe" in that no references to it + * are maintained by this set. (In other words, this method must + * allocate a new array even if this set is backed by an array). + * The caller is thus free to modify the returned array. + * + *

This method acts as bridge between array-based and collection-based + * APIs. + * + * @return an array containing all the elements in this set + */ + public Object[] toArray() { + return al.toArray(); + } + + /** + * Returns an array containing all of the elements in this set; the + * runtime type of the returned array is that of the specified array. + * If the set fits in the specified array, it is returned therein. + * Otherwise, a new array is allocated with the runtime type of the + * specified array and the size of this set. + * + *

If this set fits in the specified array with room to spare + * (i.e., the array has more elements than this set), the element in + * the array immediately following the end of the set is set to + * null. (This is useful in determining the length of this + * set only if the caller knows that this set does not contain + * any null elements.) + * + *

If this set makes any guarantees as to what order its elements + * are returned by its iterator, this method must return the elements + * in the same order. + * + *

Like the {@link #toArray()} method, this method acts as bridge between + * array-based and collection-based APIs. Further, this method allows + * precise control over the runtime type of the output array, and may, + * under certain circumstances, be used to save allocation costs. + * + *

Suppose x is a set known to contain only strings. + * The following code can be used to dump the set into a newly allocated + * array of String: + * + *

+     *     String[] y = x.toArray(new String[0]);
+ * + * Note that toArray(new Object[0]) is identical in function to + * toArray(). + * + * @param a the array into which the elements of this set are to be + * stored, if it is big enough; otherwise, a new array of the same + * runtime type is allocated for this purpose. + * @return an array containing all the elements in this set + * @throws ArrayStoreException if the runtime type of the specified array + * is not a supertype of the runtime type of every element in this + * set + * @throws NullPointerException if the specified array is null + */ + public T[] toArray(T[] a) { + return al.toArray(a); + } + + /** + * Removes all of the elements from this set. + * The set will be empty after this call returns. + */ + public void clear() { + al.clear(); + } + + /** + * Removes the specified element from this set if it is present. + * More formally, removes an element e such that + * (o==null ? e==null : o.equals(e)), + * if this set contains such an element. Returns true if + * this set contained the element (or equivalently, if this set + * changed as a result of the call). (This set will not contain the + * element once the call returns.) + * + * @param o object to be removed from this set, if present + * @return true if this set contained the specified element + */ + public boolean remove(Object o) { + return al.remove(o); + } + + /** + * Adds the specified element to this set if it is not already present. + * More formally, adds the specified element e to this set if + * the set contains no element e2 such that + * (e==null ? e2==null : e.equals(e2)). + * If this set already contains the element, the call leaves the set + * unchanged and returns false. + * + * @param e element to be added to this set + * @return true if this set did not already contain the specified + * element + */ + public boolean add(E e) { + return al.addIfAbsent(e); + } + + /** + * Returns true if this set contains all of the elements of the + * specified collection. If the specified collection is also a set, this + * method returns true if it is a subset of this set. + * + * @param c collection to be checked for containment in this set + * @return true if this set contains all of the elements of the + * specified collection + * @throws NullPointerException if the specified collection is null + * @see #contains(Object) + */ + public boolean containsAll(Collection c) { + return al.containsAll(c); + } + + /** + * Adds all of the elements in the specified collection to this set if + * they're not already present. If the specified collection is also a + * set, the addAll operation effectively modifies this set so + * that its value is the union of the two sets. The behavior of + * this operation is undefined if the specified collection is modified + * while the operation is in progress. + * + * @param c collection containing elements to be added to this set + * @return true if this set changed as a result of the call + * @throws NullPointerException if the specified collection is null + * @see #add(Object) + */ + public boolean addAll(Collection c) { + return al.addAllAbsent(c) > 0; + } + + /** + * Removes from this set all of its elements that are contained in the + * specified collection. If the specified collection is also a set, + * this operation effectively modifies this set so that its value is the + * asymmetric set difference of the two sets. + * + * @param c collection containing elements to be removed from this set + * @return true if this set changed as a result of the call + * @throws ClassCastException if the class of an element of this set + * is incompatible with the specified collection (optional) + * @throws NullPointerException if this set contains a null element and the + * specified collection does not permit null elements (optional), + * or if the specified collection is null + * @see #remove(Object) + */ + public boolean removeAll(Collection c) { + return al.removeAll(c); + } + + /** + * Retains only the elements in this set that are contained in the + * specified collection. In other words, removes from this set all of + * its elements that are not contained in the specified collection. If + * the specified collection is also a set, this operation effectively + * modifies this set so that its value is the intersection of the + * two sets. + * + * @param c collection containing elements to be retained in this set + * @return true if this set changed as a result of the call + * @throws ClassCastException if the class of an element of this set + * is incompatible with the specified collection (optional) + * @throws NullPointerException if this set contains a null element and the + * specified collection does not permit null elements (optional), + * or if the specified collection is null + * @see #remove(Object) + */ + public boolean retainAll(Collection c) { + return al.retainAll(c); + } + + /** + * Returns an iterator over the elements contained in this set + * in the order in which these elements were added. + * + *

The returned iterator provides a snapshot of the state of the set + * when the iterator was constructed. No synchronization is needed while + * traversing the iterator. The iterator does NOT support the + * remove method. + * + * @return an iterator over the elements in this set + */ + public Iterator iterator() { + return al.iterator(); + } + + /** + * Compares the specified object with this set for equality. + * Returns {@code true} if the specified object is the same object + * as this object, or if it is also a {@link Set} and the elements + * returned by an {@linkplain List#iterator() iterator} over the + * specified set are the same as the elements returned by an + * iterator over this set. More formally, the two iterators are + * considered to return the same elements if they return the same + * number of elements and for every element {@code e1} returned by + * the iterator over the specified set, there is an element + * {@code e2} returned by the iterator over this set such that + * {@code (e1==null ? e2==null : e1.equals(e2))}. + * + * @param o object to be compared for equality with this set + * @return {@code true} if the specified object is equal to this set + */ + public boolean equals(Object o) { + if (o == this) + return true; + if (!(o instanceof Set)) + return false; + Set set = (Set)(o); + Iterator it = set.iterator(); + + // Uses O(n^2) algorithm that is only appropriate + // for small sets, which CopyOnWriteArraySets should be. + + // Use a single snapshot of underlying array + Object[] elements = al.getArray(); + int len = elements.length; + // Mark matched elements to avoid re-checking + boolean[] matched = new boolean[len]; + int k = 0; + outer: while (it.hasNext()) { + if (++k > len) + return false; + Object x = it.next(); + for (int i = 0; i < len; ++i) { + if (!matched[i] && eq(x, elements[i])) { + matched[i] = true; + continue outer; + } + } + return false; + } + return k == len; + } + + /** + * Test for equality, coping with nulls. + */ + private static boolean eq(Object o1, Object o2) { + return (o1 == null ? o2 == null : o1.equals(o2)); + } +} diff -r e1953d8b8338 -r c8af252ea9eb rt/emul/compact/src/main/java/java/util/concurrent/CountDownLatch.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/CountDownLatch.java Sat Mar 19 10:48:29 2016 +0100 @@ -0,0 +1,320 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +package java.util.concurrent; +import java.util.concurrent.locks.*; +import java.util.concurrent.atomic.*; + +/** + * A synchronization aid that allows one or more threads to wait until + * a set of operations being performed in other threads completes. + * + *

A {@code CountDownLatch} is initialized with a given count. + * The {@link #await await} methods block until the current count reaches + * zero due to invocations of the {@link #countDown} method, after which + * all waiting threads are released and any subsequent invocations of + * {@link #await await} return immediately. This is a one-shot phenomenon + * -- the count cannot be reset. If you need a version that resets the + * count, consider using a {@link CyclicBarrier}. + * + *

A {@code CountDownLatch} is a versatile synchronization tool + * and can be used for a number of purposes. A + * {@code CountDownLatch} initialized with a count of one serves as a + * simple on/off latch, or gate: all threads invoking {@link #await await} + * wait at the gate until it is opened by a thread invoking {@link + * #countDown}. A {@code CountDownLatch} initialized to N + * can be used to make one thread wait until N threads have + * completed some action, or some action has been completed N times. + * + *

A useful property of a {@code CountDownLatch} is that it + * doesn't require that threads calling {@code countDown} wait for + * the count to reach zero before proceeding, it simply prevents any + * thread from proceeding past an {@link #await await} until all + * threads could pass. + * + *

Sample usage: Here is a pair of classes in which a group + * of worker threads use two countdown latches: + *

    + *
  • The first is a start signal that prevents any worker from proceeding + * until the driver is ready for them to proceed; + *
  • The second is a completion signal that allows the driver to wait + * until all workers have completed. + *
+ * + *
+ * class Driver { // ...
+ *   void main() throws InterruptedException {
+ *     CountDownLatch startSignal = new CountDownLatch(1);
+ *     CountDownLatch doneSignal = new CountDownLatch(N);
+ *
+ *     for (int i = 0; i < N; ++i) // create and start threads
+ *       new Thread(new Worker(startSignal, doneSignal)).start();
+ *
+ *     doSomethingElse();            // don't let run yet
+ *     startSignal.countDown();      // let all threads proceed
+ *     doSomethingElse();
+ *     doneSignal.await();           // wait for all to finish
+ *   }
+ * }
+ *
+ * class Worker implements Runnable {
+ *   private final CountDownLatch startSignal;
+ *   private final CountDownLatch doneSignal;
+ *   Worker(CountDownLatch startSignal, CountDownLatch doneSignal) {
+ *      this.startSignal = startSignal;
+ *      this.doneSignal = doneSignal;
+ *   }
+ *   public void run() {
+ *      try {
+ *        startSignal.await();
+ *        doWork();
+ *        doneSignal.countDown();
+ *      } catch (InterruptedException ex) {} // return;
+ *   }
+ *
+ *   void doWork() { ... }
+ * }
+ *
+ * 
+ * + *

Another typical usage would be to divide a problem into N parts, + * describe each part with a Runnable that executes that portion and + * counts down on the latch, and queue all the Runnables to an + * Executor. When all sub-parts are complete, the coordinating thread + * will be able to pass through await. (When threads must repeatedly + * count down in this way, instead use a {@link CyclicBarrier}.) + * + *

+ * class Driver2 { // ...
+ *   void main() throws InterruptedException {
+ *     CountDownLatch doneSignal = new CountDownLatch(N);
+ *     Executor e = ...
+ *
+ *     for (int i = 0; i < N; ++i) // create and start threads
+ *       e.execute(new WorkerRunnable(doneSignal, i));
+ *
+ *     doneSignal.await();           // wait for all to finish
+ *   }
+ * }
+ *
+ * class WorkerRunnable implements Runnable {
+ *   private final CountDownLatch doneSignal;
+ *   private final int i;
+ *   WorkerRunnable(CountDownLatch doneSignal, int i) {
+ *      this.doneSignal = doneSignal;
+ *      this.i = i;
+ *   }
+ *   public void run() {
+ *      try {
+ *        doWork(i);
+ *        doneSignal.countDown();
+ *      } catch (InterruptedException ex) {} // return;
+ *   }
+ *
+ *   void doWork() { ... }
+ * }
+ *
+ * 
+ * + *

Memory consistency effects: Until the count reaches + * zero, actions in a thread prior to calling + * {@code countDown()} + * happen-before + * actions following a successful return from a corresponding + * {@code await()} in another thread. + * + * @since 1.5 + * @author Doug Lea + */ +public class CountDownLatch { + /** + * Synchronization control For CountDownLatch. + * Uses AQS state to represent count. + */ + private static final class Sync extends AbstractQueuedSynchronizer { + private static final long serialVersionUID = 4982264981922014374L; + + Sync(int count) { + setState(count); + } + + int getCount() { + return getState(); + } + + protected int tryAcquireShared(int acquires) { + return (getState() == 0) ? 1 : -1; + } + + protected boolean tryReleaseShared(int releases) { + // Decrement count; signal when transition to zero + for (;;) { + int c = getState(); + if (c == 0) + return false; + int nextc = c-1; + if (compareAndSetState(c, nextc)) + return nextc == 0; + } + } + } + + private final Sync sync; + + /** + * Constructs a {@code CountDownLatch} initialized with the given count. + * + * @param count the number of times {@link #countDown} must be invoked + * before threads can pass through {@link #await} + * @throws IllegalArgumentException if {@code count} is negative + */ + public CountDownLatch(int count) { + if (count < 0) throw new IllegalArgumentException("count < 0"); + this.sync = new Sync(count); + } + + /** + * Causes the current thread to wait until the latch has counted down to + * zero, unless the thread is {@linkplain Thread#interrupt interrupted}. + * + *

If the current count is zero then this method returns immediately. + * + *

If the current count is greater than zero then the current + * thread becomes disabled for thread scheduling purposes and lies + * dormant until one of two things happen: + *

    + *
  • The count reaches zero due to invocations of the + * {@link #countDown} method; or + *
  • Some other thread {@linkplain Thread#interrupt interrupts} + * the current thread. + *
+ * + *

If the current thread: + *

    + *
  • has its interrupted status set on entry to this method; or + *
  • is {@linkplain Thread#interrupt interrupted} while waiting, + *
+ * then {@link InterruptedException} is thrown and the current thread's + * interrupted status is cleared. + * + * @throws InterruptedException if the current thread is interrupted + * while waiting + */ + public void await() throws InterruptedException { + sync.acquireSharedInterruptibly(1); + } + + /** + * Causes the current thread to wait until the latch has counted down to + * zero, unless the thread is {@linkplain Thread#interrupt interrupted}, + * or the specified waiting time elapses. + * + *

If the current count is zero then this method returns immediately + * with the value {@code true}. + * + *

If the current count is greater than zero then the current + * thread becomes disabled for thread scheduling purposes and lies + * dormant until one of three things happen: + *

    + *
  • The count reaches zero due to invocations of the + * {@link #countDown} method; or + *
  • Some other thread {@linkplain Thread#interrupt interrupts} + * the current thread; or + *
  • The specified waiting time elapses. + *
+ * + *

If the count reaches zero then the method returns with the + * value {@code true}. + * + *

If the current thread: + *

    + *
  • has its interrupted status set on entry to this method; or + *
  • is {@linkplain Thread#interrupt interrupted} while waiting, + *
+ * then {@link InterruptedException} is thrown and the current thread's + * interrupted status is cleared. + * + *

If the specified waiting time elapses then the value {@code false} + * is returned. If the time is less than or equal to zero, the method + * will not wait at all. + * + * @param timeout the maximum time to wait + * @param unit the time unit of the {@code timeout} argument + * @return {@code true} if the count reached zero and {@code false} + * if the waiting time elapsed before the count reached zero + * @throws InterruptedException if the current thread is interrupted + * while waiting + */ + public boolean await(long timeout, TimeUnit unit) + throws InterruptedException { + return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout)); + } + + /** + * Decrements the count of the latch, releasing all waiting threads if + * the count reaches zero. + * + *

If the current count is greater than zero then it is decremented. + * If the new count is zero then all waiting threads are re-enabled for + * thread scheduling purposes. + * + *

If the current count equals zero then nothing happens. + */ + public void countDown() { + sync.releaseShared(1); + } + + /** + * Returns the current count. + * + *

This method is typically used for debugging and testing purposes. + * + * @return the current count + */ + public long getCount() { + return sync.getCount(); + } + + /** + * Returns a string identifying this latch, as well as its state. + * The state, in brackets, includes the String {@code "Count ="} + * followed by the current count. + * + * @return a string identifying this latch, as well as its state + */ + public String toString() { + return super.toString() + "[Count = " + sync.getCount() + "]"; + } +} diff -r e1953d8b8338 -r c8af252ea9eb rt/emul/compact/src/main/java/java/util/concurrent/CyclicBarrier.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/CyclicBarrier.java Sat Mar 19 10:48:29 2016 +0100 @@ -0,0 +1,483 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +package java.util.concurrent; +import java.util.concurrent.locks.*; + +/** + * A synchronization aid that allows a set of threads to all wait for + * each other to reach a common barrier point. CyclicBarriers are + * useful in programs involving a fixed sized party of threads that + * must occasionally wait for each other. The barrier is called + * cyclic because it can be re-used after the waiting threads + * are released. + * + *

A CyclicBarrier supports an optional {@link Runnable} command + * that is run once per barrier point, after the last thread in the party + * arrives, but before any threads are released. + * This barrier action is useful + * for updating shared-state before any of the parties continue. + * + *

Sample usage: Here is an example of + * using a barrier in a parallel decomposition design: + *

+ * class Solver {
+ *   final int N;
+ *   final float[][] data;
+ *   final CyclicBarrier barrier;
+ *
+ *   class Worker implements Runnable {
+ *     int myRow;
+ *     Worker(int row) { myRow = row; }
+ *     public void run() {
+ *       while (!done()) {
+ *         processRow(myRow);
+ *
+ *         try {
+ *           barrier.await();
+ *         } catch (InterruptedException ex) {
+ *           return;
+ *         } catch (BrokenBarrierException ex) {
+ *           return;
+ *         }
+ *       }
+ *     }
+ *   }
+ *
+ *   public Solver(float[][] matrix) {
+ *     data = matrix;
+ *     N = matrix.length;
+ *     barrier = new CyclicBarrier(N,
+ *                                 new Runnable() {
+ *                                   public void run() {
+ *                                     mergeRows(...);
+ *                                   }
+ *                                 });
+ *     for (int i = 0; i < N; ++i)
+ *       new Thread(new Worker(i)).start();
+ *
+ *     waitUntilDone();
+ *   }
+ * }
+ * 
+ * Here, each worker thread processes a row of the matrix then waits at the + * barrier until all rows have been processed. When all rows are processed + * the supplied {@link Runnable} barrier action is executed and merges the + * rows. If the merger + * determines that a solution has been found then done() will return + * true and each worker will terminate. + * + *

If the barrier action does not rely on the parties being suspended when + * it is executed, then any of the threads in the party could execute that + * action when it is released. To facilitate this, each invocation of + * {@link #await} returns the arrival index of that thread at the barrier. + * You can then choose which thread should execute the barrier action, for + * example: + *

  if (barrier.await() == 0) {
+ *     // log the completion of this iteration
+ *   }
+ * + *

The CyclicBarrier uses an all-or-none breakage model + * for failed synchronization attempts: If a thread leaves a barrier + * point prematurely because of interruption, failure, or timeout, all + * other threads waiting at that barrier point will also leave + * abnormally via {@link BrokenBarrierException} (or + * {@link InterruptedException} if they too were interrupted at about + * the same time). + * + *

Memory consistency effects: Actions in a thread prior to calling + * {@code await()} + * happen-before + * actions that are part of the barrier action, which in turn + * happen-before actions following a successful return from the + * corresponding {@code await()} in other threads. + * + * @since 1.5 + * @see CountDownLatch + * + * @author Doug Lea + */ +public class CyclicBarrier { + /** + * Each use of the barrier is represented as a generation instance. + * The generation changes whenever the barrier is tripped, or + * is reset. There can be many generations associated with threads + * using the barrier - due to the non-deterministic way the lock + * may be allocated to waiting threads - but only one of these + * can be active at a time (the one to which count applies) + * and all the rest are either broken or tripped. + * There need not be an active generation if there has been a break + * but no subsequent reset. + */ + private static class Generation { + boolean broken = false; + } + + /** The lock for guarding barrier entry */ + private final ReentrantLock lock = new ReentrantLock(); + /** Condition to wait on until tripped */ + private final Condition trip = lock.newCondition(); + /** The number of parties */ + private final int parties; + /* The command to run when tripped */ + private final Runnable barrierCommand; + /** The current generation */ + private Generation generation = new Generation(); + + /** + * Number of parties still waiting. Counts down from parties to 0 + * on each generation. It is reset to parties on each new + * generation or when broken. + */ + private int count; + + /** + * Updates state on barrier trip and wakes up everyone. + * Called only while holding lock. + */ + private void nextGeneration() { + // signal completion of last generation + trip.signalAll(); + // set up next generation + count = parties; + generation = new Generation(); + } + + /** + * Sets current barrier generation as broken and wakes up everyone. + * Called only while holding lock. + */ + private void breakBarrier() { + generation.broken = true; + count = parties; + trip.signalAll(); + } + + /** + * Main barrier code, covering the various policies. + */ + private int dowait(boolean timed, long nanos) + throws InterruptedException, BrokenBarrierException, + TimeoutException { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + final Generation g = generation; + + if (g.broken) + throw new BrokenBarrierException(); + + if (Thread.interrupted()) { + breakBarrier(); + throw new InterruptedException(); + } + + int index = --count; + if (index == 0) { // tripped + boolean ranAction = false; + try { + final Runnable command = barrierCommand; + if (command != null) + command.run(); + ranAction = true; + nextGeneration(); + return 0; + } finally { + if (!ranAction) + breakBarrier(); + } + } + + // loop until tripped, broken, interrupted, or timed out + for (;;) { + try { + if (!timed) + trip.await(); + else if (nanos > 0L) + nanos = trip.awaitNanos(nanos); + } catch (InterruptedException ie) { + if (g == generation && ! g.broken) { + breakBarrier(); + throw ie; + } else { + // We're about to finish waiting even if we had not + // been interrupted, so this interrupt is deemed to + // "belong" to subsequent execution. + Thread.currentThread().interrupt(); + } + } + + if (g.broken) + throw new BrokenBarrierException(); + + if (g != generation) + return index; + + if (timed && nanos <= 0L) { + breakBarrier(); + throw new TimeoutException(); + } + } + } finally { + lock.unlock(); + } + } + + /** + * Creates a new CyclicBarrier that will trip when the + * given number of parties (threads) are waiting upon it, and which + * will execute the given barrier action when the barrier is tripped, + * performed by the last thread entering the barrier. + * + * @param parties the number of threads that must invoke {@link #await} + * before the barrier is tripped + * @param barrierAction the command to execute when the barrier is + * tripped, or {@code null} if there is no action + * @throws IllegalArgumentException if {@code parties} is less than 1 + */ + public CyclicBarrier(int parties, Runnable barrierAction) { + if (parties <= 0) throw new IllegalArgumentException(); + this.parties = parties; + this.count = parties; + this.barrierCommand = barrierAction; + } + + /** + * Creates a new CyclicBarrier that will trip when the + * given number of parties (threads) are waiting upon it, and + * does not perform a predefined action when the barrier is tripped. + * + * @param parties the number of threads that must invoke {@link #await} + * before the barrier is tripped + * @throws IllegalArgumentException if {@code parties} is less than 1 + */ + public CyclicBarrier(int parties) { + this(parties, null); + } + + /** + * Returns the number of parties required to trip this barrier. + * + * @return the number of parties required to trip this barrier + */ + public int getParties() { + return parties; + } + + /** + * Waits until all {@linkplain #getParties parties} have invoked + * await on this barrier. + * + *

If the current thread is not the last to arrive then it is + * disabled for thread scheduling purposes and lies dormant until + * one of the following things happens: + *

    + *
  • The last thread arrives; or + *
  • Some other thread {@linkplain Thread#interrupt interrupts} + * the current thread; or + *
  • Some other thread {@linkplain Thread#interrupt interrupts} + * one of the other waiting threads; or + *
  • Some other thread times out while waiting for barrier; or + *
  • Some other thread invokes {@link #reset} on this barrier. + *
+ * + *

If the current thread: + *

    + *
  • has its interrupted status set on entry to this method; or + *
  • is {@linkplain Thread#interrupt interrupted} while waiting + *
+ * then {@link InterruptedException} is thrown and the current thread's + * interrupted status is cleared. + * + *

If the barrier is {@link #reset} while any thread is waiting, + * or if the barrier {@linkplain #isBroken is broken} when + * await is invoked, or while any thread is waiting, then + * {@link BrokenBarrierException} is thrown. + * + *

If any thread is {@linkplain Thread#interrupt interrupted} while waiting, + * then all other waiting threads will throw + * {@link BrokenBarrierException} and the barrier is placed in the broken + * state. + * + *

If the current thread is the last thread to arrive, and a + * non-null barrier action was supplied in the constructor, then the + * current thread runs the action before allowing the other threads to + * continue. + * If an exception occurs during the barrier action then that exception + * will be propagated in the current thread and the barrier is placed in + * the broken state. + * + * @return the arrival index of the current thread, where index + * {@link #getParties()} - 1 indicates the first + * to arrive and zero indicates the last to arrive + * @throws InterruptedException if the current thread was interrupted + * while waiting + * @throws BrokenBarrierException if another thread was + * interrupted or timed out while the current thread was + * waiting, or the barrier was reset, or the barrier was + * broken when {@code await} was called, or the barrier + * action (if present) failed due an exception. + */ + public int await() throws InterruptedException, BrokenBarrierException { + try { + return dowait(false, 0L); + } catch (TimeoutException toe) { + throw new Error(toe); // cannot happen; + } + } + + /** + * Waits until all {@linkplain #getParties parties} have invoked + * await on this barrier, or the specified waiting time elapses. + * + *

If the current thread is not the last to arrive then it is + * disabled for thread scheduling purposes and lies dormant until + * one of the following things happens: + *

    + *
  • The last thread arrives; or + *
  • The specified timeout elapses; or + *
  • Some other thread {@linkplain Thread#interrupt interrupts} + * the current thread; or + *
  • Some other thread {@linkplain Thread#interrupt interrupts} + * one of the other waiting threads; or + *
  • Some other thread times out while waiting for barrier; or + *
  • Some other thread invokes {@link #reset} on this barrier. + *
+ * + *

If the current thread: + *

    + *
  • has its interrupted status set on entry to this method; or + *
  • is {@linkplain Thread#interrupt interrupted} while waiting + *
+ * then {@link InterruptedException} is thrown and the current thread's + * interrupted status is cleared. + * + *

If the specified waiting time elapses then {@link TimeoutException} + * is thrown. If the time is less than or equal to zero, the + * method will not wait at all. + * + *

If the barrier is {@link #reset} while any thread is waiting, + * or if the barrier {@linkplain #isBroken is broken} when + * await is invoked, or while any thread is waiting, then + * {@link BrokenBarrierException} is thrown. + * + *

If any thread is {@linkplain Thread#interrupt interrupted} while + * waiting, then all other waiting threads will throw {@link + * BrokenBarrierException} and the barrier is placed in the broken + * state. + * + *

If the current thread is the last thread to arrive, and a + * non-null barrier action was supplied in the constructor, then the + * current thread runs the action before allowing the other threads to + * continue. + * If an exception occurs during the barrier action then that exception + * will be propagated in the current thread and the barrier is placed in + * the broken state. + * + * @param timeout the time to wait for the barrier + * @param unit the time unit of the timeout parameter + * @return the arrival index of the current thread, where index + * {@link #getParties()} - 1 indicates the first + * to arrive and zero indicates the last to arrive + * @throws InterruptedException if the current thread was interrupted + * while waiting + * @throws TimeoutException if the specified timeout elapses + * @throws BrokenBarrierException if another thread was + * interrupted or timed out while the current thread was + * waiting, or the barrier was reset, or the barrier was broken + * when {@code await} was called, or the barrier action (if + * present) failed due an exception + */ + public int await(long timeout, TimeUnit unit) + throws InterruptedException, + BrokenBarrierException, + TimeoutException { + return dowait(true, unit.toNanos(timeout)); + } + + /** + * Queries if this barrier is in a broken state. + * + * @return {@code true} if one or more parties broke out of this + * barrier due to interruption or timeout since + * construction or the last reset, or a barrier action + * failed due to an exception; {@code false} otherwise. + */ + public boolean isBroken() { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + return generation.broken; + } finally { + lock.unlock(); + } + } + + /** + * Resets the barrier to its initial state. If any parties are + * currently waiting at the barrier, they will return with a + * {@link BrokenBarrierException}. Note that resets after + * a breakage has occurred for other reasons can be complicated to + * carry out; threads need to re-synchronize in some other way, + * and choose one to perform the reset. It may be preferable to + * instead create a new barrier for subsequent use. + */ + public void reset() { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + breakBarrier(); // break the current generation + nextGeneration(); // start a new generation + } finally { + lock.unlock(); + } + } + + /** + * Returns the number of parties currently waiting at the barrier. + * This method is primarily useful for debugging and assertions. + * + * @return the number of parties currently blocked in {@link #await} + */ + public int getNumberWaiting() { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + return parties - count; + } finally { + lock.unlock(); + } + } +} diff -r e1953d8b8338 -r c8af252ea9eb rt/emul/compact/src/main/java/java/util/concurrent/DelayQueue.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/DelayQueue.java Sat Mar 19 10:48:29 2016 +0100 @@ -0,0 +1,546 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + + +package java.util.concurrent; +import java.util.concurrent.locks.*; +import java.util.*; + +/** + * An unbounded {@linkplain BlockingQueue blocking queue} of + * Delayed elements, in which an element can only be taken + * when its delay has expired. The head of the queue is that + * Delayed element whose delay expired furthest in the + * past. If no delay has expired there is no head and poll + * will return null. Expiration occurs when an element's + * getDelay(TimeUnit.NANOSECONDS) method returns a value less + * than or equal to zero. Even though unexpired elements cannot be + * removed using take or poll, they are otherwise + * treated as normal elements. For example, the size method + * returns the count of both expired and unexpired elements. + * This queue does not permit null elements. + * + *

This class and its iterator implement all of the + * optional methods of the {@link Collection} and {@link + * Iterator} interfaces. + * + *

This class is a member of the + * + * Java Collections Framework. + * + * @since 1.5 + * @author Doug Lea + * @param the type of elements held in this collection + */ + +public class DelayQueue extends AbstractQueue + implements BlockingQueue { + + private transient final ReentrantLock lock = new ReentrantLock(); + private final PriorityQueue q = new PriorityQueue(); + + /** + * Thread designated to wait for the element at the head of + * the queue. This variant of the Leader-Follower pattern + * (http://www.cs.wustl.edu/~schmidt/POSA/POSA2/) serves to + * minimize unnecessary timed waiting. When a thread becomes + * the leader, it waits only for the next delay to elapse, but + * other threads await indefinitely. The leader thread must + * signal some other thread before returning from take() or + * poll(...), unless some other thread becomes leader in the + * interim. Whenever the head of the queue is replaced with + * an element with an earlier expiration time, the leader + * field is invalidated by being reset to null, and some + * waiting thread, but not necessarily the current leader, is + * signalled. So waiting threads must be prepared to acquire + * and lose leadership while waiting. + */ + private Thread leader = null; + + /** + * Condition signalled when a newer element becomes available + * at the head of the queue or a new thread may need to + * become leader. + */ + private final Condition available = lock.newCondition(); + + /** + * Creates a new DelayQueue that is initially empty. + */ + public DelayQueue() {} + + /** + * Creates a DelayQueue initially containing the elements of the + * given collection of {@link Delayed} instances. + * + * @param c the collection of elements to initially contain + * @throws NullPointerException if the specified collection or any + * of its elements are null + */ + public DelayQueue(Collection c) { + this.addAll(c); + } + + /** + * Inserts the specified element into this delay queue. + * + * @param e the element to add + * @return true (as specified by {@link Collection#add}) + * @throws NullPointerException if the specified element is null + */ + public boolean add(E e) { + return offer(e); + } + + /** + * Inserts the specified element into this delay queue. + * + * @param e the element to add + * @return true + * @throws NullPointerException if the specified element is null + */ + public boolean offer(E e) { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + q.offer(e); + if (q.peek() == e) { + leader = null; + available.signal(); + } + return true; + } finally { + lock.unlock(); + } + } + + /** + * Inserts the specified element into this delay queue. As the queue is + * unbounded this method will never block. + * + * @param e the element to add + * @throws NullPointerException {@inheritDoc} + */ + public void put(E e) { + offer(e); + } + + /** + * Inserts the specified element into this delay queue. As the queue is + * unbounded this method will never block. + * + * @param e the element to add + * @param timeout This parameter is ignored as the method never blocks + * @param unit This parameter is ignored as the method never blocks + * @return true + * @throws NullPointerException {@inheritDoc} + */ + public boolean offer(E e, long timeout, TimeUnit unit) { + return offer(e); + } + + /** + * Retrieves and removes the head of this queue, or returns null + * if this queue has no elements with an expired delay. + * + * @return the head of this queue, or null if this + * queue has no elements with an expired delay + */ + public E poll() { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + E first = q.peek(); + if (first == null || first.getDelay(TimeUnit.NANOSECONDS) > 0) + return null; + else + return q.poll(); + } finally { + lock.unlock(); + } + } + + /** + * Retrieves and removes the head of this queue, waiting if necessary + * until an element with an expired delay is available on this queue. + * + * @return the head of this queue + * @throws InterruptedException {@inheritDoc} + */ + public E take() throws InterruptedException { + final ReentrantLock lock = this.lock; + lock.lockInterruptibly(); + try { + for (;;) { + E first = q.peek(); + if (first == null) + available.await(); + else { + long delay = first.getDelay(TimeUnit.NANOSECONDS); + if (delay <= 0) + return q.poll(); + else if (leader != null) + available.await(); + else { + Thread thisThread = Thread.currentThread(); + leader = thisThread; + try { + available.awaitNanos(delay); + } finally { + if (leader == thisThread) + leader = null; + } + } + } + } + } finally { + if (leader == null && q.peek() != null) + available.signal(); + lock.unlock(); + } + } + + /** + * Retrieves and removes the head of this queue, waiting if necessary + * until an element with an expired delay is available on this queue, + * or the specified wait time expires. + * + * @return the head of this queue, or null if the + * specified waiting time elapses before an element with + * an expired delay becomes available + * @throws InterruptedException {@inheritDoc} + */ + public E poll(long timeout, TimeUnit unit) throws InterruptedException { + long nanos = unit.toNanos(timeout); + final ReentrantLock lock = this.lock; + lock.lockInterruptibly(); + try { + for (;;) { + E first = q.peek(); + if (first == null) { + if (nanos <= 0) + return null; + else + nanos = available.awaitNanos(nanos); + } else { + long delay = first.getDelay(TimeUnit.NANOSECONDS); + if (delay <= 0) + return q.poll(); + if (nanos <= 0) + return null; + if (nanos < delay || leader != null) + nanos = available.awaitNanos(nanos); + else { + Thread thisThread = Thread.currentThread(); + leader = thisThread; + try { + long timeLeft = available.awaitNanos(delay); + nanos -= delay - timeLeft; + } finally { + if (leader == thisThread) + leader = null; + } + } + } + } + } finally { + if (leader == null && q.peek() != null) + available.signal(); + lock.unlock(); + } + } + + /** + * Retrieves, but does not remove, the head of this queue, or + * returns null if this queue is empty. Unlike + * poll, if no expired elements are available in the queue, + * this method returns the element that will expire next, + * if one exists. + * + * @return the head of this queue, or null if this + * queue is empty. + */ + public E peek() { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + return q.peek(); + } finally { + lock.unlock(); + } + } + + public int size() { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + return q.size(); + } finally { + lock.unlock(); + } + } + + /** + * @throws UnsupportedOperationException {@inheritDoc} + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + * @throws IllegalArgumentException {@inheritDoc} + */ + public int drainTo(Collection c) { + if (c == null) + throw new NullPointerException(); + if (c == this) + throw new IllegalArgumentException(); + final ReentrantLock lock = this.lock; + lock.lock(); + try { + int n = 0; + for (;;) { + E first = q.peek(); + if (first == null || first.getDelay(TimeUnit.NANOSECONDS) > 0) + break; + c.add(q.poll()); + ++n; + } + return n; + } finally { + lock.unlock(); + } + } + + /** + * @throws UnsupportedOperationException {@inheritDoc} + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + * @throws IllegalArgumentException {@inheritDoc} + */ + public int drainTo(Collection c, int maxElements) { + if (c == null) + throw new NullPointerException(); + if (c == this) + throw new IllegalArgumentException(); + if (maxElements <= 0) + return 0; + final ReentrantLock lock = this.lock; + lock.lock(); + try { + int n = 0; + while (n < maxElements) { + E first = q.peek(); + if (first == null || first.getDelay(TimeUnit.NANOSECONDS) > 0) + break; + c.add(q.poll()); + ++n; + } + return n; + } finally { + lock.unlock(); + } + } + + /** + * Atomically removes all of the elements from this delay queue. + * The queue will be empty after this call returns. + * Elements with an unexpired delay are not waited for; they are + * simply discarded from the queue. + */ + public void clear() { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + q.clear(); + } finally { + lock.unlock(); + } + } + + /** + * Always returns Integer.MAX_VALUE because + * a DelayQueue is not capacity constrained. + * + * @return Integer.MAX_VALUE + */ + public int remainingCapacity() { + return Integer.MAX_VALUE; + } + + /** + * Returns an array containing all of the elements in this queue. + * The returned array elements are in no particular order. + * + *

The returned array will be "safe" in that no references to it are + * maintained by this queue. (In other words, this method must allocate + * a new array). The caller is thus free to modify the returned array. + * + *

This method acts as bridge between array-based and collection-based + * APIs. + * + * @return an array containing all of the elements in this queue + */ + public Object[] toArray() { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + return q.toArray(); + } finally { + lock.unlock(); + } + } + + /** + * Returns an array containing all of the elements in this queue; the + * runtime type of the returned array is that of the specified array. + * The returned array elements are in no particular order. + * If the queue fits in the specified array, it is returned therein. + * Otherwise, a new array is allocated with the runtime type of the + * specified array and the size of this queue. + * + *

If this queue fits in the specified array with room to spare + * (i.e., the array has more elements than this queue), the element in + * the array immediately following the end of the queue is set to + * null. + * + *

Like the {@link #toArray()} method, this method acts as bridge between + * array-based and collection-based APIs. Further, this method allows + * precise control over the runtime type of the output array, and may, + * under certain circumstances, be used to save allocation costs. + * + *

The following code can be used to dump a delay queue into a newly + * allocated array of Delayed: + * + *

+     *     Delayed[] a = q.toArray(new Delayed[0]);
+ * + * Note that toArray(new Object[0]) is identical in function to + * toArray(). + * + * @param a the array into which the elements of the queue are to + * be stored, if it is big enough; otherwise, a new array of the + * same runtime type is allocated for this purpose + * @return an array containing all of the elements in this queue + * @throws ArrayStoreException if the runtime type of the specified array + * is not a supertype of the runtime type of every element in + * this queue + * @throws NullPointerException if the specified array is null + */ + public T[] toArray(T[] a) { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + return q.toArray(a); + } finally { + lock.unlock(); + } + } + + /** + * Removes a single instance of the specified element from this + * queue, if it is present, whether or not it has expired. + */ + public boolean remove(Object o) { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + return q.remove(o); + } finally { + lock.unlock(); + } + } + + /** + * Returns an iterator over all the elements (both expired and + * unexpired) in this queue. The iterator does not return the + * elements in any particular order. + * + *

The returned iterator is a "weakly consistent" iterator that + * will never throw {@link java.util.ConcurrentModificationException + * ConcurrentModificationException}, and guarantees to traverse + * elements as they existed upon construction of the iterator, and + * may (but is not guaranteed to) reflect any modifications + * subsequent to construction. + * + * @return an iterator over the elements in this queue + */ + public Iterator iterator() { + return new Itr(toArray()); + } + + /** + * Snapshot iterator that works off copy of underlying q array. + */ + private class Itr implements Iterator { + final Object[] array; // Array of all elements + int cursor; // index of next element to return; + int lastRet; // index of last element, or -1 if no such + + Itr(Object[] array) { + lastRet = -1; + this.array = array; + } + + public boolean hasNext() { + return cursor < array.length; + } + + @SuppressWarnings("unchecked") + public E next() { + if (cursor >= array.length) + throw new NoSuchElementException(); + lastRet = cursor; + return (E)array[cursor++]; + } + + public void remove() { + if (lastRet < 0) + throw new IllegalStateException(); + Object x = array[lastRet]; + lastRet = -1; + // Traverse underlying queue to find == element, + // not just a .equals element. + lock.lock(); + try { + for (Iterator it = q.iterator(); it.hasNext(); ) { + if (it.next() == x) { + it.remove(); + return; + } + } + } finally { + lock.unlock(); + } + } + } + +} diff -r e1953d8b8338 -r c8af252ea9eb rt/emul/compact/src/main/java/java/util/concurrent/Delayed.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/Delayed.java Sat Mar 19 10:48:29 2016 +0100 @@ -0,0 +1,62 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +package java.util.concurrent; + +import java.util.*; + +/** + * A mix-in style interface for marking objects that should be + * acted upon after a given delay. + * + *

An implementation of this interface must define a + * compareTo method that provides an ordering consistent with + * its getDelay method. + * + * @since 1.5 + * @author Doug Lea + */ +public interface Delayed extends Comparable { + + /** + * Returns the remaining delay associated with this object, in the + * given time unit. + * + * @param unit the time unit + * @return the remaining delay; zero or negative values indicate + * that the delay has already elapsed + */ + long getDelay(TimeUnit unit); +} diff -r e1953d8b8338 -r c8af252ea9eb rt/emul/compact/src/main/java/java/util/concurrent/Exchanger.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/Exchanger.java Sat Mar 19 10:48:29 2016 +0100 @@ -0,0 +1,687 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea, Bill Scherer, and Michael Scott with + * assistance from members of JCP JSR-166 Expert Group and released to + * the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +package java.util.concurrent; +import java.util.concurrent.atomic.*; +import java.util.concurrent.locks.LockSupport; + +/** + * A synchronization point at which threads can pair and swap elements + * within pairs. Each thread presents some object on entry to the + * {@link #exchange exchange} method, matches with a partner thread, + * and receives its partner's object on return. An Exchanger may be + * viewed as a bidirectional form of a {@link SynchronousQueue}. + * Exchangers may be useful in applications such as genetic algorithms + * and pipeline designs. + * + *

Sample Usage: + * Here are the highlights of a class that uses an {@code Exchanger} + * to swap buffers between threads so that the thread filling the + * buffer gets a freshly emptied one when it needs it, handing off the + * filled one to the thread emptying the buffer. + *

{@code
+ * class FillAndEmpty {
+ *   Exchanger exchanger = new Exchanger();
+ *   DataBuffer initialEmptyBuffer = ... a made-up type
+ *   DataBuffer initialFullBuffer = ...
+ *
+ *   class FillingLoop implements Runnable {
+ *     public void run() {
+ *       DataBuffer currentBuffer = initialEmptyBuffer;
+ *       try {
+ *         while (currentBuffer != null) {
+ *           addToBuffer(currentBuffer);
+ *           if (currentBuffer.isFull())
+ *             currentBuffer = exchanger.exchange(currentBuffer);
+ *         }
+ *       } catch (InterruptedException ex) { ... handle ... }
+ *     }
+ *   }
+ *
+ *   class EmptyingLoop implements Runnable {
+ *     public void run() {
+ *       DataBuffer currentBuffer = initialFullBuffer;
+ *       try {
+ *         while (currentBuffer != null) {
+ *           takeFromBuffer(currentBuffer);
+ *           if (currentBuffer.isEmpty())
+ *             currentBuffer = exchanger.exchange(currentBuffer);
+ *         }
+ *       } catch (InterruptedException ex) { ... handle ...}
+ *     }
+ *   }
+ *
+ *   void start() {
+ *     new Thread(new FillingLoop()).start();
+ *     new Thread(new EmptyingLoop()).start();
+ *   }
+ * }
+ * }
+ * + *

Memory consistency effects: For each pair of threads that + * successfully exchange objects via an {@code Exchanger}, actions + * prior to the {@code exchange()} in each thread + * happen-before + * those subsequent to a return from the corresponding {@code exchange()} + * in the other thread. + * + * @since 1.5 + * @author Doug Lea and Bill Scherer and Michael Scott + * @param The type of objects that may be exchanged + */ +public class Exchanger { + /* + * Algorithm Description: + * + * The basic idea is to maintain a "slot", which is a reference to + * a Node containing both an Item to offer and a "hole" waiting to + * get filled in. If an incoming "occupying" thread sees that the + * slot is null, it CAS'es (compareAndSets) a Node there and waits + * for another to invoke exchange. That second "fulfilling" thread + * sees that the slot is non-null, and so CASes it back to null, + * also exchanging items by CASing the hole, plus waking up the + * occupying thread if it is blocked. In each case CAS'es may + * fail because a slot at first appears non-null but is null upon + * CAS, or vice-versa. So threads may need to retry these + * actions. + * + * This simple approach works great when there are only a few + * threads using an Exchanger, but performance rapidly + * deteriorates due to CAS contention on the single slot when + * there are lots of threads using an exchanger. So instead we use + * an "arena"; basically a kind of hash table with a dynamically + * varying number of slots, any one of which can be used by + * threads performing an exchange. Incoming threads pick slots + * based on a hash of their Thread ids. If an incoming thread + * fails to CAS in its chosen slot, it picks an alternative slot + * instead. And similarly from there. If a thread successfully + * CASes into a slot but no other thread arrives, it tries + * another, heading toward the zero slot, which always exists even + * if the table shrinks. The particular mechanics controlling this + * are as follows: + * + * Waiting: Slot zero is special in that it is the only slot that + * exists when there is no contention. A thread occupying slot + * zero will block if no thread fulfills it after a short spin. + * In other cases, occupying threads eventually give up and try + * another slot. Waiting threads spin for a while (a period that + * should be a little less than a typical context-switch time) + * before either blocking (if slot zero) or giving up (if other + * slots) and restarting. There is no reason for threads to block + * unless there are unlikely to be any other threads present. + * Occupants are mainly avoiding memory contention so sit there + * quietly polling for a shorter period than it would take to + * block and then unblock them. Non-slot-zero waits that elapse + * because of lack of other threads waste around one extra + * context-switch time per try, which is still on average much + * faster than alternative approaches. + * + * Sizing: Usually, using only a few slots suffices to reduce + * contention. Especially with small numbers of threads, using + * too many slots can lead to just as poor performance as using + * too few of them, and there's not much room for error. The + * variable "max" maintains the number of slots actually in + * use. It is increased when a thread sees too many CAS + * failures. (This is analogous to resizing a regular hash table + * based on a target load factor, except here, growth steps are + * just one-by-one rather than proportional.) Growth requires + * contention failures in each of three tried slots. Requiring + * multiple failures for expansion copes with the fact that some + * failed CASes are not due to contention but instead to simple + * races between two threads or thread pre-emptions occurring + * between reading and CASing. Also, very transient peak + * contention can be much higher than the average sustainable + * levels. An attempt to decrease the max limit is usually made + * when a non-slot-zero wait elapses without being fulfilled. + * Threads experiencing elapsed waits move closer to zero, so + * eventually find existing (or future) threads even if the table + * has been shrunk due to inactivity. The chosen mechanics and + * thresholds for growing and shrinking are intrinsically + * entangled with indexing and hashing inside the exchange code, + * and can't be nicely abstracted out. + * + * Hashing: Each thread picks its initial slot to use in accord + * with a simple hashcode. The sequence is the same on each + * encounter by any given thread, but effectively random across + * threads. Using arenas encounters the classic cost vs quality + * tradeoffs of all hash tables. Here, we use a one-step FNV-1a + * hash code based on the current thread's Thread.getId(), along + * with a cheap approximation to a mod operation to select an + * index. The downside of optimizing index selection in this way + * is that the code is hardwired to use a maximum table size of + * 32. But this value more than suffices for known platforms and + * applications. + * + * Probing: On sensed contention of a selected slot, we probe + * sequentially through the table, analogously to linear probing + * after collision in a hash table. (We move circularly, in + * reverse order, to mesh best with table growth and shrinkage + * rules.) Except that to minimize the effects of false-alarms + * and cache thrashing, we try the first selected slot twice + * before moving. + * + * Padding: Even with contention management, slots are heavily + * contended, so use cache-padding to avoid poor memory + * performance. Because of this, slots are lazily constructed + * only when used, to avoid wasting this space unnecessarily. + * While isolation of locations is not much of an issue at first + * in an application, as time goes on and garbage-collectors + * perform compaction, slots are very likely to be moved adjacent + * to each other, which can cause much thrashing of cache lines on + * MPs unless padding is employed. + * + * This is an improvement of the algorithm described in the paper + * "A Scalable Elimination-based Exchange Channel" by William + * Scherer, Doug Lea, and Michael Scott in Proceedings of SCOOL05 + * workshop. Available at: http://hdl.handle.net/1802/2104 + */ + + /** The number of CPUs, for sizing and spin control */ + private static final int NCPU = Runtime.getRuntime().availableProcessors(); + + /** + * The capacity of the arena. Set to a value that provides more + * than enough space to handle contention. On small machines + * most slots won't be used, but it is still not wasted because + * the extra space provides some machine-level address padding + * to minimize interference with heavily CAS'ed Slot locations. + * And on very large machines, performance eventually becomes + * bounded by memory bandwidth, not numbers of threads/CPUs. + * This constant cannot be changed without also modifying + * indexing and hashing algorithms. + */ + private static final int CAPACITY = 32; + + /** + * The value of "max" that will hold all threads without + * contention. When this value is less than CAPACITY, some + * otherwise wasted expansion can be avoided. + */ + private static final int FULL = + Math.max(0, Math.min(CAPACITY, NCPU / 2) - 1); + + /** + * The number of times to spin (doing nothing except polling a + * memory location) before blocking or giving up while waiting to + * be fulfilled. Should be zero on uniprocessors. On + * multiprocessors, this value should be large enough so that two + * threads exchanging items as fast as possible block only when + * one of them is stalled (due to GC or preemption), but not much + * longer, to avoid wasting CPU resources. Seen differently, this + * value is a little over half the number of cycles of an average + * context switch time on most systems. The value here is + * approximately the average of those across a range of tested + * systems. + */ + private static final int SPINS = (NCPU == 1) ? 0 : 2000; + + /** + * The number of times to spin before blocking in timed waits. + * Timed waits spin more slowly because checking the time takes + * time. The best value relies mainly on the relative rate of + * System.nanoTime vs memory accesses. The value is empirically + * derived to work well across a variety of systems. + */ + private static final int TIMED_SPINS = SPINS / 20; + + /** + * Sentinel item representing cancellation of a wait due to + * interruption, timeout, or elapsed spin-waits. This value is + * placed in holes on cancellation, and used as a return value + * from waiting methods to indicate failure to set or get hole. + */ + private static final Object CANCEL = new Object(); + + /** + * Value representing null arguments/returns from public + * methods. This disambiguates from internal requirement that + * holes start out as null to mean they are not yet set. + */ + private static final Object NULL_ITEM = new Object(); + + /** + * Nodes hold partially exchanged data. This class + * opportunistically subclasses AtomicReference to represent the + * hole. So get() returns hole, and compareAndSet CAS'es value + * into hole. This class cannot be parameterized as "V" because + * of the use of non-V CANCEL sentinels. + */ + private static final class Node extends AtomicReference { + /** The element offered by the Thread creating this node. */ + public final Object item; + + /** The Thread waiting to be signalled; null until waiting. */ + public volatile Thread waiter; + + /** + * Creates node with given item and empty hole. + * @param item the item + */ + public Node(Object item) { + this.item = item; + } + } + + /** + * A Slot is an AtomicReference with heuristic padding to lessen + * cache effects of this heavily CAS'ed location. While the + * padding adds noticeable space, all slots are created only on + * demand, and there will be more than one of them only when it + * would improve throughput more than enough to outweigh using + * extra space. + */ + private static final class Slot extends AtomicReference { + // Improve likelihood of isolation on <= 64 byte cache lines + long q0, q1, q2, q3, q4, q5, q6, q7, q8, q9, qa, qb, qc, qd, qe; + } + + /** + * Slot array. Elements are lazily initialized when needed. + * Declared volatile to enable double-checked lazy construction. + */ + private volatile Slot[] arena = new Slot[CAPACITY]; + + /** + * The maximum slot index being used. The value sometimes + * increases when a thread experiences too many CAS contentions, + * and sometimes decreases when a spin-wait elapses. Changes + * are performed only via compareAndSet, to avoid stale values + * when a thread happens to stall right before setting. + */ + private final AtomicInteger max = new AtomicInteger(); + + /** + * Main exchange function, handling the different policy variants. + * Uses Object, not "V" as argument and return value to simplify + * handling of sentinel values. Callers from public methods decode + * and cast accordingly. + * + * @param item the (non-null) item to exchange + * @param timed true if the wait is timed + * @param nanos if timed, the maximum wait time + * @return the other thread's item, or CANCEL if interrupted or timed out + */ + private Object doExchange(Object item, boolean timed, long nanos) { + Node me = new Node(item); // Create in case occupying + int index = hashIndex(); // Index of current slot + int fails = 0; // Number of CAS failures + + for (;;) { + Object y; // Contents of current slot + Slot slot = arena[index]; + if (slot == null) // Lazily initialize slots + createSlot(index); // Continue loop to reread + else if ((y = slot.get()) != null && // Try to fulfill + slot.compareAndSet(y, null)) { + Node you = (Node)y; // Transfer item + if (you.compareAndSet(null, item)) { + LockSupport.unpark(you.waiter); + return you.item; + } // Else cancelled; continue + } + else if (y == null && // Try to occupy + slot.compareAndSet(null, me)) { + if (index == 0) // Blocking wait for slot 0 + return timed ? + awaitNanos(me, slot, nanos) : + await(me, slot); + Object v = spinWait(me, slot); // Spin wait for non-0 + if (v != CANCEL) + return v; + me = new Node(item); // Throw away cancelled node + int m = max.get(); + if (m > (index >>>= 1)) // Decrease index + max.compareAndSet(m, m - 1); // Maybe shrink table + } + else if (++fails > 1) { // Allow 2 fails on 1st slot + int m = max.get(); + if (fails > 3 && m < FULL && max.compareAndSet(m, m + 1)) + index = m + 1; // Grow on 3rd failed slot + else if (--index < 0) + index = m; // Circularly traverse + } + } + } + + /** + * Returns a hash index for the current thread. Uses a one-step + * FNV-1a hash code (http://www.isthe.com/chongo/tech/comp/fnv/) + * based on the current thread's Thread.getId(). These hash codes + * have more uniform distribution properties with respect to small + * moduli (here 1-31) than do other simple hashing functions. + * + *

To return an index between 0 and max, we use a cheap + * approximation to a mod operation, that also corrects for bias + * due to non-power-of-2 remaindering (see {@link + * java.util.Random#nextInt}). Bits of the hashcode are masked + * with "nbits", the ceiling power of two of table size (looked up + * in a table packed into three ints). If too large, this is + * retried after rotating the hash by nbits bits, while forcing new + * top bit to 0, which guarantees eventual termination (although + * with a non-random-bias). This requires an average of less than + * 2 tries for all table sizes, and has a maximum 2% difference + * from perfectly uniform slot probabilities when applied to all + * possible hash codes for sizes less than 32. + * + * @return a per-thread-random index, 0 <= index < max + */ + private final int hashIndex() { + long id = Thread.currentThread().getId(); + int hash = (((int)(id ^ (id >>> 32))) ^ 0x811c9dc5) * 0x01000193; + + int m = max.get(); + int nbits = (((0xfffffc00 >> m) & 4) | // Compute ceil(log2(m+1)) + ((0x000001f8 >>> m) & 2) | // The constants hold + ((0xffff00f2 >>> m) & 1)); // a lookup table + int index; + while ((index = hash & ((1 << nbits) - 1)) > m) // May retry on + hash = (hash >>> nbits) | (hash << (33 - nbits)); // non-power-2 m + return index; + } + + /** + * Creates a new slot at given index. Called only when the slot + * appears to be null. Relies on double-check using builtin + * locks, since they rarely contend. This in turn relies on the + * arena array being declared volatile. + * + * @param index the index to add slot at + */ + private void createSlot(int index) { + // Create slot outside of lock to narrow sync region + Slot newSlot = new Slot(); + Slot[] a = arena; + synchronized (a) { + if (a[index] == null) + a[index] = newSlot; + } + } + + /** + * Tries to cancel a wait for the given node waiting in the given + * slot, if so, helping clear the node from its slot to avoid + * garbage retention. + * + * @param node the waiting node + * @param the slot it is waiting in + * @return true if successfully cancelled + */ + private static boolean tryCancel(Node node, Slot slot) { + if (!node.compareAndSet(null, CANCEL)) + return false; + if (slot.get() == node) // pre-check to minimize contention + slot.compareAndSet(node, null); + return true; + } + + // Three forms of waiting. Each just different enough not to merge + // code with others. + + /** + * Spin-waits for hole for a non-0 slot. Fails if spin elapses + * before hole filled. Does not check interrupt, relying on check + * in public exchange method to abort if interrupted on entry. + * + * @param node the waiting node + * @return on success, the hole; on failure, CANCEL + */ + private static Object spinWait(Node node, Slot slot) { + int spins = SPINS; + for (;;) { + Object v = node.get(); + if (v != null) + return v; + else if (spins > 0) + --spins; + else + tryCancel(node, slot); + } + } + + /** + * Waits for (by spinning and/or blocking) and gets the hole + * filled in by another thread. Fails if interrupted before + * hole filled. + * + * When a node/thread is about to block, it sets its waiter field + * and then rechecks state at least one more time before actually + * parking, thus covering race vs fulfiller noticing that waiter + * is non-null so should be woken. + * + * Thread interruption status is checked only surrounding calls to + * park. The caller is assumed to have checked interrupt status + * on entry. + * + * @param node the waiting node + * @return on success, the hole; on failure, CANCEL + */ + private static Object await(Node node, Slot slot) { + Thread w = Thread.currentThread(); + int spins = SPINS; + for (;;) { + Object v = node.get(); + if (v != null) + return v; + else if (spins > 0) // Spin-wait phase + --spins; + else if (node.waiter == null) // Set up to block next + node.waiter = w; + else if (w.isInterrupted()) // Abort on interrupt + tryCancel(node, slot); + else // Block + LockSupport.park(node); + } + } + + /** + * Waits for (at index 0) and gets the hole filled in by another + * thread. Fails if timed out or interrupted before hole filled. + * Same basic logic as untimed version, but a bit messier. + * + * @param node the waiting node + * @param nanos the wait time + * @return on success, the hole; on failure, CANCEL + */ + private Object awaitNanos(Node node, Slot slot, long nanos) { + int spins = TIMED_SPINS; + long lastTime = 0; + Thread w = null; + for (;;) { + Object v = node.get(); + if (v != null) + return v; + long now = System.nanoTime(); + if (w == null) + w = Thread.currentThread(); + else + nanos -= now - lastTime; + lastTime = now; + if (nanos > 0) { + if (spins > 0) + --spins; + else if (node.waiter == null) + node.waiter = w; + else if (w.isInterrupted()) + tryCancel(node, slot); + else + LockSupport.parkNanos(node, nanos); + } + else if (tryCancel(node, slot) && !w.isInterrupted()) + return scanOnTimeout(node); + } + } + + /** + * Sweeps through arena checking for any waiting threads. Called + * only upon return from timeout while waiting in slot 0. When a + * thread gives up on a timed wait, it is possible that a + * previously-entered thread is still waiting in some other + * slot. So we scan to check for any. This is almost always + * overkill, but decreases the likelihood of timeouts when there + * are other threads present to far less than that in lock-based + * exchangers in which earlier-arriving threads may still be + * waiting on entry locks. + * + * @param node the waiting node + * @return another thread's item, or CANCEL + */ + private Object scanOnTimeout(Node node) { + Object y; + for (int j = arena.length - 1; j >= 0; --j) { + Slot slot = arena[j]; + if (slot != null) { + while ((y = slot.get()) != null) { + if (slot.compareAndSet(y, null)) { + Node you = (Node)y; + if (you.compareAndSet(null, node.item)) { + LockSupport.unpark(you.waiter); + return you.item; + } + } + } + } + } + return CANCEL; + } + + /** + * Creates a new Exchanger. + */ + public Exchanger() { + } + + /** + * Waits for another thread to arrive at this exchange point (unless + * the current thread is {@linkplain Thread#interrupt interrupted}), + * and then transfers the given object to it, receiving its object + * in return. + * + *

If another thread is already waiting at the exchange point then + * it is resumed for thread scheduling purposes and receives the object + * passed in by the current thread. The current thread returns immediately, + * receiving the object passed to the exchange by that other thread. + * + *

If no other thread is already waiting at the exchange then the + * current thread is disabled for thread scheduling purposes and lies + * dormant until one of two things happens: + *

    + *
  • Some other thread enters the exchange; or + *
  • Some other thread {@linkplain Thread#interrupt interrupts} + * the current thread. + *
+ *

If the current thread: + *

    + *
  • has its interrupted status set on entry to this method; or + *
  • is {@linkplain Thread#interrupt interrupted} while waiting + * for the exchange, + *
+ * then {@link InterruptedException} is thrown and the current thread's + * interrupted status is cleared. + * + * @param x the object to exchange + * @return the object provided by the other thread + * @throws InterruptedException if the current thread was + * interrupted while waiting + */ + public V exchange(V x) throws InterruptedException { + if (!Thread.interrupted()) { + Object v = doExchange((x == null) ? NULL_ITEM : x, false, 0); + if (v == NULL_ITEM) + return null; + if (v != CANCEL) + return (V)v; + Thread.interrupted(); // Clear interrupt status on IE throw + } + throw new InterruptedException(); + } + + /** + * Waits for another thread to arrive at this exchange point (unless + * the current thread is {@linkplain Thread#interrupt interrupted} or + * the specified waiting time elapses), and then transfers the given + * object to it, receiving its object in return. + * + *

If another thread is already waiting at the exchange point then + * it is resumed for thread scheduling purposes and receives the object + * passed in by the current thread. The current thread returns immediately, + * receiving the object passed to the exchange by that other thread. + * + *

If no other thread is already waiting at the exchange then the + * current thread is disabled for thread scheduling purposes and lies + * dormant until one of three things happens: + *

    + *
  • Some other thread enters the exchange; or + *
  • Some other thread {@linkplain Thread#interrupt interrupts} + * the current thread; or + *
  • The specified waiting time elapses. + *
+ *

If the current thread: + *

    + *
  • has its interrupted status set on entry to this method; or + *
  • is {@linkplain Thread#interrupt interrupted} while waiting + * for the exchange, + *
+ * then {@link InterruptedException} is thrown and the current thread's + * interrupted status is cleared. + * + *

If the specified waiting time elapses then {@link + * TimeoutException} is thrown. If the time is less than or equal + * to zero, the method will not wait at all. + * + * @param x the object to exchange + * @param timeout the maximum time to wait + * @param unit the time unit of the timeout argument + * @return the object provided by the other thread + * @throws InterruptedException if the current thread was + * interrupted while waiting + * @throws TimeoutException if the specified waiting time elapses + * before another thread enters the exchange + */ + public V exchange(V x, long timeout, TimeUnit unit) + throws InterruptedException, TimeoutException { + if (!Thread.interrupted()) { + Object v = doExchange((x == null) ? NULL_ITEM : x, + true, unit.toNanos(timeout)); + if (v == NULL_ITEM) + return null; + if (v != CANCEL) + return (V)v; + if (!Thread.interrupted()) + throw new TimeoutException(); + } + throw new InterruptedException(); + } +} diff -r e1953d8b8338 -r c8af252ea9eb rt/emul/compact/src/main/java/java/util/concurrent/ExecutionException.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/ExecutionException.java Sat Mar 19 10:48:29 2016 +0100 @@ -0,0 +1,94 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +package java.util.concurrent; + +/** + * Exception thrown when attempting to retrieve the result of a task + * that aborted by throwing an exception. This exception can be + * inspected using the {@link #getCause()} method. + * + * @see Future + * @since 1.5 + * @author Doug Lea + */ +public class ExecutionException extends Exception { + private static final long serialVersionUID = 7830266012832686185L; + + /** + * Constructs an ExecutionException with no detail message. + * The cause is not initialized, and may subsequently be + * initialized by a call to {@link #initCause(Throwable) initCause}. + */ + protected ExecutionException() { } + + /** + * Constructs an ExecutionException with the specified detail + * message. The cause is not initialized, and may subsequently be + * initialized by a call to {@link #initCause(Throwable) initCause}. + * + * @param message the detail message + */ + protected ExecutionException(String message) { + super(message); + } + + /** + * Constructs an ExecutionException with the specified detail + * message and cause. + * + * @param message the detail message + * @param cause the cause (which is saved for later retrieval by the + * {@link #getCause()} method) + */ + public ExecutionException(String message, Throwable cause) { + super(message, cause); + } + + /** + * Constructs an ExecutionException with the specified cause. + * The detail message is set to: + *

+     *  (cause == null ? null : cause.toString())
+ * (which typically contains the class and detail message of + * cause). + * + * @param cause the cause (which is saved for later retrieval by the + * {@link #getCause()} method) + */ + public ExecutionException(Throwable cause) { + super(cause); + } +} diff -r e1953d8b8338 -r c8af252ea9eb rt/emul/compact/src/main/java/java/util/concurrent/ExecutorCompletionService.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/ExecutorCompletionService.java Sat Mar 19 10:48:29 2016 +0100 @@ -0,0 +1,205 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +package java.util.concurrent; + +/** + * A {@link CompletionService} that uses a supplied {@link Executor} + * to execute tasks. This class arranges that submitted tasks are, + * upon completion, placed on a queue accessible using {@code take}. + * The class is lightweight enough to be suitable for transient use + * when processing groups of tasks. + * + *

+ * + * Usage Examples. + * + * Suppose you have a set of solvers for a certain problem, each + * returning a value of some type {@code Result}, and would like to + * run them concurrently, processing the results of each of them that + * return a non-null value, in some method {@code use(Result r)}. You + * could write this as: + * + *

 {@code
+ * void solve(Executor e,
+ *            Collection> solvers)
+ *     throws InterruptedException, ExecutionException {
+ *     CompletionService ecs
+ *         = new ExecutorCompletionService(e);
+ *     for (Callable s : solvers)
+ *         ecs.submit(s);
+ *     int n = solvers.size();
+ *     for (int i = 0; i < n; ++i) {
+ *         Result r = ecs.take().get();
+ *         if (r != null)
+ *             use(r);
+ *     }
+ * }}
+ * + * Suppose instead that you would like to use the first non-null result + * of the set of tasks, ignoring any that encounter exceptions, + * and cancelling all other tasks when the first one is ready: + * + *
 {@code
+ * void solve(Executor e,
+ *            Collection> solvers)
+ *     throws InterruptedException {
+ *     CompletionService ecs
+ *         = new ExecutorCompletionService(e);
+ *     int n = solvers.size();
+ *     List> futures
+ *         = new ArrayList>(n);
+ *     Result result = null;
+ *     try {
+ *         for (Callable s : solvers)
+ *             futures.add(ecs.submit(s));
+ *         for (int i = 0; i < n; ++i) {
+ *             try {
+ *                 Result r = ecs.take().get();
+ *                 if (r != null) {
+ *                     result = r;
+ *                     break;
+ *                 }
+ *             } catch (ExecutionException ignore) {}
+ *         }
+ *     }
+ *     finally {
+ *         for (Future f : futures)
+ *             f.cancel(true);
+ *     }
+ *
+ *     if (result != null)
+ *         use(result);
+ * }}
+ */ +public class ExecutorCompletionService implements CompletionService { + private final Executor executor; + private final AbstractExecutorService aes; + private final BlockingQueue> completionQueue; + + /** + * FutureTask extension to enqueue upon completion + */ + private class QueueingFuture extends FutureTask { + QueueingFuture(RunnableFuture task) { + super(task, null); + this.task = task; + } + protected void done() { completionQueue.add(task); } + private final Future task; + } + + private RunnableFuture newTaskFor(Callable task) { + if (aes == null) + return new FutureTask(task); + else + return aes.newTaskFor(task); + } + + private RunnableFuture newTaskFor(Runnable task, V result) { + if (aes == null) + return new FutureTask(task, result); + else + return aes.newTaskFor(task, result); + } + + /** + * Creates an ExecutorCompletionService using the supplied + * executor for base task execution and a + * {@link LinkedBlockingQueue} as a completion queue. + * + * @param executor the executor to use + * @throws NullPointerException if executor is {@code null} + */ + public ExecutorCompletionService(Executor executor) { + if (executor == null) + throw new NullPointerException(); + this.executor = executor; + this.aes = (executor instanceof AbstractExecutorService) ? + (AbstractExecutorService) executor : null; + this.completionQueue = new LinkedBlockingQueue>(); + } + + /** + * Creates an ExecutorCompletionService using the supplied + * executor for base task execution and the supplied queue as its + * completion queue. + * + * @param executor the executor to use + * @param completionQueue the queue to use as the completion queue + * normally one dedicated for use by this service. This + * queue is treated as unbounded -- failed attempted + * {@code Queue.add} operations for completed taskes cause + * them not to be retrievable. + * @throws NullPointerException if executor or completionQueue are {@code null} + */ + public ExecutorCompletionService(Executor executor, + BlockingQueue> completionQueue) { + if (executor == null || completionQueue == null) + throw new NullPointerException(); + this.executor = executor; + this.aes = (executor instanceof AbstractExecutorService) ? + (AbstractExecutorService) executor : null; + this.completionQueue = completionQueue; + } + + public Future submit(Callable task) { + if (task == null) throw new NullPointerException(); + RunnableFuture f = newTaskFor(task); + executor.execute(new QueueingFuture(f)); + return f; + } + + public Future submit(Runnable task, V result) { + if (task == null) throw new NullPointerException(); + RunnableFuture f = newTaskFor(task, result); + executor.execute(new QueueingFuture(f)); + return f; + } + + public Future take() throws InterruptedException { + return completionQueue.take(); + } + + public Future poll() { + return completionQueue.poll(); + } + + public Future poll(long timeout, TimeUnit unit) + throws InterruptedException { + return completionQueue.poll(timeout, unit); + } + +} diff -r e1953d8b8338 -r c8af252ea9eb rt/emul/compact/src/main/java/java/util/concurrent/ExecutorService.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/ExecutorService.java Sat Mar 19 10:48:29 2016 +0100 @@ -0,0 +1,370 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +package java.util.concurrent; +import java.util.List; +import java.util.Collection; +import java.security.PrivilegedAction; +import java.security.PrivilegedExceptionAction; + +/** + * An {@link Executor} that provides methods to manage termination and + * methods that can produce a {@link Future} for tracking progress of + * one or more asynchronous tasks. + * + *

An ExecutorService can be shut down, which will cause + * it to reject new tasks. Two different methods are provided for + * shutting down an ExecutorService. The {@link #shutdown} + * method will allow previously submitted tasks to execute before + * terminating, while the {@link #shutdownNow} method prevents waiting + * tasks from starting and attempts to stop currently executing tasks. + * Upon termination, an executor has no tasks actively executing, no + * tasks awaiting execution, and no new tasks can be submitted. An + * unused ExecutorService should be shut down to allow + * reclamation of its resources. + * + *

Method submit extends base method {@link + * Executor#execute} by creating and returning a {@link Future} that + * can be used to cancel execution and/or wait for completion. + * Methods invokeAny and invokeAll perform the most + * commonly useful forms of bulk execution, executing a collection of + * tasks and then waiting for at least one, or all, to + * complete. (Class {@link ExecutorCompletionService} can be used to + * write customized variants of these methods.) + * + *

The {@link Executors} class provides factory methods for the + * executor services provided in this package. + * + *

Usage Examples

+ * + * Here is a sketch of a network service in which threads in a thread + * pool service incoming requests. It uses the preconfigured {@link + * Executors#newFixedThreadPool} factory method: + * + *
+ * class NetworkService implements Runnable {
+ *   private final ServerSocket serverSocket;
+ *   private final ExecutorService pool;
+ *
+ *   public NetworkService(int port, int poolSize)
+ *       throws IOException {
+ *     serverSocket = new ServerSocket(port);
+ *     pool = Executors.newFixedThreadPool(poolSize);
+ *   }
+ *
+ *   public void run() { // run the service
+ *     try {
+ *       for (;;) {
+ *         pool.execute(new Handler(serverSocket.accept()));
+ *       }
+ *     } catch (IOException ex) {
+ *       pool.shutdown();
+ *     }
+ *   }
+ * }
+ *
+ * class Handler implements Runnable {
+ *   private final Socket socket;
+ *   Handler(Socket socket) { this.socket = socket; }
+ *   public void run() {
+ *     // read and service request on socket
+ *   }
+ * }
+ * 
+ * + * The following method shuts down an ExecutorService in two phases, + * first by calling shutdown to reject incoming tasks, and then + * calling shutdownNow, if necessary, to cancel any lingering tasks: + * + *
+ * void shutdownAndAwaitTermination(ExecutorService pool) {
+ *   pool.shutdown(); // Disable new tasks from being submitted
+ *   try {
+ *     // Wait a while for existing tasks to terminate
+ *     if (!pool.awaitTermination(60, TimeUnit.SECONDS)) {
+ *       pool.shutdownNow(); // Cancel currently executing tasks
+ *       // Wait a while for tasks to respond to being cancelled
+ *       if (!pool.awaitTermination(60, TimeUnit.SECONDS))
+ *           System.err.println("Pool did not terminate");
+ *     }
+ *   } catch (InterruptedException ie) {
+ *     // (Re-)Cancel if current thread also interrupted
+ *     pool.shutdownNow();
+ *     // Preserve interrupt status
+ *     Thread.currentThread().interrupt();
+ *   }
+ * }
+ * 
+ * + *

Memory consistency effects: Actions in a thread prior to the + * submission of a {@code Runnable} or {@code Callable} task to an + * {@code ExecutorService} + * happen-before + * any actions taken by that task, which in turn happen-before the + * result is retrieved via {@code Future.get()}. + * + * @since 1.5 + * @author Doug Lea + */ +public interface ExecutorService extends Executor { + + /** + * Initiates an orderly shutdown in which previously submitted + * tasks are executed, but no new tasks will be accepted. + * Invocation has no additional effect if already shut down. + * + *

This method does not wait for previously submitted tasks to + * complete execution. Use {@link #awaitTermination awaitTermination} + * to do that. + * + * @throws SecurityException if a security manager exists and + * shutting down this ExecutorService may manipulate + * threads that the caller is not permitted to modify + * because it does not hold {@link + * java.lang.RuntimePermission}("modifyThread"), + * or the security manager's checkAccess method + * denies access. + */ + void shutdown(); + + /** + * Attempts to stop all actively executing tasks, halts the + * processing of waiting tasks, and returns a list of the tasks + * that were awaiting execution. + * + *

This method does not wait for actively executing tasks to + * terminate. Use {@link #awaitTermination awaitTermination} to + * do that. + * + *

There are no guarantees beyond best-effort attempts to stop + * processing actively executing tasks. For example, typical + * implementations will cancel via {@link Thread#interrupt}, so any + * task that fails to respond to interrupts may never terminate. + * + * @return list of tasks that never commenced execution + * @throws SecurityException if a security manager exists and + * shutting down this ExecutorService may manipulate + * threads that the caller is not permitted to modify + * because it does not hold {@link + * java.lang.RuntimePermission}("modifyThread"), + * or the security manager's checkAccess method + * denies access. + */ + List shutdownNow(); + + /** + * Returns true if this executor has been shut down. + * + * @return true if this executor has been shut down + */ + boolean isShutdown(); + + /** + * Returns true if all tasks have completed following shut down. + * Note that isTerminated is never true unless + * either shutdown or shutdownNow was called first. + * + * @return true if all tasks have completed following shut down + */ + boolean isTerminated(); + + /** + * Blocks until all tasks have completed execution after a shutdown + * request, or the timeout occurs, or the current thread is + * interrupted, whichever happens first. + * + * @param timeout the maximum time to wait + * @param unit the time unit of the timeout argument + * @return true if this executor terminated and + * false if the timeout elapsed before termination + * @throws InterruptedException if interrupted while waiting + */ + boolean awaitTermination(long timeout, TimeUnit unit) + throws InterruptedException; + + + /** + * Submits a value-returning task for execution and returns a + * Future representing the pending results of the task. The + * Future's get method will return the task's result upon + * successful completion. + * + *

+ * If you would like to immediately block waiting + * for a task, you can use constructions of the form + * result = exec.submit(aCallable).get(); + * + *

Note: The {@link Executors} class includes a set of methods + * that can convert some other common closure-like objects, + * for example, {@link java.security.PrivilegedAction} to + * {@link Callable} form so they can be submitted. + * + * @param task the task to submit + * @return a Future representing pending completion of the task + * @throws RejectedExecutionException if the task cannot be + * scheduled for execution + * @throws NullPointerException if the task is null + */ + Future submit(Callable task); + + /** + * Submits a Runnable task for execution and returns a Future + * representing that task. The Future's get method will + * return the given result upon successful completion. + * + * @param task the task to submit + * @param result the result to return + * @return a Future representing pending completion of the task + * @throws RejectedExecutionException if the task cannot be + * scheduled for execution + * @throws NullPointerException if the task is null + */ + Future submit(Runnable task, T result); + + /** + * Submits a Runnable task for execution and returns a Future + * representing that task. The Future's get method will + * return null upon successful completion. + * + * @param task the task to submit + * @return a Future representing pending completion of the task + * @throws RejectedExecutionException if the task cannot be + * scheduled for execution + * @throws NullPointerException if the task is null + */ + Future submit(Runnable task); + + /** + * Executes the given tasks, returning a list of Futures holding + * their status and results when all complete. + * {@link Future#isDone} is true for each + * element of the returned list. + * Note that a completed task could have + * terminated either normally or by throwing an exception. + * The results of this method are undefined if the given + * collection is modified while this operation is in progress. + * + * @param tasks the collection of tasks + * @return A list of Futures representing the tasks, in the same + * sequential order as produced by the iterator for the + * given task list, each of which has completed. + * @throws InterruptedException if interrupted while waiting, in + * which case unfinished tasks are cancelled. + * @throws NullPointerException if tasks or any of its elements are null + * @throws RejectedExecutionException if any task cannot be + * scheduled for execution + */ + + List> invokeAll(Collection> tasks) + throws InterruptedException; + + /** + * Executes the given tasks, returning a list of Futures holding + * their status and results + * when all complete or the timeout expires, whichever happens first. + * {@link Future#isDone} is true for each + * element of the returned list. + * Upon return, tasks that have not completed are cancelled. + * Note that a completed task could have + * terminated either normally or by throwing an exception. + * The results of this method are undefined if the given + * collection is modified while this operation is in progress. + * + * @param tasks the collection of tasks + * @param timeout the maximum time to wait + * @param unit the time unit of the timeout argument + * @return a list of Futures representing the tasks, in the same + * sequential order as produced by the iterator for the + * given task list. If the operation did not time out, + * each task will have completed. If it did time out, some + * of these tasks will not have completed. + * @throws InterruptedException if interrupted while waiting, in + * which case unfinished tasks are cancelled + * @throws NullPointerException if tasks, any of its elements, or + * unit are null + * @throws RejectedExecutionException if any task cannot be scheduled + * for execution + */ + List> invokeAll(Collection> tasks, + long timeout, TimeUnit unit) + throws InterruptedException; + + /** + * Executes the given tasks, returning the result + * of one that has completed successfully (i.e., without throwing + * an exception), if any do. Upon normal or exceptional return, + * tasks that have not completed are cancelled. + * The results of this method are undefined if the given + * collection is modified while this operation is in progress. + * + * @param tasks the collection of tasks + * @return the result returned by one of the tasks + * @throws InterruptedException if interrupted while waiting + * @throws NullPointerException if tasks or any element task + * subject to execution is null + * @throws IllegalArgumentException if tasks is empty + * @throws ExecutionException if no task successfully completes + * @throws RejectedExecutionException if tasks cannot be scheduled + * for execution + */ + T invokeAny(Collection> tasks) + throws InterruptedException, ExecutionException; + + /** + * Executes the given tasks, returning the result + * of one that has completed successfully (i.e., without throwing + * an exception), if any do before the given timeout elapses. + * Upon normal or exceptional return, tasks that have not + * completed are cancelled. + * The results of this method are undefined if the given + * collection is modified while this operation is in progress. + * + * @param tasks the collection of tasks + * @param timeout the maximum time to wait + * @param unit the time unit of the timeout argument + * @return the result returned by one of the tasks. + * @throws InterruptedException if interrupted while waiting + * @throws NullPointerException if tasks, or unit, or any element + * task subject to execution is null + * @throws TimeoutException if the given timeout elapses before + * any task successfully completes + * @throws ExecutionException if no task successfully completes + * @throws RejectedExecutionException if tasks cannot be scheduled + * for execution + */ + T invokeAny(Collection> tasks, + long timeout, TimeUnit unit) + throws InterruptedException, ExecutionException, TimeoutException; +} diff -r e1953d8b8338 -r c8af252ea9eb rt/emul/compact/src/main/java/java/util/concurrent/Executors.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/Executors.java Sat Mar 19 10:48:29 2016 +0100 @@ -0,0 +1,706 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +package java.util.concurrent; +import java.util.*; +import java.util.concurrent.atomic.AtomicInteger; +import java.security.AccessControlContext; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.security.PrivilegedExceptionAction; +import java.security.PrivilegedActionException; +import java.security.AccessControlException; +import sun.security.util.SecurityConstants; + +/** + * Factory and utility methods for {@link Executor}, {@link + * ExecutorService}, {@link ScheduledExecutorService}, {@link + * ThreadFactory}, and {@link Callable} classes defined in this + * package. This class supports the following kinds of methods: + * + *

    + *
  • Methods that create and return an {@link ExecutorService} + * set up with commonly useful configuration settings. + *
  • Methods that create and return a {@link ScheduledExecutorService} + * set up with commonly useful configuration settings. + *
  • Methods that create and return a "wrapped" ExecutorService, that + * disables reconfiguration by making implementation-specific methods + * inaccessible. + *
  • Methods that create and return a {@link ThreadFactory} + * that sets newly created threads to a known state. + *
  • Methods that create and return a {@link Callable} + * out of other closure-like forms, so they can be used + * in execution methods requiring Callable. + *
+ * + * @since 1.5 + * @author Doug Lea + */ +public class Executors { + + /** + * Creates a thread pool that reuses a fixed number of threads + * operating off a shared unbounded queue. At any point, at most + * nThreads threads will be active processing tasks. + * If additional tasks are submitted when all threads are active, + * they will wait in the queue until a thread is available. + * If any thread terminates due to a failure during execution + * prior to shutdown, a new one will take its place if needed to + * execute subsequent tasks. The threads in the pool will exist + * until it is explicitly {@link ExecutorService#shutdown shutdown}. + * + * @param nThreads the number of threads in the pool + * @return the newly created thread pool + * @throws IllegalArgumentException if {@code nThreads <= 0} + */ + public static ExecutorService newFixedThreadPool(int nThreads) { + return new ThreadPoolExecutor(nThreads, nThreads, + 0L, TimeUnit.MILLISECONDS, + new LinkedBlockingQueue()); + } + + /** + * Creates a thread pool that reuses a fixed number of threads + * operating off a shared unbounded queue, using the provided + * ThreadFactory to create new threads when needed. At any point, + * at most nThreads threads will be active processing + * tasks. If additional tasks are submitted when all threads are + * active, they will wait in the queue until a thread is + * available. If any thread terminates due to a failure during + * execution prior to shutdown, a new one will take its place if + * needed to execute subsequent tasks. The threads in the pool will + * exist until it is explicitly {@link ExecutorService#shutdown + * shutdown}. + * + * @param nThreads the number of threads in the pool + * @param threadFactory the factory to use when creating new threads + * @return the newly created thread pool + * @throws NullPointerException if threadFactory is null + * @throws IllegalArgumentException if {@code nThreads <= 0} + */ + public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) { + return new ThreadPoolExecutor(nThreads, nThreads, + 0L, TimeUnit.MILLISECONDS, + new LinkedBlockingQueue(), + threadFactory); + } + + /** + * Creates an Executor that uses a single worker thread operating + * off an unbounded queue. (Note however that if this single + * thread terminates due to a failure during execution prior to + * shutdown, a new one will take its place if needed to execute + * subsequent tasks.) Tasks are guaranteed to execute + * sequentially, and no more than one task will be active at any + * given time. Unlike the otherwise equivalent + * newFixedThreadPool(1) the returned executor is + * guaranteed not to be reconfigurable to use additional threads. + * + * @return the newly created single-threaded Executor + */ + public static ExecutorService newSingleThreadExecutor() { + return new FinalizableDelegatedExecutorService + (new ThreadPoolExecutor(1, 1, + 0L, TimeUnit.MILLISECONDS, + new LinkedBlockingQueue())); + } + + /** + * Creates an Executor that uses a single worker thread operating + * off an unbounded queue, and uses the provided ThreadFactory to + * create a new thread when needed. Unlike the otherwise + * equivalent newFixedThreadPool(1, threadFactory) the + * returned executor is guaranteed not to be reconfigurable to use + * additional threads. + * + * @param threadFactory the factory to use when creating new + * threads + * + * @return the newly created single-threaded Executor + * @throws NullPointerException if threadFactory is null + */ + public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) { + return new FinalizableDelegatedExecutorService + (new ThreadPoolExecutor(1, 1, + 0L, TimeUnit.MILLISECONDS, + new LinkedBlockingQueue(), + threadFactory)); + } + + /** + * Creates a thread pool that creates new threads as needed, but + * will reuse previously constructed threads when they are + * available. These pools will typically improve the performance + * of programs that execute many short-lived asynchronous tasks. + * Calls to execute will reuse previously constructed + * threads if available. If no existing thread is available, a new + * thread will be created and added to the pool. Threads that have + * not been used for sixty seconds are terminated and removed from + * the cache. Thus, a pool that remains idle for long enough will + * not consume any resources. Note that pools with similar + * properties but different details (for example, timeout parameters) + * may be created using {@link ThreadPoolExecutor} constructors. + * + * @return the newly created thread pool + */ + public static ExecutorService newCachedThreadPool() { + return new ThreadPoolExecutor(0, Integer.MAX_VALUE, + 60L, TimeUnit.SECONDS, + new SynchronousQueue()); + } + + /** + * Creates a thread pool that creates new threads as needed, but + * will reuse previously constructed threads when they are + * available, and uses the provided + * ThreadFactory to create new threads when needed. + * @param threadFactory the factory to use when creating new threads + * @return the newly created thread pool + * @throws NullPointerException if threadFactory is null + */ + public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) { + return new ThreadPoolExecutor(0, Integer.MAX_VALUE, + 60L, TimeUnit.SECONDS, + new SynchronousQueue(), + threadFactory); + } + + /** + * Creates a single-threaded executor that can schedule commands + * to run after a given delay, or to execute periodically. + * (Note however that if this single + * thread terminates due to a failure during execution prior to + * shutdown, a new one will take its place if needed to execute + * subsequent tasks.) Tasks are guaranteed to execute + * sequentially, and no more than one task will be active at any + * given time. Unlike the otherwise equivalent + * newScheduledThreadPool(1) the returned executor is + * guaranteed not to be reconfigurable to use additional threads. + * @return the newly created scheduled executor + */ + public static ScheduledExecutorService newSingleThreadScheduledExecutor() { + return new DelegatedScheduledExecutorService + (new ScheduledThreadPoolExecutor(1)); + } + + /** + * Creates a single-threaded executor that can schedule commands + * to run after a given delay, or to execute periodically. (Note + * however that if this single thread terminates due to a failure + * during execution prior to shutdown, a new one will take its + * place if needed to execute subsequent tasks.) Tasks are + * guaranteed to execute sequentially, and no more than one task + * will be active at any given time. Unlike the otherwise + * equivalent newScheduledThreadPool(1, threadFactory) + * the returned executor is guaranteed not to be reconfigurable to + * use additional threads. + * @param threadFactory the factory to use when creating new + * threads + * @return a newly created scheduled executor + * @throws NullPointerException if threadFactory is null + */ + public static ScheduledExecutorService newSingleThreadScheduledExecutor(ThreadFactory threadFactory) { + return new DelegatedScheduledExecutorService + (new ScheduledThreadPoolExecutor(1, threadFactory)); + } + + /** + * Creates a thread pool that can schedule commands to run after a + * given delay, or to execute periodically. + * @param corePoolSize the number of threads to keep in the pool, + * even if they are idle. + * @return a newly created scheduled thread pool + * @throws IllegalArgumentException if {@code corePoolSize < 0} + */ + public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) { + return new ScheduledThreadPoolExecutor(corePoolSize); + } + + /** + * Creates a thread pool that can schedule commands to run after a + * given delay, or to execute periodically. + * @param corePoolSize the number of threads to keep in the pool, + * even if they are idle. + * @param threadFactory the factory to use when the executor + * creates a new thread. + * @return a newly created scheduled thread pool + * @throws IllegalArgumentException if {@code corePoolSize < 0} + * @throws NullPointerException if threadFactory is null + */ + public static ScheduledExecutorService newScheduledThreadPool( + int corePoolSize, ThreadFactory threadFactory) { + return new ScheduledThreadPoolExecutor(corePoolSize, threadFactory); + } + + + /** + * Returns an object that delegates all defined {@link + * ExecutorService} methods to the given executor, but not any + * other methods that might otherwise be accessible using + * casts. This provides a way to safely "freeze" configuration and + * disallow tuning of a given concrete implementation. + * @param executor the underlying implementation + * @return an ExecutorService instance + * @throws NullPointerException if executor null + */ + public static ExecutorService unconfigurableExecutorService(ExecutorService executor) { + if (executor == null) + throw new NullPointerException(); + return new DelegatedExecutorService(executor); + } + + /** + * Returns an object that delegates all defined {@link + * ScheduledExecutorService} methods to the given executor, but + * not any other methods that might otherwise be accessible using + * casts. This provides a way to safely "freeze" configuration and + * disallow tuning of a given concrete implementation. + * @param executor the underlying implementation + * @return a ScheduledExecutorService instance + * @throws NullPointerException if executor null + */ + public static ScheduledExecutorService unconfigurableScheduledExecutorService(ScheduledExecutorService executor) { + if (executor == null) + throw new NullPointerException(); + return new DelegatedScheduledExecutorService(executor); + } + + /** + * Returns a default thread factory used to create new threads. + * This factory creates all new threads used by an Executor in the + * same {@link ThreadGroup}. If there is a {@link + * java.lang.SecurityManager}, it uses the group of {@link + * System#getSecurityManager}, else the group of the thread + * invoking this defaultThreadFactory method. Each new + * thread is created as a non-daemon thread with priority set to + * the smaller of Thread.NORM_PRIORITY and the maximum + * priority permitted in the thread group. New threads have names + * accessible via {@link Thread#getName} of + * pool-N-thread-M, where N is the sequence + * number of this factory, and M is the sequence number + * of the thread created by this factory. + * @return a thread factory + */ + public static ThreadFactory defaultThreadFactory() { + return new DefaultThreadFactory(); + } + + /** + * Returns a thread factory used to create new threads that + * have the same permissions as the current thread. + * This factory creates threads with the same settings as {@link + * Executors#defaultThreadFactory}, additionally setting the + * AccessControlContext and contextClassLoader of new threads to + * be the same as the thread invoking this + * privilegedThreadFactory method. A new + * privilegedThreadFactory can be created within an + * {@link AccessController#doPrivileged} action setting the + * current thread's access control context to create threads with + * the selected permission settings holding within that action. + * + *

Note that while tasks running within such threads will have + * the same access control and class loader settings as the + * current thread, they need not have the same {@link + * java.lang.ThreadLocal} or {@link + * java.lang.InheritableThreadLocal} values. If necessary, + * particular values of thread locals can be set or reset before + * any task runs in {@link ThreadPoolExecutor} subclasses using + * {@link ThreadPoolExecutor#beforeExecute}. Also, if it is + * necessary to initialize worker threads to have the same + * InheritableThreadLocal settings as some other designated + * thread, you can create a custom ThreadFactory in which that + * thread waits for and services requests to create others that + * will inherit its values. + * + * @return a thread factory + * @throws AccessControlException if the current access control + * context does not have permission to both get and set context + * class loader. + */ + public static ThreadFactory privilegedThreadFactory() { + return new PrivilegedThreadFactory(); + } + + /** + * Returns a {@link Callable} object that, when + * called, runs the given task and returns the given result. This + * can be useful when applying methods requiring a + * Callable to an otherwise resultless action. + * @param task the task to run + * @param result the result to return + * @return a callable object + * @throws NullPointerException if task null + */ + public static Callable callable(Runnable task, T result) { + if (task == null) + throw new NullPointerException(); + return new RunnableAdapter(task, result); + } + + /** + * Returns a {@link Callable} object that, when + * called, runs the given task and returns null. + * @param task the task to run + * @return a callable object + * @throws NullPointerException if task null + */ + public static Callable callable(Runnable task) { + if (task == null) + throw new NullPointerException(); + return new RunnableAdapter(task, null); + } + + /** + * Returns a {@link Callable} object that, when + * called, runs the given privileged action and returns its result. + * @param action the privileged action to run + * @return a callable object + * @throws NullPointerException if action null + */ + public static Callable callable(final PrivilegedAction action) { + if (action == null) + throw new NullPointerException(); + return new Callable() { + public Object call() { return action.run(); }}; + } + + /** + * Returns a {@link Callable} object that, when + * called, runs the given privileged exception action and returns + * its result. + * @param action the privileged exception action to run + * @return a callable object + * @throws NullPointerException if action null + */ + public static Callable callable(final PrivilegedExceptionAction action) { + if (action == null) + throw new NullPointerException(); + return new Callable() { + public Object call() throws Exception { return action.run(); }}; + } + + /** + * Returns a {@link Callable} object that will, when + * called, execute the given callable under the current + * access control context. This method should normally be + * invoked within an {@link AccessController#doPrivileged} action + * to create callables that will, if possible, execute under the + * selected permission settings holding within that action; or if + * not possible, throw an associated {@link + * AccessControlException}. + * @param callable the underlying task + * @return a callable object + * @throws NullPointerException if callable null + * + */ + public static Callable privilegedCallable(Callable callable) { + if (callable == null) + throw new NullPointerException(); + return new PrivilegedCallable(callable); + } + + /** + * Returns a {@link Callable} object that will, when + * called, execute the given callable under the current + * access control context, with the current context class loader + * as the context class loader. This method should normally be + * invoked within an {@link AccessController#doPrivileged} action + * to create callables that will, if possible, execute under the + * selected permission settings holding within that action; or if + * not possible, throw an associated {@link + * AccessControlException}. + * @param callable the underlying task + * + * @return a callable object + * @throws NullPointerException if callable null + * @throws AccessControlException if the current access control + * context does not have permission to both set and get context + * class loader. + */ + public static Callable privilegedCallableUsingCurrentClassLoader(Callable callable) { + if (callable == null) + throw new NullPointerException(); + return new PrivilegedCallableUsingCurrentClassLoader(callable); + } + + // Non-public classes supporting the public methods + + /** + * A callable that runs given task and returns given result + */ + static final class RunnableAdapter implements Callable { + final Runnable task; + final T result; + RunnableAdapter(Runnable task, T result) { + this.task = task; + this.result = result; + } + public T call() { + task.run(); + return result; + } + } + + /** + * A callable that runs under established access control settings + */ + static final class PrivilegedCallable implements Callable { + private final Callable task; + private final AccessControlContext acc; + + PrivilegedCallable(Callable task) { + this.task = task; + this.acc = AccessController.getContext(); + } + + public T call() throws Exception { + try { + return AccessController.doPrivileged( + new PrivilegedExceptionAction() { + public T run() throws Exception { + return task.call(); + } + }, acc); + } catch (PrivilegedActionException e) { + throw e.getException(); + } + } + } + + /** + * A callable that runs under established access control settings and + * current ClassLoader + */ + static final class PrivilegedCallableUsingCurrentClassLoader implements Callable { + private final Callable task; + private final AccessControlContext acc; + private final ClassLoader ccl; + + PrivilegedCallableUsingCurrentClassLoader(Callable task) { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + // Calls to getContextClassLoader from this class + // never trigger a security check, but we check + // whether our callers have this permission anyways. + sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION); + + // Whether setContextClassLoader turns out to be necessary + // or not, we fail fast if permission is not available. + sm.checkPermission(new RuntimePermission("setContextClassLoader")); + } + this.task = task; + this.acc = AccessController.getContext(); + this.ccl = Thread.currentThread().getContextClassLoader(); + } + + public T call() throws Exception { + try { + return AccessController.doPrivileged( + new PrivilegedExceptionAction() { + public T run() throws Exception { + ClassLoader savedcl = null; + Thread t = Thread.currentThread(); + try { + ClassLoader cl = t.getContextClassLoader(); + if (ccl != cl) { + t.setContextClassLoader(ccl); + savedcl = cl; + } + return task.call(); + } finally { + if (savedcl != null) + t.setContextClassLoader(savedcl); + } + } + }, acc); + } catch (PrivilegedActionException e) { + throw e.getException(); + } + } + } + + /** + * The default thread factory + */ + static class DefaultThreadFactory implements ThreadFactory { + private static final AtomicInteger poolNumber = new AtomicInteger(1); + private final ThreadGroup group; + private final AtomicInteger threadNumber = new AtomicInteger(1); + private final String namePrefix; + + DefaultThreadFactory() { + SecurityManager s = System.getSecurityManager(); + group = (s != null) ? s.getThreadGroup() : + Thread.currentThread().getThreadGroup(); + namePrefix = "pool-" + + poolNumber.getAndIncrement() + + "-thread-"; + } + + public Thread newThread(Runnable r) { + Thread t = new Thread(group, r, + namePrefix + threadNumber.getAndIncrement(), + 0); + if (t.isDaemon()) + t.setDaemon(false); + if (t.getPriority() != Thread.NORM_PRIORITY) + t.setPriority(Thread.NORM_PRIORITY); + return t; + } + } + + /** + * Thread factory capturing access control context and class loader + */ + static class PrivilegedThreadFactory extends DefaultThreadFactory { + private final AccessControlContext acc; + private final ClassLoader ccl; + + PrivilegedThreadFactory() { + super(); + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + // Calls to getContextClassLoader from this class + // never trigger a security check, but we check + // whether our callers have this permission anyways. + sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION); + + // Fail fast + sm.checkPermission(new RuntimePermission("setContextClassLoader")); + } + this.acc = AccessController.getContext(); + this.ccl = Thread.currentThread().getContextClassLoader(); + } + + public Thread newThread(final Runnable r) { + return super.newThread(new Runnable() { + public void run() { + AccessController.doPrivileged(new PrivilegedAction() { + public Void run() { + Thread.currentThread().setContextClassLoader(ccl); + r.run(); + return null; + } + }, acc); + } + }); + } + } + + /** + * A wrapper class that exposes only the ExecutorService methods + * of an ExecutorService implementation. + */ + static class DelegatedExecutorService extends AbstractExecutorService { + private final ExecutorService e; + DelegatedExecutorService(ExecutorService executor) { e = executor; } + public void execute(Runnable command) { e.execute(command); } + public void shutdown() { e.shutdown(); } + public List shutdownNow() { return e.shutdownNow(); } + public boolean isShutdown() { return e.isShutdown(); } + public boolean isTerminated() { return e.isTerminated(); } + public boolean awaitTermination(long timeout, TimeUnit unit) + throws InterruptedException { + return e.awaitTermination(timeout, unit); + } + public Future submit(Runnable task) { + return e.submit(task); + } + public Future submit(Callable task) { + return e.submit(task); + } + public Future submit(Runnable task, T result) { + return e.submit(task, result); + } + public List> invokeAll(Collection> tasks) + throws InterruptedException { + return e.invokeAll(tasks); + } + public List> invokeAll(Collection> tasks, + long timeout, TimeUnit unit) + throws InterruptedException { + return e.invokeAll(tasks, timeout, unit); + } + public T invokeAny(Collection> tasks) + throws InterruptedException, ExecutionException { + return e.invokeAny(tasks); + } + public T invokeAny(Collection> tasks, + long timeout, TimeUnit unit) + throws InterruptedException, ExecutionException, TimeoutException { + return e.invokeAny(tasks, timeout, unit); + } + } + + static class FinalizableDelegatedExecutorService + extends DelegatedExecutorService { + FinalizableDelegatedExecutorService(ExecutorService executor) { + super(executor); + } + protected void finalize() { + super.shutdown(); + } + } + + /** + * A wrapper class that exposes only the ScheduledExecutorService + * methods of a ScheduledExecutorService implementation. + */ + static class DelegatedScheduledExecutorService + extends DelegatedExecutorService + implements ScheduledExecutorService { + private final ScheduledExecutorService e; + DelegatedScheduledExecutorService(ScheduledExecutorService executor) { + super(executor); + e = executor; + } + public ScheduledFuture schedule(Runnable command, long delay, TimeUnit unit) { + return e.schedule(command, delay, unit); + } + public ScheduledFuture schedule(Callable callable, long delay, TimeUnit unit) { + return e.schedule(callable, delay, unit); + } + public ScheduledFuture scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) { + return e.scheduleAtFixedRate(command, initialDelay, period, unit); + } + public ScheduledFuture scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit) { + return e.scheduleWithFixedDelay(command, initialDelay, delay, unit); + } + } + + + /** Cannot instantiate. */ + private Executors() {} +} diff -r e1953d8b8338 -r c8af252ea9eb rt/emul/compact/src/main/java/java/util/concurrent/ForkJoinPool.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/ForkJoinPool.java Sat Mar 19 10:48:29 2016 +0100 @@ -0,0 +1,2177 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +package java.util.concurrent; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Random; +import java.util.concurrent.AbstractExecutorService; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Future; +import java.util.concurrent.RejectedExecutionException; +import java.util.concurrent.RunnableFuture; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.locks.LockSupport; +import java.util.concurrent.locks.ReentrantLock; +import java.util.concurrent.locks.Condition; + +/** + * An {@link ExecutorService} for running {@link ForkJoinTask}s. + * A {@code ForkJoinPool} provides the entry point for submissions + * from non-{@code ForkJoinTask} clients, as well as management and + * monitoring operations. + * + *

A {@code ForkJoinPool} differs from other kinds of {@link + * ExecutorService} mainly by virtue of employing + * work-stealing: all threads in the pool attempt to find and + * execute subtasks created by other active tasks (eventually blocking + * waiting for work if none exist). This enables efficient processing + * when most tasks spawn other subtasks (as do most {@code + * ForkJoinTask}s). When setting asyncMode to true in + * constructors, {@code ForkJoinPool}s may also be appropriate for use + * with event-style tasks that are never joined. + * + *

A {@code ForkJoinPool} is constructed with a given target + * parallelism level; by default, equal to the number of available + * processors. The pool attempts to maintain enough active (or + * available) threads by dynamically adding, suspending, or resuming + * internal worker threads, even if some tasks are stalled waiting to + * join others. However, no such adjustments are guaranteed in the + * face of blocked IO or other unmanaged synchronization. The nested + * {@link ManagedBlocker} interface enables extension of the kinds of + * synchronization accommodated. + * + *

In addition to execution and lifecycle control methods, this + * class provides status check methods (for example + * {@link #getStealCount}) that are intended to aid in developing, + * tuning, and monitoring fork/join applications. Also, method + * {@link #toString} returns indications of pool state in a + * convenient form for informal monitoring. + * + *

As is the case with other ExecutorServices, there are three + * main task execution methods summarized in the following + * table. These are designed to be used by clients not already engaged + * in fork/join computations in the current pool. The main forms of + * these methods accept instances of {@code ForkJoinTask}, but + * overloaded forms also allow mixed execution of plain {@code + * Runnable}- or {@code Callable}- based activities as well. However, + * tasks that are already executing in a pool should normally + * NOT use these pool execution methods, but instead use the + * within-computation forms listed in the table. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Call from non-fork/join clients Call from within fork/join computations
Arrange async execution {@link #execute(ForkJoinTask)} {@link ForkJoinTask#fork}
Await and obtain result {@link #invoke(ForkJoinTask)} {@link ForkJoinTask#invoke}
Arrange exec and obtain Future {@link #submit(ForkJoinTask)} {@link ForkJoinTask#fork} (ForkJoinTasks are Futures)
+ * + *

Sample Usage. Normally a single {@code ForkJoinPool} is + * used for all parallel task execution in a program or subsystem. + * Otherwise, use would not usually outweigh the construction and + * bookkeeping overhead of creating a large set of threads. For + * example, a common pool could be used for the {@code SortTasks} + * illustrated in {@link RecursiveAction}. Because {@code + * ForkJoinPool} uses threads in {@linkplain java.lang.Thread#isDaemon + * daemon} mode, there is typically no need to explicitly {@link + * #shutdown} such a pool upon program exit. + * + *

+ * static final ForkJoinPool mainPool = new ForkJoinPool();
+ * ...
+ * public void sort(long[] array) {
+ *   mainPool.invoke(new SortTask(array, 0, array.length));
+ * }
+ * 
+ * + *

Implementation notes: This implementation restricts the + * maximum number of running threads to 32767. Attempts to create + * pools with greater than the maximum number result in + * {@code IllegalArgumentException}. + * + *

This implementation rejects submitted tasks (that is, by throwing + * {@link RejectedExecutionException}) only when the pool is shut down + * or internal resources have been exhausted. + * + * @since 1.7 + * @author Doug Lea + */ +public class ForkJoinPool extends AbstractExecutorService { + + /* + * Implementation Overview + * + * This class provides the central bookkeeping and control for a + * set of worker threads: Submissions from non-FJ threads enter + * into a submission queue. Workers take these tasks and typically + * split them into subtasks that may be stolen by other workers. + * Preference rules give first priority to processing tasks from + * their own queues (LIFO or FIFO, depending on mode), then to + * randomized FIFO steals of tasks in other worker queues, and + * lastly to new submissions. + * + * The main throughput advantages of work-stealing stem from + * decentralized control -- workers mostly take tasks from + * themselves or each other. We cannot negate this in the + * implementation of other management responsibilities. The main + * tactic for avoiding bottlenecks is packing nearly all + * essentially atomic control state into a single 64bit volatile + * variable ("ctl"). This variable is read on the order of 10-100 + * times as often as it is modified (always via CAS). (There is + * some additional control state, for example variable "shutdown" + * for which we can cope with uncoordinated updates.) This + * streamlines synchronization and control at the expense of messy + * constructions needed to repack status bits upon updates. + * Updates tend not to contend with each other except during + * bursts while submitted tasks begin or end. In some cases when + * they do contend, threads can instead do something else + * (usually, scan for tasks) until contention subsides. + * + * To enable packing, we restrict maximum parallelism to (1<<15)-1 + * (which is far in excess of normal operating range) to allow + * ids, counts, and their negations (used for thresholding) to fit + * into 16bit fields. + * + * Recording Workers. Workers are recorded in the "workers" array + * that is created upon pool construction and expanded if (rarely) + * necessary. This is an array as opposed to some other data + * structure to support index-based random steals by workers. + * Updates to the array recording new workers and unrecording + * terminated ones are protected from each other by a seqLock + * (scanGuard) but the array is otherwise concurrently readable, + * and accessed directly by workers. To simplify index-based + * operations, the array size is always a power of two, and all + * readers must tolerate null slots. To avoid flailing during + * start-up, the array is presized to hold twice #parallelism + * workers (which is unlikely to need further resizing during + * execution). But to avoid dealing with so many null slots, + * variable scanGuard includes a mask for the nearest power of two + * that contains all current workers. All worker thread creation + * is on-demand, triggered by task submissions, replacement of + * terminated workers, and/or compensation for blocked + * workers. However, all other support code is set up to work with + * other policies. To ensure that we do not hold on to worker + * references that would prevent GC, ALL accesses to workers are + * via indices into the workers array (which is one source of some + * of the messy code constructions here). In essence, the workers + * array serves as a weak reference mechanism. Thus for example + * the wait queue field of ctl stores worker indices, not worker + * references. Access to the workers in associated methods (for + * example signalWork) must both index-check and null-check the + * IDs. All such accesses ignore bad IDs by returning out early + * from what they are doing, since this can only be associated + * with termination, in which case it is OK to give up. + * + * All uses of the workers array, as well as queue arrays, check + * that the array is non-null (even if previously non-null). This + * allows nulling during termination, which is currently not + * necessary, but remains an option for resource-revocation-based + * shutdown schemes. + * + * Wait Queuing. Unlike HPC work-stealing frameworks, we cannot + * let workers spin indefinitely scanning for tasks when none can + * be found immediately, and we cannot start/resume workers unless + * there appear to be tasks available. On the other hand, we must + * quickly prod them into action when new tasks are submitted or + * generated. We park/unpark workers after placing in an event + * wait queue when they cannot find work. This "queue" is actually + * a simple Treiber stack, headed by the "id" field of ctl, plus a + * 15bit counter value to both wake up waiters (by advancing their + * count) and avoid ABA effects. Successors are held in worker + * field "nextWait". Queuing deals with several intrinsic races, + * mainly that a task-producing thread can miss seeing (and + * signalling) another thread that gave up looking for work but + * has not yet entered the wait queue. We solve this by requiring + * a full sweep of all workers both before (in scan()) and after + * (in tryAwaitWork()) a newly waiting worker is added to the wait + * queue. During a rescan, the worker might release some other + * queued worker rather than itself, which has the same net + * effect. Because enqueued workers may actually be rescanning + * rather than waiting, we set and clear the "parked" field of + * ForkJoinWorkerThread to reduce unnecessary calls to unpark. + * (Use of the parked field requires a secondary recheck to avoid + * missed signals.) + * + * Signalling. We create or wake up workers only when there + * appears to be at least one task they might be able to find and + * execute. When a submission is added or another worker adds a + * task to a queue that previously had two or fewer tasks, they + * signal waiting workers (or trigger creation of new ones if + * fewer than the given parallelism level -- see signalWork). + * These primary signals are buttressed by signals during rescans + * as well as those performed when a worker steals a task and + * notices that there are more tasks too; together these cover the + * signals needed in cases when more than two tasks are pushed + * but untaken. + * + * Trimming workers. To release resources after periods of lack of + * use, a worker starting to wait when the pool is quiescent will + * time out and terminate if the pool has remained quiescent for + * SHRINK_RATE nanosecs. This will slowly propagate, eventually + * terminating all workers after long periods of non-use. + * + * Submissions. External submissions are maintained in an + * array-based queue that is structured identically to + * ForkJoinWorkerThread queues except for the use of + * submissionLock in method addSubmission. Unlike the case for + * worker queues, multiple external threads can add new + * submissions, so adding requires a lock. + * + * Compensation. Beyond work-stealing support and lifecycle + * control, the main responsibility of this framework is to take + * actions when one worker is waiting to join a task stolen (or + * always held by) another. Because we are multiplexing many + * tasks on to a pool of workers, we can't just let them block (as + * in Thread.join). We also cannot just reassign the joiner's + * run-time stack with another and replace it later, which would + * be a form of "continuation", that even if possible is not + * necessarily a good idea since we sometimes need both an + * unblocked task and its continuation to progress. Instead we + * combine two tactics: + * + * Helping: Arranging for the joiner to execute some task that it + * would be running if the steal had not occurred. Method + * ForkJoinWorkerThread.joinTask tracks joining->stealing + * links to try to find such a task. + * + * Compensating: Unless there are already enough live threads, + * method tryPreBlock() may create or re-activate a spare + * thread to compensate for blocked joiners until they + * unblock. + * + * The ManagedBlocker extension API can't use helping so relies + * only on compensation in method awaitBlocker. + * + * It is impossible to keep exactly the target parallelism number + * of threads running at any given time. Determining the + * existence of conservatively safe helping targets, the + * availability of already-created spares, and the apparent need + * to create new spares are all racy and require heuristic + * guidance, so we rely on multiple retries of each. Currently, + * in keeping with on-demand signalling policy, we compensate only + * if blocking would leave less than one active (non-waiting, + * non-blocked) worker. Additionally, to avoid some false alarms + * due to GC, lagging counters, system activity, etc, compensated + * blocking for joins is only attempted after rechecks stabilize + * (retries are interspersed with Thread.yield, for good + * citizenship). The variable blockedCount, incremented before + * blocking and decremented after, is sometimes needed to + * distinguish cases of waiting for work vs blocking on joins or + * other managed sync. Both cases are equivalent for most pool + * control, so we can update non-atomically. (Additionally, + * contention on blockedCount alleviates some contention on ctl). + * + * Shutdown and Termination. A call to shutdownNow atomically sets + * the ctl stop bit and then (non-atomically) sets each workers + * "terminate" status, cancels all unprocessed tasks, and wakes up + * all waiting workers. Detecting whether termination should + * commence after a non-abrupt shutdown() call requires more work + * and bookkeeping. We need consensus about quiesence (i.e., that + * there is no more work) which is reflected in active counts so + * long as there are no current blockers, as well as possible + * re-evaluations during independent changes in blocking or + * quiescing workers. + * + * Style notes: There is a lot of representation-level coupling + * among classes ForkJoinPool, ForkJoinWorkerThread, and + * ForkJoinTask. Most fields of ForkJoinWorkerThread maintain + * data structures managed by ForkJoinPool, so are directly + * accessed. Conversely we allow access to "workers" array by + * workers, and direct access to ForkJoinTask.status by both + * ForkJoinPool and ForkJoinWorkerThread. There is little point + * trying to reduce this, since any associated future changes in + * representations will need to be accompanied by algorithmic + * changes anyway. All together, these low-level implementation + * choices produce as much as a factor of 4 performance + * improvement compared to naive implementations, and enable the + * processing of billions of tasks per second, at the expense of + * some ugliness. + * + * Methods signalWork() and scan() are the main bottlenecks so are + * especially heavily micro-optimized/mangled. There are lots of + * inline assignments (of form "while ((local = field) != 0)") + * which are usually the simplest way to ensure the required read + * orderings (which are sometimes critical). This leads to a + * "C"-like style of listing declarations of these locals at the + * heads of methods or blocks. There are several occurrences of + * the unusual "do {} while (!cas...)" which is the simplest way + * to force an update of a CAS'ed variable. There are also other + * coding oddities that help some methods perform reasonably even + * when interpreted (not compiled). + * + * The order of declarations in this file is: (1) declarations of + * statics (2) fields (along with constants used when unpacking + * some of them), listed in an order that tends to reduce + * contention among them a bit under most JVMs. (3) internal + * control methods (4) callbacks and other support for + * ForkJoinTask and ForkJoinWorkerThread classes, (5) exported + * methods (plus a few little helpers). (6) static block + * initializing all statics in a minimally dependent order. + */ + + /** + * Factory for creating new {@link ForkJoinWorkerThread}s. + * A {@code ForkJoinWorkerThreadFactory} must be defined and used + * for {@code ForkJoinWorkerThread} subclasses that extend base + * functionality or initialize threads with different contexts. + */ + public static interface ForkJoinWorkerThreadFactory { + /** + * Returns a new worker thread operating in the given pool. + * + * @param pool the pool this thread works in + * @throws NullPointerException if the pool is null + */ + public ForkJoinWorkerThread newThread(ForkJoinPool pool); + } + + /** + * Default ForkJoinWorkerThreadFactory implementation; creates a + * new ForkJoinWorkerThread. + */ + static class DefaultForkJoinWorkerThreadFactory + implements ForkJoinWorkerThreadFactory { + public ForkJoinWorkerThread newThread(ForkJoinPool pool) { + return new ForkJoinWorkerThread(pool); + } + } + + /** + * Creates a new ForkJoinWorkerThread. This factory is used unless + * overridden in ForkJoinPool constructors. + */ + public static final ForkJoinWorkerThreadFactory + defaultForkJoinWorkerThreadFactory; + + /** + * Permission required for callers of methods that may start or + * kill threads. + */ + private static final RuntimePermission modifyThreadPermission; + + /** + * If there is a security manager, makes sure caller has + * permission to modify threads. + */ + private static void checkPermission() { + SecurityManager security = System.getSecurityManager(); + if (security != null) + security.checkPermission(modifyThreadPermission); + } + + /** + * Generator for assigning sequence numbers as pool names. + */ + private static final AtomicInteger poolNumberGenerator; + + /** + * Generator for initial random seeds for worker victim + * selection. This is used only to create initial seeds. Random + * steals use a cheaper xorshift generator per steal attempt. We + * don't expect much contention on seedGenerator, so just use a + * plain Random. + */ + static final Random workerSeedGenerator; + + /** + * Array holding all worker threads in the pool. Initialized upon + * construction. Array size must be a power of two. Updates and + * replacements are protected by scanGuard, but the array is + * always kept in a consistent enough state to be randomly + * accessed without locking by workers performing work-stealing, + * as well as other traversal-based methods in this class, so long + * as reads memory-acquire by first reading ctl. All readers must + * tolerate that some array slots may be null. + */ + ForkJoinWorkerThread[] workers; + + /** + * Initial size for submission queue array. Must be a power of + * two. In many applications, these always stay small so we use a + * small initial cap. + */ + private static final int INITIAL_QUEUE_CAPACITY = 8; + + /** + * Maximum size for submission queue array. Must be a power of two + * less than or equal to 1 << (31 - width of array entry) to + * ensure lack of index wraparound, but is capped at a lower + * value to help users trap runaway computations. + */ + private static final int MAXIMUM_QUEUE_CAPACITY = 1 << 24; // 16M + + /** + * Array serving as submission queue. Initialized upon construction. + */ + private ForkJoinTask[] submissionQueue; + + /** + * Lock protecting submissions array for addSubmission + */ + private final ReentrantLock submissionLock; + + /** + * Condition for awaitTermination, using submissionLock for + * convenience. + */ + private final Condition termination; + + /** + * Creation factory for worker threads. + */ + private final ForkJoinWorkerThreadFactory factory; + + /** + * The uncaught exception handler used when any worker abruptly + * terminates. + */ + final Thread.UncaughtExceptionHandler ueh; + + /** + * Prefix for assigning names to worker threads + */ + private final String workerNamePrefix; + + /** + * Sum of per-thread steal counts, updated only when threads are + * idle or terminating. + */ + private volatile long stealCount; + + /** + * Main pool control -- a long packed with: + * AC: Number of active running workers minus target parallelism (16 bits) + * TC: Number of total workers minus target parallelism (16bits) + * ST: true if pool is terminating (1 bit) + * EC: the wait count of top waiting thread (15 bits) + * ID: ~poolIndex of top of Treiber stack of waiting threads (16 bits) + * + * When convenient, we can extract the upper 32 bits of counts and + * the lower 32 bits of queue state, u = (int)(ctl >>> 32) and e = + * (int)ctl. The ec field is never accessed alone, but always + * together with id and st. The offsets of counts by the target + * parallelism and the positionings of fields makes it possible to + * perform the most common checks via sign tests of fields: When + * ac is negative, there are not enough active workers, when tc is + * negative, there are not enough total workers, when id is + * negative, there is at least one waiting worker, and when e is + * negative, the pool is terminating. To deal with these possibly + * negative fields, we use casts in and out of "short" and/or + * signed shifts to maintain signedness. + */ + volatile long ctl; + + // bit positions/shifts for fields + private static final int AC_SHIFT = 48; + private static final int TC_SHIFT = 32; + private static final int ST_SHIFT = 31; + private static final int EC_SHIFT = 16; + + // bounds + private static final int MAX_ID = 0x7fff; // max poolIndex + private static final int SMASK = 0xffff; // mask short bits + private static final int SHORT_SIGN = 1 << 15; + private static final int INT_SIGN = 1 << 31; + + // masks + private static final long STOP_BIT = 0x0001L << ST_SHIFT; + private static final long AC_MASK = ((long)SMASK) << AC_SHIFT; + private static final long TC_MASK = ((long)SMASK) << TC_SHIFT; + + // units for incrementing and decrementing + private static final long TC_UNIT = 1L << TC_SHIFT; + private static final long AC_UNIT = 1L << AC_SHIFT; + + // masks and units for dealing with u = (int)(ctl >>> 32) + private static final int UAC_SHIFT = AC_SHIFT - 32; + private static final int UTC_SHIFT = TC_SHIFT - 32; + private static final int UAC_MASK = SMASK << UAC_SHIFT; + private static final int UTC_MASK = SMASK << UTC_SHIFT; + private static final int UAC_UNIT = 1 << UAC_SHIFT; + private static final int UTC_UNIT = 1 << UTC_SHIFT; + + // masks and units for dealing with e = (int)ctl + private static final int E_MASK = 0x7fffffff; // no STOP_BIT + private static final int EC_UNIT = 1 << EC_SHIFT; + + /** + * The target parallelism level. + */ + final int parallelism; + + /** + * Index (mod submission queue length) of next element to take + * from submission queue. Usage is identical to that for + * per-worker queues -- see ForkJoinWorkerThread internal + * documentation. + */ + volatile int queueBase; + + /** + * Index (mod submission queue length) of next element to add + * in submission queue. Usage is identical to that for + * per-worker queues -- see ForkJoinWorkerThread internal + * documentation. + */ + int queueTop; + + /** + * True when shutdown() has been called. + */ + volatile boolean shutdown; + + /** + * True if use local fifo, not default lifo, for local polling + * Read by, and replicated by ForkJoinWorkerThreads + */ + final boolean locallyFifo; + + /** + * The number of threads in ForkJoinWorkerThreads.helpQuiescePool. + * When non-zero, suppresses automatic shutdown when active + * counts become zero. + */ + volatile int quiescerCount; + + /** + * The number of threads blocked in join. + */ + volatile int blockedCount; + + /** + * Counter for worker Thread names (unrelated to their poolIndex) + */ + private volatile int nextWorkerNumber; + + /** + * The index for the next created worker. Accessed under scanGuard. + */ + private int nextWorkerIndex; + + /** + * SeqLock and index masking for updates to workers array. Locked + * when SG_UNIT is set. Unlocking clears bit by adding + * SG_UNIT. Staleness of read-only operations can be checked by + * comparing scanGuard to value before the reads. The low 16 bits + * (i.e, anding with SMASK) hold (the smallest power of two + * covering all worker indices, minus one, and is used to avoid + * dealing with large numbers of null slots when the workers array + * is overallocated. + */ + volatile int scanGuard; + + private static final int SG_UNIT = 1 << 16; + + /** + * The wakeup interval (in nanoseconds) for a worker waiting for a + * task when the pool is quiescent to instead try to shrink the + * number of workers. The exact value does not matter too + * much. It must be short enough to release resources during + * sustained periods of idleness, but not so short that threads + * are continually re-created. + */ + private static final long SHRINK_RATE = + 4L * 1000L * 1000L * 1000L; // 4 seconds + + /** + * Top-level loop for worker threads: On each step: if the + * previous step swept through all queues and found no tasks, or + * there are excess threads, then possibly blocks. Otherwise, + * scans for and, if found, executes a task. Returns when pool + * and/or worker terminate. + * + * @param w the worker + */ + final void work(ForkJoinWorkerThread w) { + boolean swept = false; // true on empty scans + long c; + while (!w.terminate && (int)(c = ctl) >= 0) { + int a; // active count + if (!swept && (a = (int)(c >> AC_SHIFT)) <= 0) + swept = scan(w, a); + else if (tryAwaitWork(w, c)) + swept = false; + } + } + + // Signalling + + /** + * Wakes up or creates a worker. + */ + final void signalWork() { + /* + * The while condition is true if: (there is are too few total + * workers OR there is at least one waiter) AND (there are too + * few active workers OR the pool is terminating). The value + * of e distinguishes the remaining cases: zero (no waiters) + * for create, negative if terminating (in which case do + * nothing), else release a waiter. The secondary checks for + * release (non-null array etc) can fail if the pool begins + * terminating after the test, and don't impose any added cost + * because JVMs must perform null and bounds checks anyway. + */ + long c; int e, u; + while ((((e = (int)(c = ctl)) | (u = (int)(c >>> 32))) & + (INT_SIGN|SHORT_SIGN)) == (INT_SIGN|SHORT_SIGN) && e >= 0) { + if (e > 0) { // release a waiting worker + int i; ForkJoinWorkerThread w; ForkJoinWorkerThread[] ws; + if ((ws = workers) == null || + (i = ~e & SMASK) >= ws.length || + (w = ws[i]) == null) + break; + long nc = (((long)(w.nextWait & E_MASK)) | + ((long)(u + UAC_UNIT) << 32)); + if (w.eventCount == e && + UNSAFE.compareAndSwapLong(this, ctlOffset, c, nc)) { + w.eventCount = (e + EC_UNIT) & E_MASK; + if (w.parked) + UNSAFE.unpark(w); + break; + } + } + else if (UNSAFE.compareAndSwapLong + (this, ctlOffset, c, + (long)(((u + UTC_UNIT) & UTC_MASK) | + ((u + UAC_UNIT) & UAC_MASK)) << 32)) { + addWorker(); + break; + } + } + } + + /** + * Variant of signalWork to help release waiters on rescans. + * Tries once to release a waiter if active count < 0. + * + * @return false if failed due to contention, else true + */ + private boolean tryReleaseWaiter() { + long c; int e, i; ForkJoinWorkerThread w; ForkJoinWorkerThread[] ws; + if ((e = (int)(c = ctl)) > 0 && + (int)(c >> AC_SHIFT) < 0 && + (ws = workers) != null && + (i = ~e & SMASK) < ws.length && + (w = ws[i]) != null) { + long nc = ((long)(w.nextWait & E_MASK) | + ((c + AC_UNIT) & (AC_MASK|TC_MASK))); + if (w.eventCount != e || + !UNSAFE.compareAndSwapLong(this, ctlOffset, c, nc)) + return false; + w.eventCount = (e + EC_UNIT) & E_MASK; + if (w.parked) + UNSAFE.unpark(w); + } + return true; + } + + // Scanning for tasks + + /** + * Scans for and, if found, executes one task. Scans start at a + * random index of workers array, and randomly select the first + * (2*#workers)-1 probes, and then, if all empty, resort to 2 + * circular sweeps, which is necessary to check quiescence. and + * taking a submission only if no stealable tasks were found. The + * steal code inside the loop is a specialized form of + * ForkJoinWorkerThread.deqTask, followed bookkeeping to support + * helpJoinTask and signal propagation. The code for submission + * queues is almost identical. On each steal, the worker completes + * not only the task, but also all local tasks that this task may + * have generated. On detecting staleness or contention when + * trying to take a task, this method returns without finishing + * sweep, which allows global state rechecks before retry. + * + * @param w the worker + * @param a the number of active workers + * @return true if swept all queues without finding a task + */ + private boolean scan(ForkJoinWorkerThread w, int a) { + int g = scanGuard; // mask 0 avoids useless scans if only one active + int m = (parallelism == 1 - a && blockedCount == 0) ? 0 : g & SMASK; + ForkJoinWorkerThread[] ws = workers; + if (ws == null || ws.length <= m) // staleness check + return false; + for (int r = w.seed, k = r, j = -(m + m); j <= m + m; ++j) { + ForkJoinTask t; ForkJoinTask[] q; int b, i; + ForkJoinWorkerThread v = ws[k & m]; + if (v != null && (b = v.queueBase) != v.queueTop && + (q = v.queue) != null && (i = (q.length - 1) & b) >= 0) { + long u = (i << ASHIFT) + ABASE; + if ((t = q[i]) != null && v.queueBase == b && + UNSAFE.compareAndSwapObject(q, u, t, null)) { + int d = (v.queueBase = b + 1) - v.queueTop; + v.stealHint = w.poolIndex; + if (d != 0) + signalWork(); // propagate if nonempty + w.execTask(t); + } + r ^= r << 13; r ^= r >>> 17; w.seed = r ^ (r << 5); + return false; // store next seed + } + else if (j < 0) { // xorshift + r ^= r << 13; r ^= r >>> 17; k = r ^= r << 5; + } + else + ++k; + } + if (scanGuard != g) // staleness check + return false; + else { // try to take submission + ForkJoinTask t; ForkJoinTask[] q; int b, i; + if ((b = queueBase) != queueTop && + (q = submissionQueue) != null && + (i = (q.length - 1) & b) >= 0) { + long u = (i << ASHIFT) + ABASE; + if ((t = q[i]) != null && queueBase == b && + UNSAFE.compareAndSwapObject(q, u, t, null)) { + queueBase = b + 1; + w.execTask(t); + } + return false; + } + return true; // all queues empty + } + } + + /** + * Tries to enqueue worker w in wait queue and await change in + * worker's eventCount. If the pool is quiescent and there is + * more than one worker, possibly terminates worker upon exit. + * Otherwise, before blocking, rescans queues to avoid missed + * signals. Upon finding work, releases at least one worker + * (which may be the current worker). Rescans restart upon + * detected staleness or failure to release due to + * contention. Note the unusual conventions about Thread.interrupt + * here and elsewhere: Because interrupts are used solely to alert + * threads to check termination, which is checked here anyway, we + * clear status (using Thread.interrupted) before any call to + * park, so that park does not immediately return due to status + * being set via some other unrelated call to interrupt in user + * code. + * + * @param w the calling worker + * @param c the ctl value on entry + * @return true if waited or another thread was released upon enq + */ + private boolean tryAwaitWork(ForkJoinWorkerThread w, long c) { + int v = w.eventCount; + w.nextWait = (int)c; // w's successor record + long nc = (long)(v & E_MASK) | ((c - AC_UNIT) & (AC_MASK|TC_MASK)); + if (ctl != c || !UNSAFE.compareAndSwapLong(this, ctlOffset, c, nc)) { + long d = ctl; // return true if lost to a deq, to force scan + return (int)d != (int)c && ((d - c) & AC_MASK) >= 0L; + } + for (int sc = w.stealCount; sc != 0;) { // accumulate stealCount + long s = stealCount; + if (UNSAFE.compareAndSwapLong(this, stealCountOffset, s, s + sc)) + sc = w.stealCount = 0; + else if (w.eventCount != v) + return true; // update next time + } + if ((!shutdown || !tryTerminate(false)) && + (int)c != 0 && parallelism + (int)(nc >> AC_SHIFT) == 0 && + blockedCount == 0 && quiescerCount == 0) + idleAwaitWork(w, nc, c, v); // quiescent + for (boolean rescanned = false;;) { + if (w.eventCount != v) + return true; + if (!rescanned) { + int g = scanGuard, m = g & SMASK; + ForkJoinWorkerThread[] ws = workers; + if (ws != null && m < ws.length) { + rescanned = true; + for (int i = 0; i <= m; ++i) { + ForkJoinWorkerThread u = ws[i]; + if (u != null) { + if (u.queueBase != u.queueTop && + !tryReleaseWaiter()) + rescanned = false; // contended + if (w.eventCount != v) + return true; + } + } + } + if (scanGuard != g || // stale + (queueBase != queueTop && !tryReleaseWaiter())) + rescanned = false; + if (!rescanned) + Thread.yield(); // reduce contention + else + Thread.interrupted(); // clear before park + } + else { + w.parked = true; // must recheck + if (w.eventCount != v) { + w.parked = false; + return true; + } + LockSupport.park(this); + rescanned = w.parked = false; + } + } + } + + /** + * If inactivating worker w has caused pool to become + * quiescent, check for pool termination, and wait for event + * for up to SHRINK_RATE nanosecs (rescans are unnecessary in + * this case because quiescence reflects consensus about lack + * of work). On timeout, if ctl has not changed, terminate the + * worker. Upon its termination (see deregisterWorker), it may + * wake up another worker to possibly repeat this process. + * + * @param w the calling worker + * @param currentCtl the ctl value after enqueuing w + * @param prevCtl the ctl value if w terminated + * @param v the eventCount w awaits change + */ + private void idleAwaitWork(ForkJoinWorkerThread w, long currentCtl, + long prevCtl, int v) { + if (w.eventCount == v) { + if (shutdown) + tryTerminate(false); + ForkJoinTask.helpExpungeStaleExceptions(); // help clean weak refs + while (ctl == currentCtl) { + long startTime = System.nanoTime(); + w.parked = true; + if (w.eventCount == v) // must recheck + LockSupport.parkNanos(this, SHRINK_RATE); + w.parked = false; + if (w.eventCount != v) + break; + else if (System.nanoTime() - startTime < + SHRINK_RATE - (SHRINK_RATE / 10)) // timing slop + Thread.interrupted(); // spurious wakeup + else if (UNSAFE.compareAndSwapLong(this, ctlOffset, + currentCtl, prevCtl)) { + w.terminate = true; // restore previous + w.eventCount = ((int)currentCtl + EC_UNIT) & E_MASK; + break; + } + } + } + } + + // Submissions + + /** + * Enqueues the given task in the submissionQueue. Same idea as + * ForkJoinWorkerThread.pushTask except for use of submissionLock. + * + * @param t the task + */ + private void addSubmission(ForkJoinTask t) { + final ReentrantLock lock = this.submissionLock; + lock.lock(); + try { + ForkJoinTask[] q; int s, m; + if ((q = submissionQueue) != null) { // ignore if queue removed + long u = (((s = queueTop) & (m = q.length-1)) << ASHIFT)+ABASE; + UNSAFE.putOrderedObject(q, u, t); + queueTop = s + 1; + if (s - queueBase == m) + growSubmissionQueue(); + } + } finally { + lock.unlock(); + } + signalWork(); + } + + // (pollSubmission is defined below with exported methods) + + /** + * Creates or doubles submissionQueue array. + * Basically identical to ForkJoinWorkerThread version. + */ + private void growSubmissionQueue() { + ForkJoinTask[] oldQ = submissionQueue; + int size = oldQ != null ? oldQ.length << 1 : INITIAL_QUEUE_CAPACITY; + if (size > MAXIMUM_QUEUE_CAPACITY) + throw new RejectedExecutionException("Queue capacity exceeded"); + if (size < INITIAL_QUEUE_CAPACITY) + size = INITIAL_QUEUE_CAPACITY; + ForkJoinTask[] q = submissionQueue = new ForkJoinTask[size]; + int mask = size - 1; + int top = queueTop; + int oldMask; + if (oldQ != null && (oldMask = oldQ.length - 1) >= 0) { + for (int b = queueBase; b != top; ++b) { + long u = ((b & oldMask) << ASHIFT) + ABASE; + Object x = UNSAFE.getObjectVolatile(oldQ, u); + if (x != null && UNSAFE.compareAndSwapObject(oldQ, u, x, null)) + UNSAFE.putObjectVolatile + (q, ((b & mask) << ASHIFT) + ABASE, x); + } + } + } + + // Blocking support + + /** + * Tries to increment blockedCount, decrement active count + * (sometimes implicitly) and possibly release or create a + * compensating worker in preparation for blocking. Fails + * on contention or termination. + * + * @return true if the caller can block, else should recheck and retry + */ + private boolean tryPreBlock() { + int b = blockedCount; + if (UNSAFE.compareAndSwapInt(this, blockedCountOffset, b, b + 1)) { + int pc = parallelism; + do { + ForkJoinWorkerThread[] ws; ForkJoinWorkerThread w; + int e, ac, tc, rc, i; + long c = ctl; + int u = (int)(c >>> 32); + if ((e = (int)c) < 0) { + // skip -- terminating + } + else if ((ac = (u >> UAC_SHIFT)) <= 0 && e != 0 && + (ws = workers) != null && + (i = ~e & SMASK) < ws.length && + (w = ws[i]) != null) { + long nc = ((long)(w.nextWait & E_MASK) | + (c & (AC_MASK|TC_MASK))); + if (w.eventCount == e && + UNSAFE.compareAndSwapLong(this, ctlOffset, c, nc)) { + w.eventCount = (e + EC_UNIT) & E_MASK; + if (w.parked) + UNSAFE.unpark(w); + return true; // release an idle worker + } + } + else if ((tc = (short)(u >>> UTC_SHIFT)) >= 0 && ac + pc > 1) { + long nc = ((c - AC_UNIT) & AC_MASK) | (c & ~AC_MASK); + if (UNSAFE.compareAndSwapLong(this, ctlOffset, c, nc)) + return true; // no compensation needed + } + else if (tc + pc < MAX_ID) { + long nc = ((c + TC_UNIT) & TC_MASK) | (c & ~TC_MASK); + if (UNSAFE.compareAndSwapLong(this, ctlOffset, c, nc)) { + addWorker(); + return true; // create a replacement + } + } + // try to back out on any failure and let caller retry + } while (!UNSAFE.compareAndSwapInt(this, blockedCountOffset, + b = blockedCount, b - 1)); + } + return false; + } + + /** + * Decrements blockedCount and increments active count + */ + private void postBlock() { + long c; + do {} while (!UNSAFE.compareAndSwapLong(this, ctlOffset, // no mask + c = ctl, c + AC_UNIT)); + int b; + do {} while (!UNSAFE.compareAndSwapInt(this, blockedCountOffset, + b = blockedCount, b - 1)); + } + + /** + * Possibly blocks waiting for the given task to complete, or + * cancels the task if terminating. Fails to wait if contended. + * + * @param joinMe the task + */ + final void tryAwaitJoin(ForkJoinTask joinMe) { + int s; + Thread.interrupted(); // clear interrupts before checking termination + if (joinMe.status >= 0) { + if (tryPreBlock()) { + joinMe.tryAwaitDone(0L); + postBlock(); + } + else if ((ctl & STOP_BIT) != 0L) + joinMe.cancelIgnoringExceptions(); + } + } + + /** + * Possibly blocks the given worker waiting for joinMe to + * complete or timeout + * + * @param joinMe the task + * @param millis the wait time for underlying Object.wait + */ + final void timedAwaitJoin(ForkJoinTask joinMe, long nanos) { + while (joinMe.status >= 0) { + Thread.interrupted(); + if ((ctl & STOP_BIT) != 0L) { + joinMe.cancelIgnoringExceptions(); + break; + } + if (tryPreBlock()) { + long last = System.nanoTime(); + while (joinMe.status >= 0) { + long millis = TimeUnit.NANOSECONDS.toMillis(nanos); + if (millis <= 0) + break; + joinMe.tryAwaitDone(millis); + if (joinMe.status < 0) + break; + if ((ctl & STOP_BIT) != 0L) { + joinMe.cancelIgnoringExceptions(); + break; + } + long now = System.nanoTime(); + nanos -= now - last; + last = now; + } + postBlock(); + break; + } + } + } + + /** + * If necessary, compensates for blocker, and blocks + */ + private void awaitBlocker(ManagedBlocker blocker) + throws InterruptedException { + while (!blocker.isReleasable()) { + if (tryPreBlock()) { + try { + do {} while (!blocker.isReleasable() && !blocker.block()); + } finally { + postBlock(); + } + break; + } + } + } + + // Creating, registering and deregistring workers + + /** + * Tries to create and start a worker; minimally rolls back counts + * on failure. + */ + private void addWorker() { + Throwable ex = null; + ForkJoinWorkerThread t = null; + try { + t = factory.newThread(this); + } catch (Throwable e) { + ex = e; + } + if (t == null) { // null or exceptional factory return + long c; // adjust counts + do {} while (!UNSAFE.compareAndSwapLong + (this, ctlOffset, c = ctl, + (((c - AC_UNIT) & AC_MASK) | + ((c - TC_UNIT) & TC_MASK) | + (c & ~(AC_MASK|TC_MASK))))); + // Propagate exception if originating from an external caller + if (!tryTerminate(false) && ex != null && + !(Thread.currentThread() instanceof ForkJoinWorkerThread)) + UNSAFE.throwException(ex); + } + else + t.start(); + } + + /** + * Callback from ForkJoinWorkerThread constructor to assign a + * public name + */ + final String nextWorkerName() { + for (int n;;) { + if (UNSAFE.compareAndSwapInt(this, nextWorkerNumberOffset, + n = nextWorkerNumber, ++n)) + return workerNamePrefix + n; + } + } + + /** + * Callback from ForkJoinWorkerThread constructor to + * determine its poolIndex and record in workers array. + * + * @param w the worker + * @return the worker's pool index + */ + final int registerWorker(ForkJoinWorkerThread w) { + /* + * In the typical case, a new worker acquires the lock, uses + * next available index and returns quickly. Since we should + * not block callers (ultimately from signalWork or + * tryPreBlock) waiting for the lock needed to do this, we + * instead help release other workers while waiting for the + * lock. + */ + for (int g;;) { + ForkJoinWorkerThread[] ws; + if (((g = scanGuard) & SG_UNIT) == 0 && + UNSAFE.compareAndSwapInt(this, scanGuardOffset, + g, g | SG_UNIT)) { + int k = nextWorkerIndex; + try { + if ((ws = workers) != null) { // ignore on shutdown + int n = ws.length; + if (k < 0 || k >= n || ws[k] != null) { + for (k = 0; k < n && ws[k] != null; ++k) + ; + if (k == n) + ws = workers = Arrays.copyOf(ws, n << 1); + } + ws[k] = w; + nextWorkerIndex = k + 1; + int m = g & SMASK; + g = (k > m) ? ((m << 1) + 1) & SMASK : g + (SG_UNIT<<1); + } + } finally { + scanGuard = g; + } + return k; + } + else if ((ws = workers) != null) { // help release others + for (ForkJoinWorkerThread u : ws) { + if (u != null && u.queueBase != u.queueTop) { + if (tryReleaseWaiter()) + break; + } + } + } + } + } + + /** + * Final callback from terminating worker. Removes record of + * worker from array, and adjusts counts. If pool is shutting + * down, tries to complete termination. + * + * @param w the worker + */ + final void deregisterWorker(ForkJoinWorkerThread w, Throwable ex) { + int idx = w.poolIndex; + int sc = w.stealCount; + int steps = 0; + // Remove from array, adjust worker counts and collect steal count. + // We can intermix failed removes or adjusts with steal updates + do { + long s, c; + int g; + if (steps == 0 && ((g = scanGuard) & SG_UNIT) == 0 && + UNSAFE.compareAndSwapInt(this, scanGuardOffset, + g, g |= SG_UNIT)) { + ForkJoinWorkerThread[] ws = workers; + if (ws != null && idx >= 0 && + idx < ws.length && ws[idx] == w) + ws[idx] = null; // verify + nextWorkerIndex = idx; + scanGuard = g + SG_UNIT; + steps = 1; + } + if (steps == 1 && + UNSAFE.compareAndSwapLong(this, ctlOffset, c = ctl, + (((c - AC_UNIT) & AC_MASK) | + ((c - TC_UNIT) & TC_MASK) | + (c & ~(AC_MASK|TC_MASK))))) + steps = 2; + if (sc != 0 && + UNSAFE.compareAndSwapLong(this, stealCountOffset, + s = stealCount, s + sc)) + sc = 0; + } while (steps != 2 || sc != 0); + if (!tryTerminate(false)) { + if (ex != null) // possibly replace if died abnormally + signalWork(); + else + tryReleaseWaiter(); + } + } + + // Shutdown and termination + + /** + * Possibly initiates and/or completes termination. + * + * @param now if true, unconditionally terminate, else only + * if shutdown and empty queue and no active workers + * @return true if now terminating or terminated + */ + private boolean tryTerminate(boolean now) { + long c; + while (((c = ctl) & STOP_BIT) == 0) { + if (!now) { + if ((int)(c >> AC_SHIFT) != -parallelism) + return false; + if (!shutdown || blockedCount != 0 || quiescerCount != 0 || + queueBase != queueTop) { + if (ctl == c) // staleness check + return false; + continue; + } + } + if (UNSAFE.compareAndSwapLong(this, ctlOffset, c, c | STOP_BIT)) + startTerminating(); + } + if ((short)(c >>> TC_SHIFT) == -parallelism) { // signal when 0 workers + final ReentrantLock lock = this.submissionLock; + lock.lock(); + try { + termination.signalAll(); + } finally { + lock.unlock(); + } + } + return true; + } + + /** + * Runs up to three passes through workers: (0) Setting + * termination status for each worker, followed by wakeups up to + * queued workers; (1) helping cancel tasks; (2) interrupting + * lagging threads (likely in external tasks, but possibly also + * blocked in joins). Each pass repeats previous steps because of + * potential lagging thread creation. + */ + private void startTerminating() { + cancelSubmissions(); + for (int pass = 0; pass < 3; ++pass) { + ForkJoinWorkerThread[] ws = workers; + if (ws != null) { + for (ForkJoinWorkerThread w : ws) { + if (w != null) { + w.terminate = true; + if (pass > 0) { + w.cancelTasks(); + if (pass > 1 && !w.isInterrupted()) { + try { + w.interrupt(); + } catch (SecurityException ignore) { + } + } + } + } + } + terminateWaiters(); + } + } + } + + /** + * Polls and cancels all submissions. Called only during termination. + */ + private void cancelSubmissions() { + while (queueBase != queueTop) { + ForkJoinTask task = pollSubmission(); + if (task != null) { + try { + task.cancel(false); + } catch (Throwable ignore) { + } + } + } + } + + /** + * Tries to set the termination status of waiting workers, and + * then wakes them up (after which they will terminate). + */ + private void terminateWaiters() { + ForkJoinWorkerThread[] ws = workers; + if (ws != null) { + ForkJoinWorkerThread w; long c; int i, e; + int n = ws.length; + while ((i = ~(e = (int)(c = ctl)) & SMASK) < n && + (w = ws[i]) != null && w.eventCount == (e & E_MASK)) { + if (UNSAFE.compareAndSwapLong(this, ctlOffset, c, + (long)(w.nextWait & E_MASK) | + ((c + AC_UNIT) & AC_MASK) | + (c & (TC_MASK|STOP_BIT)))) { + w.terminate = true; + w.eventCount = e + EC_UNIT; + if (w.parked) + UNSAFE.unpark(w); + } + } + } + } + + // misc ForkJoinWorkerThread support + + /** + * Increment or decrement quiescerCount. Needed only to prevent + * triggering shutdown if a worker is transiently inactive while + * checking quiescence. + * + * @param delta 1 for increment, -1 for decrement + */ + final void addQuiescerCount(int delta) { + int c; + do {} while (!UNSAFE.compareAndSwapInt(this, quiescerCountOffset, + c = quiescerCount, c + delta)); + } + + /** + * Directly increment or decrement active count without + * queuing. This method is used to transiently assert inactivation + * while checking quiescence. + * + * @param delta 1 for increment, -1 for decrement + */ + final void addActiveCount(int delta) { + long d = delta < 0 ? -AC_UNIT : AC_UNIT; + long c; + do {} while (!UNSAFE.compareAndSwapLong(this, ctlOffset, c = ctl, + ((c + d) & AC_MASK) | + (c & ~AC_MASK))); + } + + /** + * Returns the approximate (non-atomic) number of idle threads per + * active thread. + */ + final int idlePerActive() { + // Approximate at powers of two for small values, saturate past 4 + int p = parallelism; + int a = p + (int)(ctl >> AC_SHIFT); + return (a > (p >>>= 1) ? 0 : + a > (p >>>= 1) ? 1 : + a > (p >>>= 1) ? 2 : + a > (p >>>= 1) ? 4 : + 8); + } + + // Exported methods + + // Constructors + + /** + * Creates a {@code ForkJoinPool} with parallelism equal to {@link + * java.lang.Runtime#availableProcessors}, using the {@linkplain + * #defaultForkJoinWorkerThreadFactory default thread factory}, + * no UncaughtExceptionHandler, and non-async LIFO processing mode. + * + * @throws SecurityException if a security manager exists and + * the caller is not permitted to modify threads + * because it does not hold {@link + * java.lang.RuntimePermission}{@code ("modifyThread")} + */ + public ForkJoinPool() { + this(Runtime.getRuntime().availableProcessors(), + defaultForkJoinWorkerThreadFactory, null, false); + } + + /** + * Creates a {@code ForkJoinPool} with the indicated parallelism + * level, the {@linkplain + * #defaultForkJoinWorkerThreadFactory default thread factory}, + * no UncaughtExceptionHandler, and non-async LIFO processing mode. + * + * @param parallelism the parallelism level + * @throws IllegalArgumentException if parallelism less than or + * equal to zero, or greater than implementation limit + * @throws SecurityException if a security manager exists and + * the caller is not permitted to modify threads + * because it does not hold {@link + * java.lang.RuntimePermission}{@code ("modifyThread")} + */ + public ForkJoinPool(int parallelism) { + this(parallelism, defaultForkJoinWorkerThreadFactory, null, false); + } + + /** + * Creates a {@code ForkJoinPool} with the given parameters. + * + * @param parallelism the parallelism level. For default value, + * use {@link java.lang.Runtime#availableProcessors}. + * @param factory the factory for creating new threads. For default value, + * use {@link #defaultForkJoinWorkerThreadFactory}. + * @param handler the handler for internal worker threads that + * terminate due to unrecoverable errors encountered while executing + * tasks. For default value, use {@code null}. + * @param asyncMode if true, + * establishes local first-in-first-out scheduling mode for forked + * tasks that are never joined. This mode may be more appropriate + * than default locally stack-based mode in applications in which + * worker threads only process event-style asynchronous tasks. + * For default value, use {@code false}. + * @throws IllegalArgumentException if parallelism less than or + * equal to zero, or greater than implementation limit + * @throws NullPointerException if the factory is null + * @throws SecurityException if a security manager exists and + * the caller is not permitted to modify threads + * because it does not hold {@link + * java.lang.RuntimePermission}{@code ("modifyThread")} + */ + public ForkJoinPool(int parallelism, + ForkJoinWorkerThreadFactory factory, + Thread.UncaughtExceptionHandler handler, + boolean asyncMode) { + checkPermission(); + if (factory == null) + throw new NullPointerException(); + if (parallelism <= 0 || parallelism > MAX_ID) + throw new IllegalArgumentException(); + this.parallelism = parallelism; + this.factory = factory; + this.ueh = handler; + this.locallyFifo = asyncMode; + long np = (long)(-parallelism); // offset ctl counts + this.ctl = ((np << AC_SHIFT) & AC_MASK) | ((np << TC_SHIFT) & TC_MASK); + this.submissionQueue = new ForkJoinTask[INITIAL_QUEUE_CAPACITY]; + // initialize workers array with room for 2*parallelism if possible + int n = parallelism << 1; + if (n >= MAX_ID) + n = MAX_ID; + else { // See Hackers Delight, sec 3.2, where n < (1 << 16) + n |= n >>> 1; n |= n >>> 2; n |= n >>> 4; n |= n >>> 8; + } + workers = new ForkJoinWorkerThread[n + 1]; + this.submissionLock = new ReentrantLock(); + this.termination = submissionLock.newCondition(); + StringBuilder sb = new StringBuilder("ForkJoinPool-"); + sb.append(poolNumberGenerator.incrementAndGet()); + sb.append("-worker-"); + this.workerNamePrefix = sb.toString(); + } + + // Execution methods + + /** + * Performs the given task, returning its result upon completion. + * If the computation encounters an unchecked Exception or Error, + * it is rethrown as the outcome of this invocation. Rethrown + * exceptions behave in the same way as regular exceptions, but, + * when possible, contain stack traces (as displayed for example + * using {@code ex.printStackTrace()}) of both the current thread + * as well as the thread actually encountering the exception; + * minimally only the latter. + * + * @param task the task + * @return the task's result + * @throws NullPointerException if the task is null + * @throws RejectedExecutionException if the task cannot be + * scheduled for execution + */ + public T invoke(ForkJoinTask task) { + Thread t = Thread.currentThread(); + if (task == null) + throw new NullPointerException(); + if (shutdown) + throw new RejectedExecutionException(); + if ((t instanceof ForkJoinWorkerThread) && + ((ForkJoinWorkerThread)t).pool == this) + return task.invoke(); // bypass submit if in same pool + else { + addSubmission(task); + return task.join(); + } + } + + /** + * Unless terminating, forks task if within an ongoing FJ + * computation in the current pool, else submits as external task. + */ + private void forkOrSubmit(ForkJoinTask task) { + ForkJoinWorkerThread w; + Thread t = Thread.currentThread(); + if (shutdown) + throw new RejectedExecutionException(); + if ((t instanceof ForkJoinWorkerThread) && + (w = (ForkJoinWorkerThread)t).pool == this) + w.pushTask(task); + else + addSubmission(task); + } + + /** + * Arranges for (asynchronous) execution of the given task. + * + * @param task the task + * @throws NullPointerException if the task is null + * @throws RejectedExecutionException if the task cannot be + * scheduled for execution + */ + public void execute(ForkJoinTask task) { + if (task == null) + throw new NullPointerException(); + forkOrSubmit(task); + } + + // AbstractExecutorService methods + + /** + * @throws NullPointerException if the task is null + * @throws RejectedExecutionException if the task cannot be + * scheduled for execution + */ + public void execute(Runnable task) { + if (task == null) + throw new NullPointerException(); + ForkJoinTask job; + if (task instanceof ForkJoinTask) // avoid re-wrap + job = (ForkJoinTask) task; + else + job = ForkJoinTask.adapt(task, null); + forkOrSubmit(job); + } + + /** + * Submits a ForkJoinTask for execution. + * + * @param task the task to submit + * @return the task + * @throws NullPointerException if the task is null + * @throws RejectedExecutionException if the task cannot be + * scheduled for execution + */ + public ForkJoinTask submit(ForkJoinTask task) { + if (task == null) + throw new NullPointerException(); + forkOrSubmit(task); + return task; + } + + /** + * @throws NullPointerException if the task is null + * @throws RejectedExecutionException if the task cannot be + * scheduled for execution + */ + public ForkJoinTask submit(Callable task) { + if (task == null) + throw new NullPointerException(); + ForkJoinTask job = ForkJoinTask.adapt(task); + forkOrSubmit(job); + return job; + } + + /** + * @throws NullPointerException if the task is null + * @throws RejectedExecutionException if the task cannot be + * scheduled for execution + */ + public ForkJoinTask submit(Runnable task, T result) { + if (task == null) + throw new NullPointerException(); + ForkJoinTask job = ForkJoinTask.adapt(task, result); + forkOrSubmit(job); + return job; + } + + /** + * @throws NullPointerException if the task is null + * @throws RejectedExecutionException if the task cannot be + * scheduled for execution + */ + public ForkJoinTask submit(Runnable task) { + if (task == null) + throw new NullPointerException(); + ForkJoinTask job; + if (task instanceof ForkJoinTask) // avoid re-wrap + job = (ForkJoinTask) task; + else + job = ForkJoinTask.adapt(task, null); + forkOrSubmit(job); + return job; + } + + /** + * @throws NullPointerException {@inheritDoc} + * @throws RejectedExecutionException {@inheritDoc} + */ + public List> invokeAll(Collection> tasks) { + ArrayList> forkJoinTasks = + new ArrayList>(tasks.size()); + for (Callable task : tasks) + forkJoinTasks.add(ForkJoinTask.adapt(task)); + invoke(new InvokeAll(forkJoinTasks)); + + @SuppressWarnings({"unchecked", "rawtypes"}) + List> futures = (List>) (List) forkJoinTasks; + return futures; + } + + static final class InvokeAll extends RecursiveAction { + final ArrayList> tasks; + InvokeAll(ArrayList> tasks) { this.tasks = tasks; } + public void compute() { + try { invokeAll(tasks); } + catch (Exception ignore) {} + } + private static final long serialVersionUID = -7914297376763021607L; + } + + /** + * Returns the factory used for constructing new workers. + * + * @return the factory used for constructing new workers + */ + public ForkJoinWorkerThreadFactory getFactory() { + return factory; + } + + /** + * Returns the handler for internal worker threads that terminate + * due to unrecoverable errors encountered while executing tasks. + * + * @return the handler, or {@code null} if none + */ + public Thread.UncaughtExceptionHandler getUncaughtExceptionHandler() { + return ueh; + } + + /** + * Returns the targeted parallelism level of this pool. + * + * @return the targeted parallelism level of this pool + */ + public int getParallelism() { + return parallelism; + } + + /** + * Returns the number of worker threads that have started but not + * yet terminated. The result returned by this method may differ + * from {@link #getParallelism} when threads are created to + * maintain parallelism when others are cooperatively blocked. + * + * @return the number of worker threads + */ + public int getPoolSize() { + return parallelism + (short)(ctl >>> TC_SHIFT); + } + + /** + * Returns {@code true} if this pool uses local first-in-first-out + * scheduling mode for forked tasks that are never joined. + * + * @return {@code true} if this pool uses async mode + */ + public boolean getAsyncMode() { + return locallyFifo; + } + + /** + * Returns an estimate of the number of worker threads that are + * not blocked waiting to join tasks or for other managed + * synchronization. This method may overestimate the + * number of running threads. + * + * @return the number of worker threads + */ + public int getRunningThreadCount() { + int r = parallelism + (int)(ctl >> AC_SHIFT); + return (r <= 0) ? 0 : r; // suppress momentarily negative values + } + + /** + * Returns an estimate of the number of threads that are currently + * stealing or executing tasks. This method may overestimate the + * number of active threads. + * + * @return the number of active threads + */ + public int getActiveThreadCount() { + int r = parallelism + (int)(ctl >> AC_SHIFT) + blockedCount; + return (r <= 0) ? 0 : r; // suppress momentarily negative values + } + + /** + * Returns {@code true} if all worker threads are currently idle. + * An idle worker is one that cannot obtain a task to execute + * because none are available to steal from other threads, and + * there are no pending submissions to the pool. This method is + * conservative; it might not return {@code true} immediately upon + * idleness of all threads, but will eventually become true if + * threads remain inactive. + * + * @return {@code true} if all threads are currently idle + */ + public boolean isQuiescent() { + return parallelism + (int)(ctl >> AC_SHIFT) + blockedCount == 0; + } + + /** + * Returns an estimate of the total number of tasks stolen from + * one thread's work queue by another. The reported value + * underestimates the actual total number of steals when the pool + * is not quiescent. This value may be useful for monitoring and + * tuning fork/join programs: in general, steal counts should be + * high enough to keep threads busy, but low enough to avoid + * overhead and contention across threads. + * + * @return the number of steals + */ + public long getStealCount() { + return stealCount; + } + + /** + * Returns an estimate of the total number of tasks currently held + * in queues by worker threads (but not including tasks submitted + * to the pool that have not begun executing). This value is only + * an approximation, obtained by iterating across all threads in + * the pool. This method may be useful for tuning task + * granularities. + * + * @return the number of queued tasks + */ + public long getQueuedTaskCount() { + long count = 0; + ForkJoinWorkerThread[] ws; + if ((short)(ctl >>> TC_SHIFT) > -parallelism && + (ws = workers) != null) { + for (ForkJoinWorkerThread w : ws) + if (w != null) + count -= w.queueBase - w.queueTop; // must read base first + } + return count; + } + + /** + * Returns an estimate of the number of tasks submitted to this + * pool that have not yet begun executing. This method may take + * time proportional to the number of submissions. + * + * @return the number of queued submissions + */ + public int getQueuedSubmissionCount() { + return -queueBase + queueTop; + } + + /** + * Returns {@code true} if there are any tasks submitted to this + * pool that have not yet begun executing. + * + * @return {@code true} if there are any queued submissions + */ + public boolean hasQueuedSubmissions() { + return queueBase != queueTop; + } + + /** + * Removes and returns the next unexecuted submission if one is + * available. This method may be useful in extensions to this + * class that re-assign work in systems with multiple pools. + * + * @return the next submission, or {@code null} if none + */ + protected ForkJoinTask pollSubmission() { + ForkJoinTask t; ForkJoinTask[] q; int b, i; + while ((b = queueBase) != queueTop && + (q = submissionQueue) != null && + (i = (q.length - 1) & b) >= 0) { + long u = (i << ASHIFT) + ABASE; + if ((t = q[i]) != null && + queueBase == b && + UNSAFE.compareAndSwapObject(q, u, t, null)) { + queueBase = b + 1; + return t; + } + } + return null; + } + + /** + * Removes all available unexecuted submitted and forked tasks + * from scheduling queues and adds them to the given collection, + * without altering their execution status. These may include + * artificially generated or wrapped tasks. This method is + * designed to be invoked only when the pool is known to be + * quiescent. Invocations at other times may not remove all + * tasks. A failure encountered while attempting to add elements + * to collection {@code c} may result in elements being in + * neither, either or both collections when the associated + * exception is thrown. The behavior of this operation is + * undefined if the specified collection is modified while the + * operation is in progress. + * + * @param c the collection to transfer elements into + * @return the number of elements transferred + */ + protected int drainTasksTo(Collection> c) { + int count = 0; + while (queueBase != queueTop) { + ForkJoinTask t = pollSubmission(); + if (t != null) { + c.add(t); + ++count; + } + } + ForkJoinWorkerThread[] ws; + if ((short)(ctl >>> TC_SHIFT) > -parallelism && + (ws = workers) != null) { + for (ForkJoinWorkerThread w : ws) + if (w != null) + count += w.drainTasksTo(c); + } + return count; + } + + /** + * Returns a string identifying this pool, as well as its state, + * including indications of run state, parallelism level, and + * worker and task counts. + * + * @return a string identifying this pool, as well as its state + */ + public String toString() { + long st = getStealCount(); + long qt = getQueuedTaskCount(); + long qs = getQueuedSubmissionCount(); + int pc = parallelism; + long c = ctl; + int tc = pc + (short)(c >>> TC_SHIFT); + int rc = pc + (int)(c >> AC_SHIFT); + if (rc < 0) // ignore transient negative + rc = 0; + int ac = rc + blockedCount; + String level; + if ((c & STOP_BIT) != 0) + level = (tc == 0) ? "Terminated" : "Terminating"; + else + level = shutdown ? "Shutting down" : "Running"; + return super.toString() + + "[" + level + + ", parallelism = " + pc + + ", size = " + tc + + ", active = " + ac + + ", running = " + rc + + ", steals = " + st + + ", tasks = " + qt + + ", submissions = " + qs + + "]"; + } + + /** + * Initiates an orderly shutdown in which previously submitted + * tasks are executed, but no new tasks will be accepted. + * Invocation has no additional effect if already shut down. + * Tasks that are in the process of being submitted concurrently + * during the course of this method may or may not be rejected. + * + * @throws SecurityException if a security manager exists and + * the caller is not permitted to modify threads + * because it does not hold {@link + * java.lang.RuntimePermission}{@code ("modifyThread")} + */ + public void shutdown() { + checkPermission(); + shutdown = true; + tryTerminate(false); + } + + /** + * Attempts to cancel and/or stop all tasks, and reject all + * subsequently submitted tasks. Tasks that are in the process of + * being submitted or executed concurrently during the course of + * this method may or may not be rejected. This method cancels + * both existing and unexecuted tasks, in order to permit + * termination in the presence of task dependencies. So the method + * always returns an empty list (unlike the case for some other + * Executors). + * + * @return an empty list + * @throws SecurityException if a security manager exists and + * the caller is not permitted to modify threads + * because it does not hold {@link + * java.lang.RuntimePermission}{@code ("modifyThread")} + */ + public List shutdownNow() { + checkPermission(); + shutdown = true; + tryTerminate(true); + return Collections.emptyList(); + } + + /** + * Returns {@code true} if all tasks have completed following shut down. + * + * @return {@code true} if all tasks have completed following shut down + */ + public boolean isTerminated() { + long c = ctl; + return ((c & STOP_BIT) != 0L && + (short)(c >>> TC_SHIFT) == -parallelism); + } + + /** + * Returns {@code true} if the process of termination has + * commenced but not yet completed. This method may be useful for + * debugging. A return of {@code true} reported a sufficient + * period after shutdown may indicate that submitted tasks have + * ignored or suppressed interruption, or are waiting for IO, + * causing this executor not to properly terminate. (See the + * advisory notes for class {@link ForkJoinTask} stating that + * tasks should not normally entail blocking operations. But if + * they do, they must abort them on interrupt.) + * + * @return {@code true} if terminating but not yet terminated + */ + public boolean isTerminating() { + long c = ctl; + return ((c & STOP_BIT) != 0L && + (short)(c >>> TC_SHIFT) != -parallelism); + } + + /** + * Returns true if terminating or terminated. Used by ForkJoinWorkerThread. + */ + final boolean isAtLeastTerminating() { + return (ctl & STOP_BIT) != 0L; + } + + /** + * Returns {@code true} if this pool has been shut down. + * + * @return {@code true} if this pool has been shut down + */ + public boolean isShutdown() { + return shutdown; + } + + /** + * Blocks until all tasks have completed execution after a shutdown + * request, or the timeout occurs, or the current thread is + * interrupted, whichever happens first. + * + * @param timeout the maximum time to wait + * @param unit the time unit of the timeout argument + * @return {@code true} if this executor terminated and + * {@code false} if the timeout elapsed before termination + * @throws InterruptedException if interrupted while waiting + */ + public boolean awaitTermination(long timeout, TimeUnit unit) + throws InterruptedException { + long nanos = unit.toNanos(timeout); + final ReentrantLock lock = this.submissionLock; + lock.lock(); + try { + for (;;) { + if (isTerminated()) + return true; + if (nanos <= 0) + return false; + nanos = termination.awaitNanos(nanos); + } + } finally { + lock.unlock(); + } + } + + /** + * Interface for extending managed parallelism for tasks running + * in {@link ForkJoinPool}s. + * + *

A {@code ManagedBlocker} provides two methods. Method + * {@code isReleasable} must return {@code true} if blocking is + * not necessary. Method {@code block} blocks the current thread + * if necessary (perhaps internally invoking {@code isReleasable} + * before actually blocking). These actions are performed by any + * thread invoking {@link ForkJoinPool#managedBlock}. The + * unusual methods in this API accommodate synchronizers that may, + * but don't usually, block for long periods. Similarly, they + * allow more efficient internal handling of cases in which + * additional workers may be, but usually are not, needed to + * ensure sufficient parallelism. Toward this end, + * implementations of method {@code isReleasable} must be amenable + * to repeated invocation. + * + *

For example, here is a ManagedBlocker based on a + * ReentrantLock: + *

 {@code
+     * class ManagedLocker implements ManagedBlocker {
+     *   final ReentrantLock lock;
+     *   boolean hasLock = false;
+     *   ManagedLocker(ReentrantLock lock) { this.lock = lock; }
+     *   public boolean block() {
+     *     if (!hasLock)
+     *       lock.lock();
+     *     return true;
+     *   }
+     *   public boolean isReleasable() {
+     *     return hasLock || (hasLock = lock.tryLock());
+     *   }
+     * }}
+ * + *

Here is a class that possibly blocks waiting for an + * item on a given queue: + *

 {@code
+     * class QueueTaker implements ManagedBlocker {
+     *   final BlockingQueue queue;
+     *   volatile E item = null;
+     *   QueueTaker(BlockingQueue q) { this.queue = q; }
+     *   public boolean block() throws InterruptedException {
+     *     if (item == null)
+     *       item = queue.take();
+     *     return true;
+     *   }
+     *   public boolean isReleasable() {
+     *     return item != null || (item = queue.poll()) != null;
+     *   }
+     *   public E getItem() { // call after pool.managedBlock completes
+     *     return item;
+     *   }
+     * }}
+ */ + public static interface ManagedBlocker { + /** + * Possibly blocks the current thread, for example waiting for + * a lock or condition. + * + * @return {@code true} if no additional blocking is necessary + * (i.e., if isReleasable would return true) + * @throws InterruptedException if interrupted while waiting + * (the method is not required to do so, but is allowed to) + */ + boolean block() throws InterruptedException; + + /** + * Returns {@code true} if blocking is unnecessary. + */ + boolean isReleasable(); + } + + /** + * Blocks in accord with the given blocker. If the current thread + * is a {@link ForkJoinWorkerThread}, this method possibly + * arranges for a spare thread to be activated if necessary to + * ensure sufficient parallelism while the current thread is blocked. + * + *

If the caller is not a {@link ForkJoinTask}, this method is + * behaviorally equivalent to + *

 {@code
+     * while (!blocker.isReleasable())
+     *   if (blocker.block())
+     *     return;
+     * }
+ * + * If the caller is a {@code ForkJoinTask}, then the pool may + * first be expanded to ensure parallelism, and later adjusted. + * + * @param blocker the blocker + * @throws InterruptedException if blocker.block did so + */ + public static void managedBlock(ManagedBlocker blocker) + throws InterruptedException { + Thread t = Thread.currentThread(); + if (t instanceof ForkJoinWorkerThread) { + ForkJoinWorkerThread w = (ForkJoinWorkerThread) t; + w.pool.awaitBlocker(blocker); + } + else { + do {} while (!blocker.isReleasable() && !blocker.block()); + } + } + + // AbstractExecutorService overrides. These rely on undocumented + // fact that ForkJoinTask.adapt returns ForkJoinTasks that also + // implement RunnableFuture. + + protected RunnableFuture newTaskFor(Runnable runnable, T value) { + return (RunnableFuture) ForkJoinTask.adapt(runnable, value); + } + + protected RunnableFuture newTaskFor(Callable callable) { + return (RunnableFuture) ForkJoinTask.adapt(callable); + } + + // Unsafe mechanics + private static final sun.misc.Unsafe UNSAFE; + private static final long ctlOffset; + private static final long stealCountOffset; + private static final long blockedCountOffset; + private static final long quiescerCountOffset; + private static final long scanGuardOffset; + private static final long nextWorkerNumberOffset; + private static final long ABASE; + private static final int ASHIFT; + + static { + poolNumberGenerator = new AtomicInteger(); + workerSeedGenerator = new Random(); + modifyThreadPermission = new RuntimePermission("modifyThread"); + defaultForkJoinWorkerThreadFactory = + new DefaultForkJoinWorkerThreadFactory(); + int s; + try { + UNSAFE = sun.misc.Unsafe.getUnsafe(); + Class k = ForkJoinPool.class; + ctlOffset = UNSAFE.objectFieldOffset + (k.getDeclaredField("ctl")); + stealCountOffset = UNSAFE.objectFieldOffset + (k.getDeclaredField("stealCount")); + blockedCountOffset = UNSAFE.objectFieldOffset + (k.getDeclaredField("blockedCount")); + quiescerCountOffset = UNSAFE.objectFieldOffset + (k.getDeclaredField("quiescerCount")); + scanGuardOffset = UNSAFE.objectFieldOffset + (k.getDeclaredField("scanGuard")); + nextWorkerNumberOffset = UNSAFE.objectFieldOffset + (k.getDeclaredField("nextWorkerNumber")); + Class a = ForkJoinTask[].class; + ABASE = UNSAFE.arrayBaseOffset(a); + s = UNSAFE.arrayIndexScale(a); + } catch (Exception e) { + throw new Error(e); + } + if ((s & (s-1)) != 0) + throw new Error("data type scale not a power of two"); + ASHIFT = 31 - Integer.numberOfLeadingZeros(s); + } + +} diff -r e1953d8b8338 -r c8af252ea9eb rt/emul/compact/src/main/java/java/util/concurrent/ForkJoinTask.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/ForkJoinTask.java Sat Mar 19 10:48:29 2016 +0100 @@ -0,0 +1,1386 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +package java.util.concurrent; + +import java.io.Serializable; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.RandomAccess; +import java.util.Map; +import java.lang.ref.WeakReference; +import java.lang.ref.ReferenceQueue; +import java.util.concurrent.Callable; +import java.util.concurrent.CancellationException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executor; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Future; +import java.util.concurrent.RejectedExecutionException; +import java.util.concurrent.RunnableFuture; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.locks.ReentrantLock; +import java.lang.reflect.Constructor; + +/** + * Abstract base class for tasks that run within a {@link ForkJoinPool}. + * A {@code ForkJoinTask} is a thread-like entity that is much + * lighter weight than a normal thread. Huge numbers of tasks and + * subtasks may be hosted by a small number of actual threads in a + * ForkJoinPool, at the price of some usage limitations. + * + *

A "main" {@code ForkJoinTask} begins execution when submitted + * to a {@link ForkJoinPool}. Once started, it will usually in turn + * start other subtasks. As indicated by the name of this class, + * many programs using {@code ForkJoinTask} employ only methods + * {@link #fork} and {@link #join}, or derivatives such as {@link + * #invokeAll(ForkJoinTask...) invokeAll}. However, this class also + * provides a number of other methods that can come into play in + * advanced usages, as well as extension mechanics that allow + * support of new forms of fork/join processing. + * + *

A {@code ForkJoinTask} is a lightweight form of {@link Future}. + * The efficiency of {@code ForkJoinTask}s stems from a set of + * restrictions (that are only partially statically enforceable) + * reflecting their intended use as computational tasks calculating + * pure functions or operating on purely isolated objects. The + * primary coordination mechanisms are {@link #fork}, that arranges + * asynchronous execution, and {@link #join}, that doesn't proceed + * until the task's result has been computed. Computations should + * avoid {@code synchronized} methods or blocks, and should minimize + * other blocking synchronization apart from joining other tasks or + * using synchronizers such as Phasers that are advertised to + * cooperate with fork/join scheduling. Tasks should also not perform + * blocking IO, and should ideally access variables that are + * completely independent of those accessed by other running + * tasks. Minor breaches of these restrictions, for example using + * shared output streams, may be tolerable in practice, but frequent + * use may result in poor performance, and the potential to + * indefinitely stall if the number of threads not waiting for IO or + * other external synchronization becomes exhausted. This usage + * restriction is in part enforced by not permitting checked + * exceptions such as {@code IOExceptions} to be thrown. However, + * computations may still encounter unchecked exceptions, that are + * rethrown to callers attempting to join them. These exceptions may + * additionally include {@link RejectedExecutionException} stemming + * from internal resource exhaustion, such as failure to allocate + * internal task queues. Rethrown exceptions behave in the same way as + * regular exceptions, but, when possible, contain stack traces (as + * displayed for example using {@code ex.printStackTrace()}) of both + * the thread that initiated the computation as well as the thread + * actually encountering the exception; minimally only the latter. + * + *

The primary method for awaiting completion and extracting + * results of a task is {@link #join}, but there are several variants: + * The {@link Future#get} methods support interruptible and/or timed + * waits for completion and report results using {@code Future} + * conventions. Method {@link #invoke} is semantically + * equivalent to {@code fork(); join()} but always attempts to begin + * execution in the current thread. The "quiet" forms of + * these methods do not extract results or report exceptions. These + * may be useful when a set of tasks are being executed, and you need + * to delay processing of results or exceptions until all complete. + * Method {@code invokeAll} (available in multiple versions) + * performs the most common form of parallel invocation: forking a set + * of tasks and joining them all. + * + *

The execution status of tasks may be queried at several levels + * of detail: {@link #isDone} is true if a task completed in any way + * (including the case where a task was cancelled without executing); + * {@link #isCompletedNormally} is true if a task completed without + * cancellation or encountering an exception; {@link #isCancelled} is + * true if the task was cancelled (in which case {@link #getException} + * returns a {@link java.util.concurrent.CancellationException}); and + * {@link #isCompletedAbnormally} is true if a task was either + * cancelled or encountered an exception, in which case {@link + * #getException} will return either the encountered exception or + * {@link java.util.concurrent.CancellationException}. + * + *

The ForkJoinTask class is not usually directly subclassed. + * Instead, you subclass one of the abstract classes that support a + * particular style of fork/join processing, typically {@link + * RecursiveAction} for computations that do not return results, or + * {@link RecursiveTask} for those that do. Normally, a concrete + * ForkJoinTask subclass declares fields comprising its parameters, + * established in a constructor, and then defines a {@code compute} + * method that somehow uses the control methods supplied by this base + * class. While these methods have {@code public} access (to allow + * instances of different task subclasses to call each other's + * methods), some of them may only be called from within other + * ForkJoinTasks (as may be determined using method {@link + * #inForkJoinPool}). Attempts to invoke them in other contexts + * result in exceptions or errors, possibly including + * {@code ClassCastException}. + * + *

Method {@link #join} and its variants are appropriate for use + * only when completion dependencies are acyclic; that is, the + * parallel computation can be described as a directed acyclic graph + * (DAG). Otherwise, executions may encounter a form of deadlock as + * tasks cyclically wait for each other. However, this framework + * supports other methods and techniques (for example the use of + * {@link Phaser}, {@link #helpQuiesce}, and {@link #complete}) that + * may be of use in constructing custom subclasses for problems that + * are not statically structured as DAGs. + * + *

Most base support methods are {@code final}, to prevent + * overriding of implementations that are intrinsically tied to the + * underlying lightweight task scheduling framework. Developers + * creating new basic styles of fork/join processing should minimally + * implement {@code protected} methods {@link #exec}, {@link + * #setRawResult}, and {@link #getRawResult}, while also introducing + * an abstract computational method that can be implemented in its + * subclasses, possibly relying on other {@code protected} methods + * provided by this class. + * + *

ForkJoinTasks should perform relatively small amounts of + * computation. Large tasks should be split into smaller subtasks, + * usually via recursive decomposition. As a very rough rule of thumb, + * a task should perform more than 100 and less than 10000 basic + * computational steps, and should avoid indefinite looping. If tasks + * are too big, then parallelism cannot improve throughput. If too + * small, then memory and internal task maintenance overhead may + * overwhelm processing. + * + *

This class provides {@code adapt} methods for {@link Runnable} + * and {@link Callable}, that may be of use when mixing execution of + * {@code ForkJoinTasks} with other kinds of tasks. When all tasks are + * of this form, consider using a pool constructed in asyncMode. + * + *

ForkJoinTasks are {@code Serializable}, which enables them to be + * used in extensions such as remote execution frameworks. It is + * sensible to serialize tasks only before or after, but not during, + * execution. Serialization is not relied on during execution itself. + * + * @since 1.7 + * @author Doug Lea + */ +public abstract class ForkJoinTask implements Future, Serializable { + + /* + * See the internal documentation of class ForkJoinPool for a + * general implementation overview. ForkJoinTasks are mainly + * responsible for maintaining their "status" field amidst relays + * to methods in ForkJoinWorkerThread and ForkJoinPool. The + * methods of this class are more-or-less layered into (1) basic + * status maintenance (2) execution and awaiting completion (3) + * user-level methods that additionally report results. This is + * sometimes hard to see because this file orders exported methods + * in a way that flows well in javadocs. + */ + + /* + * The status field holds run control status bits packed into a + * single int to minimize footprint and to ensure atomicity (via + * CAS). Status is initially zero, and takes on nonnegative + * values until completed, upon which status holds value + * NORMAL, CANCELLED, or EXCEPTIONAL. Tasks undergoing blocking + * waits by other threads have the SIGNAL bit set. Completion of + * a stolen task with SIGNAL set awakens any waiters via + * notifyAll. Even though suboptimal for some purposes, we use + * basic builtin wait/notify to take advantage of "monitor + * inflation" in JVMs that we would otherwise need to emulate to + * avoid adding further per-task bookkeeping overhead. We want + * these monitors to be "fat", i.e., not use biasing or thin-lock + * techniques, so use some odd coding idioms that tend to avoid + * them. + */ + + /** The run status of this task */ + volatile int status; // accessed directly by pool and workers + private static final int NORMAL = -1; + private static final int CANCELLED = -2; + private static final int EXCEPTIONAL = -3; + private static final int SIGNAL = 1; + + /** + * Marks completion and wakes up threads waiting to join this task, + * also clearing signal request bits. + * + * @param completion one of NORMAL, CANCELLED, EXCEPTIONAL + * @return completion status on exit + */ + private int setCompletion(int completion) { + for (int s;;) { + if ((s = status) < 0) + return s; + if (UNSAFE.compareAndSwapInt(this, statusOffset, s, completion)) { + if (s != 0) + synchronized (this) { notifyAll(); } + return completion; + } + } + } + + /** + * Tries to block a worker thread until completed or timed out. + * Uses Object.wait time argument conventions. + * May fail on contention or interrupt. + * + * @param millis if > 0, wait time. + */ + final void tryAwaitDone(long millis) { + int s; + try { + if (((s = status) > 0 || + (s == 0 && + UNSAFE.compareAndSwapInt(this, statusOffset, 0, SIGNAL))) && + status > 0) { + synchronized (this) { + if (status > 0) + wait(millis); + } + } + } catch (InterruptedException ie) { + // caller must check termination + } + } + + /** + * Blocks a non-worker-thread until completion. + * @return status upon completion + */ + private int externalAwaitDone() { + int s; + if ((s = status) >= 0) { + boolean interrupted = false; + synchronized (this) { + while ((s = status) >= 0) { + if (s == 0) + UNSAFE.compareAndSwapInt(this, statusOffset, + 0, SIGNAL); + else { + try { + wait(); + } catch (InterruptedException ie) { + interrupted = true; + } + } + } + } + if (interrupted) + Thread.currentThread().interrupt(); + } + return s; + } + + /** + * Blocks a non-worker-thread until completion or interruption or timeout. + */ + private int externalInterruptibleAwaitDone(long millis) + throws InterruptedException { + int s; + if (Thread.interrupted()) + throw new InterruptedException(); + if ((s = status) >= 0) { + synchronized (this) { + while ((s = status) >= 0) { + if (s == 0) + UNSAFE.compareAndSwapInt(this, statusOffset, + 0, SIGNAL); + else { + wait(millis); + if (millis > 0L) + break; + } + } + } + } + return s; + } + + /** + * Primary execution method for stolen tasks. Unless done, calls + * exec and records status if completed, but doesn't wait for + * completion otherwise. + */ + final void doExec() { + if (status >= 0) { + boolean completed; + try { + completed = exec(); + } catch (Throwable rex) { + setExceptionalCompletion(rex); + return; + } + if (completed) + setCompletion(NORMAL); // must be outside try block + } + } + + /** + * Primary mechanics for join, get, quietlyJoin. + * @return status upon completion + */ + private int doJoin() { + Thread t; ForkJoinWorkerThread w; int s; boolean completed; + if ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) { + if ((s = status) < 0) + return s; + if ((w = (ForkJoinWorkerThread)t).unpushTask(this)) { + try { + completed = exec(); + } catch (Throwable rex) { + return setExceptionalCompletion(rex); + } + if (completed) + return setCompletion(NORMAL); + } + return w.joinTask(this); + } + else + return externalAwaitDone(); + } + + /** + * Primary mechanics for invoke, quietlyInvoke. + * @return status upon completion + */ + private int doInvoke() { + int s; boolean completed; + if ((s = status) < 0) + return s; + try { + completed = exec(); + } catch (Throwable rex) { + return setExceptionalCompletion(rex); + } + if (completed) + return setCompletion(NORMAL); + else + return doJoin(); + } + + // Exception table support + + /** + * Table of exceptions thrown by tasks, to enable reporting by + * callers. Because exceptions are rare, we don't directly keep + * them with task objects, but instead use a weak ref table. Note + * that cancellation exceptions don't appear in the table, but are + * instead recorded as status values. + * + * Note: These statics are initialized below in static block. + */ + private static final ExceptionNode[] exceptionTable; + private static final ReentrantLock exceptionTableLock; + private static final ReferenceQueue exceptionTableRefQueue; + + /** + * Fixed capacity for exceptionTable. + */ + private static final int EXCEPTION_MAP_CAPACITY = 32; + + /** + * Key-value nodes for exception table. The chained hash table + * uses identity comparisons, full locking, and weak references + * for keys. The table has a fixed capacity because it only + * maintains task exceptions long enough for joiners to access + * them, so should never become very large for sustained + * periods. However, since we do not know when the last joiner + * completes, we must use weak references and expunge them. We do + * so on each operation (hence full locking). Also, some thread in + * any ForkJoinPool will call helpExpungeStaleExceptions when its + * pool becomes isQuiescent. + */ + static final class ExceptionNode extends WeakReference>{ + final Throwable ex; + ExceptionNode next; + final long thrower; // use id not ref to avoid weak cycles + ExceptionNode(ForkJoinTask task, Throwable ex, ExceptionNode next) { + super(task, exceptionTableRefQueue); + this.ex = ex; + this.next = next; + this.thrower = Thread.currentThread().getId(); + } + } + + /** + * Records exception and sets exceptional completion. + * + * @return status on exit + */ + private int setExceptionalCompletion(Throwable ex) { + int h = System.identityHashCode(this); + final ReentrantLock lock = exceptionTableLock; + lock.lock(); + try { + expungeStaleExceptions(); + ExceptionNode[] t = exceptionTable; + int i = h & (t.length - 1); + for (ExceptionNode e = t[i]; ; e = e.next) { + if (e == null) { + t[i] = new ExceptionNode(this, ex, t[i]); + break; + } + if (e.get() == this) // already present + break; + } + } finally { + lock.unlock(); + } + return setCompletion(EXCEPTIONAL); + } + + /** + * Removes exception node and clears status + */ + private void clearExceptionalCompletion() { + int h = System.identityHashCode(this); + final ReentrantLock lock = exceptionTableLock; + lock.lock(); + try { + ExceptionNode[] t = exceptionTable; + int i = h & (t.length - 1); + ExceptionNode e = t[i]; + ExceptionNode pred = null; + while (e != null) { + ExceptionNode next = e.next; + if (e.get() == this) { + if (pred == null) + t[i] = next; + else + pred.next = next; + break; + } + pred = e; + e = next; + } + expungeStaleExceptions(); + status = 0; + } finally { + lock.unlock(); + } + } + + /** + * Returns a rethrowable exception for the given task, if + * available. To provide accurate stack traces, if the exception + * was not thrown by the current thread, we try to create a new + * exception of the same type as the one thrown, but with the + * recorded exception as its cause. If there is no such + * constructor, we instead try to use a no-arg constructor, + * followed by initCause, to the same effect. If none of these + * apply, or any fail due to other exceptions, we return the + * recorded exception, which is still correct, although it may + * contain a misleading stack trace. + * + * @return the exception, or null if none + */ + private Throwable getThrowableException() { + if (status != EXCEPTIONAL) + return null; + int h = System.identityHashCode(this); + ExceptionNode e; + final ReentrantLock lock = exceptionTableLock; + lock.lock(); + try { + expungeStaleExceptions(); + ExceptionNode[] t = exceptionTable; + e = t[h & (t.length - 1)]; + while (e != null && e.get() != this) + e = e.next; + } finally { + lock.unlock(); + } + Throwable ex; + if (e == null || (ex = e.ex) == null) + return null; + if (e.thrower != Thread.currentThread().getId()) { + Class ec = ex.getClass(); + try { + Constructor noArgCtor = null; + Constructor[] cs = ec.getConstructors();// public ctors only + for (int i = 0; i < cs.length; ++i) { + Constructor c = cs[i]; + Class[] ps = c.getParameterTypes(); + if (ps.length == 0) + noArgCtor = c; + else if (ps.length == 1 && ps[0] == Throwable.class) + return (Throwable)(c.newInstance(ex)); + } + if (noArgCtor != null) { + Throwable wx = (Throwable)(noArgCtor.newInstance()); + wx.initCause(ex); + return wx; + } + } catch (Exception ignore) { + } + } + return ex; + } + + /** + * Poll stale refs and remove them. Call only while holding lock. + */ + private static void expungeStaleExceptions() { + for (Object x; (x = exceptionTableRefQueue.poll()) != null;) { + if (x instanceof ExceptionNode) { + ForkJoinTask key = ((ExceptionNode)x).get(); + ExceptionNode[] t = exceptionTable; + int i = System.identityHashCode(key) & (t.length - 1); + ExceptionNode e = t[i]; + ExceptionNode pred = null; + while (e != null) { + ExceptionNode next = e.next; + if (e == x) { + if (pred == null) + t[i] = next; + else + pred.next = next; + break; + } + pred = e; + e = next; + } + } + } + } + + /** + * If lock is available, poll stale refs and remove them. + * Called from ForkJoinPool when pools become quiescent. + */ + static final void helpExpungeStaleExceptions() { + final ReentrantLock lock = exceptionTableLock; + if (lock.tryLock()) { + try { + expungeStaleExceptions(); + } finally { + lock.unlock(); + } + } + } + + /** + * Report the result of invoke or join; called only upon + * non-normal return of internal versions. + */ + private V reportResult() { + int s; Throwable ex; + if ((s = status) == CANCELLED) + throw new CancellationException(); + if (s == EXCEPTIONAL && (ex = getThrowableException()) != null) + UNSAFE.throwException(ex); + return getRawResult(); + } + + // public methods + + /** + * Arranges to asynchronously execute this task. While it is not + * necessarily enforced, it is a usage error to fork a task more + * than once unless it has completed and been reinitialized. + * Subsequent modifications to the state of this task or any data + * it operates on are not necessarily consistently observable by + * any thread other than the one executing it unless preceded by a + * call to {@link #join} or related methods, or a call to {@link + * #isDone} returning {@code true}. + * + *

This method may be invoked only from within {@code + * ForkJoinPool} computations (as may be determined using method + * {@link #inForkJoinPool}). Attempts to invoke in other contexts + * result in exceptions or errors, possibly including {@code + * ClassCastException}. + * + * @return {@code this}, to simplify usage + */ + public final ForkJoinTask fork() { + ((ForkJoinWorkerThread) Thread.currentThread()) + .pushTask(this); + return this; + } + + /** + * Returns the result of the computation when it {@link #isDone is + * done}. This method differs from {@link #get()} in that + * abnormal completion results in {@code RuntimeException} or + * {@code Error}, not {@code ExecutionException}, and that + * interrupts of the calling thread do not cause the + * method to abruptly return by throwing {@code + * InterruptedException}. + * + * @return the computed result + */ + public final V join() { + if (doJoin() != NORMAL) + return reportResult(); + else + return getRawResult(); + } + + /** + * Commences performing this task, awaits its completion if + * necessary, and returns its result, or throws an (unchecked) + * {@code RuntimeException} or {@code Error} if the underlying + * computation did so. + * + * @return the computed result + */ + public final V invoke() { + if (doInvoke() != NORMAL) + return reportResult(); + else + return getRawResult(); + } + + /** + * Forks the given tasks, returning when {@code isDone} holds for + * each task or an (unchecked) exception is encountered, in which + * case the exception is rethrown. If more than one task + * encounters an exception, then this method throws any one of + * these exceptions. If any task encounters an exception, the + * other may be cancelled. However, the execution status of + * individual tasks is not guaranteed upon exceptional return. The + * status of each task may be obtained using {@link + * #getException()} and related methods to check if they have been + * cancelled, completed normally or exceptionally, or left + * unprocessed. + * + *

This method may be invoked only from within {@code + * ForkJoinPool} computations (as may be determined using method + * {@link #inForkJoinPool}). Attempts to invoke in other contexts + * result in exceptions or errors, possibly including {@code + * ClassCastException}. + * + * @param t1 the first task + * @param t2 the second task + * @throws NullPointerException if any task is null + */ + public static void invokeAll(ForkJoinTask t1, ForkJoinTask t2) { + t2.fork(); + t1.invoke(); + t2.join(); + } + + /** + * Forks the given tasks, returning when {@code isDone} holds for + * each task or an (unchecked) exception is encountered, in which + * case the exception is rethrown. If more than one task + * encounters an exception, then this method throws any one of + * these exceptions. If any task encounters an exception, others + * may be cancelled. However, the execution status of individual + * tasks is not guaranteed upon exceptional return. The status of + * each task may be obtained using {@link #getException()} and + * related methods to check if they have been cancelled, completed + * normally or exceptionally, or left unprocessed. + * + *

This method may be invoked only from within {@code + * ForkJoinPool} computations (as may be determined using method + * {@link #inForkJoinPool}). Attempts to invoke in other contexts + * result in exceptions or errors, possibly including {@code + * ClassCastException}. + * + * @param tasks the tasks + * @throws NullPointerException if any task is null + */ + public static void invokeAll(ForkJoinTask... tasks) { + Throwable ex = null; + int last = tasks.length - 1; + for (int i = last; i >= 0; --i) { + ForkJoinTask t = tasks[i]; + if (t == null) { + if (ex == null) + ex = new NullPointerException(); + } + else if (i != 0) + t.fork(); + else if (t.doInvoke() < NORMAL && ex == null) + ex = t.getException(); + } + for (int i = 1; i <= last; ++i) { + ForkJoinTask t = tasks[i]; + if (t != null) { + if (ex != null) + t.cancel(false); + else if (t.doJoin() < NORMAL && ex == null) + ex = t.getException(); + } + } + if (ex != null) + UNSAFE.throwException(ex); + } + + /** + * Forks all tasks in the specified collection, returning when + * {@code isDone} holds for each task or an (unchecked) exception + * is encountered, in which case the exception is rethrown. If + * more than one task encounters an exception, then this method + * throws any one of these exceptions. If any task encounters an + * exception, others may be cancelled. However, the execution + * status of individual tasks is not guaranteed upon exceptional + * return. The status of each task may be obtained using {@link + * #getException()} and related methods to check if they have been + * cancelled, completed normally or exceptionally, or left + * unprocessed. + * + *

This method may be invoked only from within {@code + * ForkJoinPool} computations (as may be determined using method + * {@link #inForkJoinPool}). Attempts to invoke in other contexts + * result in exceptions or errors, possibly including {@code + * ClassCastException}. + * + * @param tasks the collection of tasks + * @return the tasks argument, to simplify usage + * @throws NullPointerException if tasks or any element are null + */ + public static > Collection invokeAll(Collection tasks) { + if (!(tasks instanceof RandomAccess) || !(tasks instanceof List)) { + invokeAll(tasks.toArray(new ForkJoinTask[tasks.size()])); + return tasks; + } + @SuppressWarnings("unchecked") + List> ts = + (List>) tasks; + Throwable ex = null; + int last = ts.size() - 1; + for (int i = last; i >= 0; --i) { + ForkJoinTask t = ts.get(i); + if (t == null) { + if (ex == null) + ex = new NullPointerException(); + } + else if (i != 0) + t.fork(); + else if (t.doInvoke() < NORMAL && ex == null) + ex = t.getException(); + } + for (int i = 1; i <= last; ++i) { + ForkJoinTask t = ts.get(i); + if (t != null) { + if (ex != null) + t.cancel(false); + else if (t.doJoin() < NORMAL && ex == null) + ex = t.getException(); + } + } + if (ex != null) + UNSAFE.throwException(ex); + return tasks; + } + + /** + * Attempts to cancel execution of this task. This attempt will + * fail if the task has already completed or could not be + * cancelled for some other reason. If successful, and this task + * has not started when {@code cancel} is called, execution of + * this task is suppressed. After this method returns + * successfully, unless there is an intervening call to {@link + * #reinitialize}, subsequent calls to {@link #isCancelled}, + * {@link #isDone}, and {@code cancel} will return {@code true} + * and calls to {@link #join} and related methods will result in + * {@code CancellationException}. + * + *

This method may be overridden in subclasses, but if so, must + * still ensure that these properties hold. In particular, the + * {@code cancel} method itself must not throw exceptions. + * + *

This method is designed to be invoked by other + * tasks. To terminate the current task, you can just return or + * throw an unchecked exception from its computation method, or + * invoke {@link #completeExceptionally}. + * + * @param mayInterruptIfRunning this value has no effect in the + * default implementation because interrupts are not used to + * control cancellation. + * + * @return {@code true} if this task is now cancelled + */ + public boolean cancel(boolean mayInterruptIfRunning) { + return setCompletion(CANCELLED) == CANCELLED; + } + + /** + * Cancels, ignoring any exceptions thrown by cancel. Used during + * worker and pool shutdown. Cancel is spec'ed not to throw any + * exceptions, but if it does anyway, we have no recourse during + * shutdown, so guard against this case. + */ + final void cancelIgnoringExceptions() { + try { + cancel(false); + } catch (Throwable ignore) { + } + } + + public final boolean isDone() { + return status < 0; + } + + public final boolean isCancelled() { + return status == CANCELLED; + } + + /** + * Returns {@code true} if this task threw an exception or was cancelled. + * + * @return {@code true} if this task threw an exception or was cancelled + */ + public final boolean isCompletedAbnormally() { + return status < NORMAL; + } + + /** + * Returns {@code true} if this task completed without throwing an + * exception and was not cancelled. + * + * @return {@code true} if this task completed without throwing an + * exception and was not cancelled + */ + public final boolean isCompletedNormally() { + return status == NORMAL; + } + + /** + * Returns the exception thrown by the base computation, or a + * {@code CancellationException} if cancelled, or {@code null} if + * none or if the method has not yet completed. + * + * @return the exception, or {@code null} if none + */ + public final Throwable getException() { + int s = status; + return ((s >= NORMAL) ? null : + (s == CANCELLED) ? new CancellationException() : + getThrowableException()); + } + + /** + * Completes this task abnormally, and if not already aborted or + * cancelled, causes it to throw the given exception upon + * {@code join} and related operations. This method may be used + * to induce exceptions in asynchronous tasks, or to force + * completion of tasks that would not otherwise complete. Its use + * in other situations is discouraged. This method is + * overridable, but overridden versions must invoke {@code super} + * implementation to maintain guarantees. + * + * @param ex the exception to throw. If this exception is not a + * {@code RuntimeException} or {@code Error}, the actual exception + * thrown will be a {@code RuntimeException} with cause {@code ex}. + */ + public void completeExceptionally(Throwable ex) { + setExceptionalCompletion((ex instanceof RuntimeException) || + (ex instanceof Error) ? ex : + new RuntimeException(ex)); + } + + /** + * Completes this task, and if not already aborted or cancelled, + * returning the given value as the result of subsequent + * invocations of {@code join} and related operations. This method + * may be used to provide results for asynchronous tasks, or to + * provide alternative handling for tasks that would not otherwise + * complete normally. Its use in other situations is + * discouraged. This method is overridable, but overridden + * versions must invoke {@code super} implementation to maintain + * guarantees. + * + * @param value the result value for this task + */ + public void complete(V value) { + try { + setRawResult(value); + } catch (Throwable rex) { + setExceptionalCompletion(rex); + return; + } + setCompletion(NORMAL); + } + + /** + * Waits if necessary for the computation to complete, and then + * retrieves its result. + * + * @return the computed result + * @throws CancellationException if the computation was cancelled + * @throws ExecutionException if the computation threw an + * exception + * @throws InterruptedException if the current thread is not a + * member of a ForkJoinPool and was interrupted while waiting + */ + public final V get() throws InterruptedException, ExecutionException { + int s = (Thread.currentThread() instanceof ForkJoinWorkerThread) ? + doJoin() : externalInterruptibleAwaitDone(0L); + Throwable ex; + if (s == CANCELLED) + throw new CancellationException(); + if (s == EXCEPTIONAL && (ex = getThrowableException()) != null) + throw new ExecutionException(ex); + return getRawResult(); + } + + /** + * Waits if necessary for at most the given time for the computation + * to complete, and then retrieves its result, if available. + * + * @param timeout the maximum time to wait + * @param unit the time unit of the timeout argument + * @return the computed result + * @throws CancellationException if the computation was cancelled + * @throws ExecutionException if the computation threw an + * exception + * @throws InterruptedException if the current thread is not a + * member of a ForkJoinPool and was interrupted while waiting + * @throws TimeoutException if the wait timed out + */ + public final V get(long timeout, TimeUnit unit) + throws InterruptedException, ExecutionException, TimeoutException { + Thread t = Thread.currentThread(); + if (t instanceof ForkJoinWorkerThread) { + ForkJoinWorkerThread w = (ForkJoinWorkerThread) t; + long nanos = unit.toNanos(timeout); + if (status >= 0) { + boolean completed = false; + if (w.unpushTask(this)) { + try { + completed = exec(); + } catch (Throwable rex) { + setExceptionalCompletion(rex); + } + } + if (completed) + setCompletion(NORMAL); + else if (status >= 0 && nanos > 0) + w.pool.timedAwaitJoin(this, nanos); + } + } + else { + long millis = unit.toMillis(timeout); + if (millis > 0) + externalInterruptibleAwaitDone(millis); + } + int s = status; + if (s != NORMAL) { + Throwable ex; + if (s == CANCELLED) + throw new CancellationException(); + if (s != EXCEPTIONAL) + throw new TimeoutException(); + if ((ex = getThrowableException()) != null) + throw new ExecutionException(ex); + } + return getRawResult(); + } + + /** + * Joins this task, without returning its result or throwing its + * exception. This method may be useful when processing + * collections of tasks when some have been cancelled or otherwise + * known to have aborted. + */ + public final void quietlyJoin() { + doJoin(); + } + + /** + * Commences performing this task and awaits its completion if + * necessary, without returning its result or throwing its + * exception. + */ + public final void quietlyInvoke() { + doInvoke(); + } + + /** + * Possibly executes tasks until the pool hosting the current task + * {@link ForkJoinPool#isQuiescent is quiescent}. This method may + * be of use in designs in which many tasks are forked, but none + * are explicitly joined, instead executing them until all are + * processed. + * + *

This method may be invoked only from within {@code + * ForkJoinPool} computations (as may be determined using method + * {@link #inForkJoinPool}). Attempts to invoke in other contexts + * result in exceptions or errors, possibly including {@code + * ClassCastException}. + */ + public static void helpQuiesce() { + ((ForkJoinWorkerThread) Thread.currentThread()) + .helpQuiescePool(); + } + + /** + * Resets the internal bookkeeping state of this task, allowing a + * subsequent {@code fork}. This method allows repeated reuse of + * this task, but only if reuse occurs when this task has either + * never been forked, or has been forked, then completed and all + * outstanding joins of this task have also completed. Effects + * under any other usage conditions are not guaranteed. + * This method may be useful when executing + * pre-constructed trees of subtasks in loops. + * + *

Upon completion of this method, {@code isDone()} reports + * {@code false}, and {@code getException()} reports {@code + * null}. However, the value returned by {@code getRawResult} is + * unaffected. To clear this value, you can invoke {@code + * setRawResult(null)}. + */ + public void reinitialize() { + if (status == EXCEPTIONAL) + clearExceptionalCompletion(); + else + status = 0; + } + + /** + * Returns the pool hosting the current task execution, or null + * if this task is executing outside of any ForkJoinPool. + * + * @see #inForkJoinPool + * @return the pool, or {@code null} if none + */ + public static ForkJoinPool getPool() { + Thread t = Thread.currentThread(); + return (t instanceof ForkJoinWorkerThread) ? + ((ForkJoinWorkerThread) t).pool : null; + } + + /** + * Returns {@code true} if the current thread is a {@link + * ForkJoinWorkerThread} executing as a ForkJoinPool computation. + * + * @return {@code true} if the current thread is a {@link + * ForkJoinWorkerThread} executing as a ForkJoinPool computation, + * or {@code false} otherwise + */ + public static boolean inForkJoinPool() { + return Thread.currentThread() instanceof ForkJoinWorkerThread; + } + + /** + * Tries to unschedule this task for execution. This method will + * typically succeed if this task is the most recently forked task + * by the current thread, and has not commenced executing in + * another thread. This method may be useful when arranging + * alternative local processing of tasks that could have been, but + * were not, stolen. + * + *

This method may be invoked only from within {@code + * ForkJoinPool} computations (as may be determined using method + * {@link #inForkJoinPool}). Attempts to invoke in other contexts + * result in exceptions or errors, possibly including {@code + * ClassCastException}. + * + * @return {@code true} if unforked + */ + public boolean tryUnfork() { + return ((ForkJoinWorkerThread) Thread.currentThread()) + .unpushTask(this); + } + + /** + * Returns an estimate of the number of tasks that have been + * forked by the current worker thread but not yet executed. This + * value may be useful for heuristic decisions about whether to + * fork other tasks. + * + *

This method may be invoked only from within {@code + * ForkJoinPool} computations (as may be determined using method + * {@link #inForkJoinPool}). Attempts to invoke in other contexts + * result in exceptions or errors, possibly including {@code + * ClassCastException}. + * + * @return the number of tasks + */ + public static int getQueuedTaskCount() { + return ((ForkJoinWorkerThread) Thread.currentThread()) + .getQueueSize(); + } + + /** + * Returns an estimate of how many more locally queued tasks are + * held by the current worker thread than there are other worker + * threads that might steal them. This value may be useful for + * heuristic decisions about whether to fork other tasks. In many + * usages of ForkJoinTasks, at steady state, each worker should + * aim to maintain a small constant surplus (for example, 3) of + * tasks, and to process computations locally if this threshold is + * exceeded. + * + *

This method may be invoked only from within {@code + * ForkJoinPool} computations (as may be determined using method + * {@link #inForkJoinPool}). Attempts to invoke in other contexts + * result in exceptions or errors, possibly including {@code + * ClassCastException}. + * + * @return the surplus number of tasks, which may be negative + */ + public static int getSurplusQueuedTaskCount() { + return ((ForkJoinWorkerThread) Thread.currentThread()) + .getEstimatedSurplusTaskCount(); + } + + // Extension methods + + /** + * Returns the result that would be returned by {@link #join}, even + * if this task completed abnormally, or {@code null} if this task + * is not known to have been completed. This method is designed + * to aid debugging, as well as to support extensions. Its use in + * any other context is discouraged. + * + * @return the result, or {@code null} if not completed + */ + public abstract V getRawResult(); + + /** + * Forces the given value to be returned as a result. This method + * is designed to support extensions, and should not in general be + * called otherwise. + * + * @param value the value + */ + protected abstract void setRawResult(V value); + + /** + * Immediately performs the base action of this task. This method + * is designed to support extensions, and should not in general be + * called otherwise. The return value controls whether this task + * is considered to be done normally. It may return false in + * asynchronous actions that require explicit invocations of + * {@link #complete} to become joinable. It may also throw an + * (unchecked) exception to indicate abnormal exit. + * + * @return {@code true} if completed normally + */ + protected abstract boolean exec(); + + /** + * Returns, but does not unschedule or execute, a task queued by + * the current thread but not yet executed, if one is immediately + * available. There is no guarantee that this task will actually + * be polled or executed next. Conversely, this method may return + * null even if a task exists but cannot be accessed without + * contention with other threads. This method is designed + * primarily to support extensions, and is unlikely to be useful + * otherwise. + * + *

This method may be invoked only from within {@code + * ForkJoinPool} computations (as may be determined using method + * {@link #inForkJoinPool}). Attempts to invoke in other contexts + * result in exceptions or errors, possibly including {@code + * ClassCastException}. + * + * @return the next task, or {@code null} if none are available + */ + protected static ForkJoinTask peekNextLocalTask() { + return ((ForkJoinWorkerThread) Thread.currentThread()) + .peekTask(); + } + + /** + * Unschedules and returns, without executing, the next task + * queued by the current thread but not yet executed. This method + * is designed primarily to support extensions, and is unlikely to + * be useful otherwise. + * + *

This method may be invoked only from within {@code + * ForkJoinPool} computations (as may be determined using method + * {@link #inForkJoinPool}). Attempts to invoke in other contexts + * result in exceptions or errors, possibly including {@code + * ClassCastException}. + * + * @return the next task, or {@code null} if none are available + */ + protected static ForkJoinTask pollNextLocalTask() { + return ((ForkJoinWorkerThread) Thread.currentThread()) + .pollLocalTask(); + } + + /** + * Unschedules and returns, without executing, the next task + * queued by the current thread but not yet executed, if one is + * available, or if not available, a task that was forked by some + * other thread, if available. Availability may be transient, so a + * {@code null} result does not necessarily imply quiescence + * of the pool this task is operating in. This method is designed + * primarily to support extensions, and is unlikely to be useful + * otherwise. + * + *

This method may be invoked only from within {@code + * ForkJoinPool} computations (as may be determined using method + * {@link #inForkJoinPool}). Attempts to invoke in other contexts + * result in exceptions or errors, possibly including {@code + * ClassCastException}. + * + * @return a task, or {@code null} if none are available + */ + protected static ForkJoinTask pollTask() { + return ((ForkJoinWorkerThread) Thread.currentThread()) + .pollTask(); + } + + /** + * Adaptor for Runnables. This implements RunnableFuture + * to be compliant with AbstractExecutorService constraints + * when used in ForkJoinPool. + */ + static final class AdaptedRunnable extends ForkJoinTask + implements RunnableFuture { + final Runnable runnable; + final T resultOnCompletion; + T result; + AdaptedRunnable(Runnable runnable, T result) { + if (runnable == null) throw new NullPointerException(); + this.runnable = runnable; + this.resultOnCompletion = result; + } + public T getRawResult() { return result; } + public void setRawResult(T v) { result = v; } + public boolean exec() { + runnable.run(); + result = resultOnCompletion; + return true; + } + public void run() { invoke(); } + private static final long serialVersionUID = 5232453952276885070L; + } + + /** + * Adaptor for Callables + */ + static final class AdaptedCallable extends ForkJoinTask + implements RunnableFuture { + final Callable callable; + T result; + AdaptedCallable(Callable callable) { + if (callable == null) throw new NullPointerException(); + this.callable = callable; + } + public T getRawResult() { return result; } + public void setRawResult(T v) { result = v; } + public boolean exec() { + try { + result = callable.call(); + return true; + } catch (Error err) { + throw err; + } catch (RuntimeException rex) { + throw rex; + } catch (Exception ex) { + throw new RuntimeException(ex); + } + } + public void run() { invoke(); } + private static final long serialVersionUID = 2838392045355241008L; + } + + /** + * Returns a new {@code ForkJoinTask} that performs the {@code run} + * method of the given {@code Runnable} as its action, and returns + * a null result upon {@link #join}. + * + * @param runnable the runnable action + * @return the task + */ + public static ForkJoinTask adapt(Runnable runnable) { + return new AdaptedRunnable(runnable, null); + } + + /** + * Returns a new {@code ForkJoinTask} that performs the {@code run} + * method of the given {@code Runnable} as its action, and returns + * the given result upon {@link #join}. + * + * @param runnable the runnable action + * @param result the result upon completion + * @return the task + */ + public static ForkJoinTask adapt(Runnable runnable, T result) { + return new AdaptedRunnable(runnable, result); + } + + /** + * Returns a new {@code ForkJoinTask} that performs the {@code call} + * method of the given {@code Callable} as its action, and returns + * its result upon {@link #join}, translating any checked exceptions + * encountered into {@code RuntimeException}. + * + * @param callable the callable action + * @return the task + */ + public static ForkJoinTask adapt(Callable callable) { + return new AdaptedCallable(callable); + } + + // Serialization support + + private static final long serialVersionUID = -7721805057305804111L; + + /** + * Saves the state to a stream (that is, serializes it). + * + * @serialData the current run status and the exception thrown + * during execution, or {@code null} if none + * @param s the stream + */ + private void writeObject(java.io.ObjectOutputStream s) + throws java.io.IOException { + s.defaultWriteObject(); + s.writeObject(getException()); + } + + /** + * Reconstitutes the instance from a stream (that is, deserializes it). + * + * @param s the stream + */ + private void readObject(java.io.ObjectInputStream s) + throws java.io.IOException, ClassNotFoundException { + s.defaultReadObject(); + Object ex = s.readObject(); + if (ex != null) + setExceptionalCompletion((Throwable)ex); + } + + // Unsafe mechanics + private static final sun.misc.Unsafe UNSAFE; + private static final long statusOffset; + static { + exceptionTableLock = new ReentrantLock(); + exceptionTableRefQueue = new ReferenceQueue(); + exceptionTable = new ExceptionNode[EXCEPTION_MAP_CAPACITY]; + try { + UNSAFE = sun.misc.Unsafe.getUnsafe(); + statusOffset = UNSAFE.objectFieldOffset + (ForkJoinTask.class.getDeclaredField("status")); + } catch (Exception e) { + throw new Error(e); + } + } + +} diff -r e1953d8b8338 -r c8af252ea9eb rt/emul/compact/src/main/java/java/util/concurrent/ForkJoinWorkerThread.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/ForkJoinWorkerThread.java Sat Mar 19 10:48:29 2016 +0100 @@ -0,0 +1,998 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +package java.util.concurrent; + +import java.util.Collection; +import java.util.concurrent.RejectedExecutionException; + +/** + * A thread managed by a {@link ForkJoinPool}, which executes + * {@link ForkJoinTask}s. + * This class is subclassable solely for the sake of adding + * functionality -- there are no overridable methods dealing with + * scheduling or execution. However, you can override initialization + * and termination methods surrounding the main task processing loop. + * If you do create such a subclass, you will also need to supply a + * custom {@link ForkJoinPool.ForkJoinWorkerThreadFactory} to use it + * in a {@code ForkJoinPool}. + * + * @since 1.7 + * @author Doug Lea + */ +public class ForkJoinWorkerThread extends Thread { + /* + * Overview: + * + * ForkJoinWorkerThreads are managed by ForkJoinPools and perform + * ForkJoinTasks. This class includes bookkeeping in support of + * worker activation, suspension, and lifecycle control described + * in more detail in the internal documentation of class + * ForkJoinPool. And as described further below, this class also + * includes special-cased support for some ForkJoinTask + * methods. But the main mechanics involve work-stealing: + * + * Work-stealing queues are special forms of Deques that support + * only three of the four possible end-operations -- push, pop, + * and deq (aka steal), under the further constraints that push + * and pop are called only from the owning thread, while deq may + * be called from other threads. (If you are unfamiliar with + * them, you probably want to read Herlihy and Shavit's book "The + * Art of Multiprocessor programming", chapter 16 describing these + * in more detail before proceeding.) The main work-stealing + * queue design is roughly similar to those in the papers "Dynamic + * Circular Work-Stealing Deque" by Chase and Lev, SPAA 2005 + * (http://research.sun.com/scalable/pubs/index.html) and + * "Idempotent work stealing" by Michael, Saraswat, and Vechev, + * PPoPP 2009 (http://portal.acm.org/citation.cfm?id=1504186). + * The main differences ultimately stem from gc requirements that + * we null out taken slots as soon as we can, to maintain as small + * a footprint as possible even in programs generating huge + * numbers of tasks. To accomplish this, we shift the CAS + * arbitrating pop vs deq (steal) from being on the indices + * ("queueBase" and "queueTop") to the slots themselves (mainly + * via method "casSlotNull()"). So, both a successful pop and deq + * mainly entail a CAS of a slot from non-null to null. Because + * we rely on CASes of references, we do not need tag bits on + * queueBase or queueTop. They are simple ints as used in any + * circular array-based queue (see for example ArrayDeque). + * Updates to the indices must still be ordered in a way that + * guarantees that queueTop == queueBase means the queue is empty, + * but otherwise may err on the side of possibly making the queue + * appear nonempty when a push, pop, or deq have not fully + * committed. Note that this means that the deq operation, + * considered individually, is not wait-free. One thief cannot + * successfully continue until another in-progress one (or, if + * previously empty, a push) completes. However, in the + * aggregate, we ensure at least probabilistic non-blockingness. + * If an attempted steal fails, a thief always chooses a different + * random victim target to try next. So, in order for one thief to + * progress, it suffices for any in-progress deq or new push on + * any empty queue to complete. + * + * This approach also enables support for "async mode" where local + * task processing is in FIFO, not LIFO order; simply by using a + * version of deq rather than pop when locallyFifo is true (as set + * by the ForkJoinPool). This allows use in message-passing + * frameworks in which tasks are never joined. However neither + * mode considers affinities, loads, cache localities, etc, so + * rarely provide the best possible performance on a given + * machine, but portably provide good throughput by averaging over + * these factors. (Further, even if we did try to use such + * information, we do not usually have a basis for exploiting + * it. For example, some sets of tasks profit from cache + * affinities, but others are harmed by cache pollution effects.) + * + * When a worker would otherwise be blocked waiting to join a + * task, it first tries a form of linear helping: Each worker + * records (in field currentSteal) the most recent task it stole + * from some other worker. Plus, it records (in field currentJoin) + * the task it is currently actively joining. Method joinTask uses + * these markers to try to find a worker to help (i.e., steal back + * a task from and execute it) that could hasten completion of the + * actively joined task. In essence, the joiner executes a task + * that would be on its own local deque had the to-be-joined task + * not been stolen. This may be seen as a conservative variant of + * the approach in Wagner & Calder "Leapfrogging: a portable + * technique for implementing efficient futures" SIGPLAN Notices, + * 1993 (http://portal.acm.org/citation.cfm?id=155354). It differs + * in that: (1) We only maintain dependency links across workers + * upon steals, rather than use per-task bookkeeping. This may + * require a linear scan of workers array to locate stealers, but + * usually doesn't because stealers leave hints (that may become + * stale/wrong) of where to locate them. This isolates cost to + * when it is needed, rather than adding to per-task overhead. + * (2) It is "shallow", ignoring nesting and potentially cyclic + * mutual steals. (3) It is intentionally racy: field currentJoin + * is updated only while actively joining, which means that we + * miss links in the chain during long-lived tasks, GC stalls etc + * (which is OK since blocking in such cases is usually a good + * idea). (4) We bound the number of attempts to find work (see + * MAX_HELP) and fall back to suspending the worker and if + * necessary replacing it with another. + * + * Efficient implementation of these algorithms currently relies + * on an uncomfortable amount of "Unsafe" mechanics. To maintain + * correct orderings, reads and writes of variable queueBase + * require volatile ordering. Variable queueTop need not be + * volatile because non-local reads always follow those of + * queueBase. Similarly, because they are protected by volatile + * queueBase reads, reads of the queue array and its slots by + * other threads do not need volatile load semantics, but writes + * (in push) require store order and CASes (in pop and deq) + * require (volatile) CAS semantics. (Michael, Saraswat, and + * Vechev's algorithm has similar properties, but without support + * for nulling slots.) Since these combinations aren't supported + * using ordinary volatiles, the only way to accomplish these + * efficiently is to use direct Unsafe calls. (Using external + * AtomicIntegers and AtomicReferenceArrays for the indices and + * array is significantly slower because of memory locality and + * indirection effects.) + * + * Further, performance on most platforms is very sensitive to + * placement and sizing of the (resizable) queue array. Even + * though these queues don't usually become all that big, the + * initial size must be large enough to counteract cache + * contention effects across multiple queues (especially in the + * presence of GC cardmarking). Also, to improve thread-locality, + * queues are initialized after starting. + */ + + /** + * Mask for pool indices encoded as shorts + */ + private static final int SMASK = 0xffff; + + /** + * Capacity of work-stealing queue array upon initialization. + * Must be a power of two. Initial size must be at least 4, but is + * padded to minimize cache effects. + */ + private static final int INITIAL_QUEUE_CAPACITY = 1 << 13; + + /** + * Maximum size for queue array. Must be a power of two + * less than or equal to 1 << (31 - width of array entry) to + * ensure lack of index wraparound, but is capped at a lower + * value to help users trap runaway computations. + */ + private static final int MAXIMUM_QUEUE_CAPACITY = 1 << 24; // 16M + + /** + * The work-stealing queue array. Size must be a power of two. + * Initialized when started (as oposed to when constructed), to + * improve memory locality. + */ + ForkJoinTask[] queue; + + /** + * The pool this thread works in. Accessed directly by ForkJoinTask. + */ + final ForkJoinPool pool; + + /** + * Index (mod queue.length) of next queue slot to push to or pop + * from. It is written only by owner thread, and accessed by other + * threads only after reading (volatile) queueBase. Both queueTop + * and queueBase are allowed to wrap around on overflow, but + * (queueTop - queueBase) still estimates size. + */ + int queueTop; + + /** + * Index (mod queue.length) of least valid queue slot, which is + * always the next position to steal from if nonempty. + */ + volatile int queueBase; + + /** + * The index of most recent stealer, used as a hint to avoid + * traversal in method helpJoinTask. This is only a hint because a + * worker might have had multiple steals and this only holds one + * of them (usually the most current). Declared non-volatile, + * relying on other prevailing sync to keep reasonably current. + */ + int stealHint; + + /** + * Index of this worker in pool array. Set once by pool before + * running, and accessed directly by pool to locate this worker in + * its workers array. + */ + final int poolIndex; + + /** + * Encoded record for pool task waits. Usages are always + * surrounded by volatile reads/writes + */ + int nextWait; + + /** + * Complement of poolIndex, offset by count of entries of task + * waits. Accessed by ForkJoinPool to manage event waiters. + */ + volatile int eventCount; + + /** + * Seed for random number generator for choosing steal victims. + * Uses Marsaglia xorshift. Must be initialized as nonzero. + */ + int seed; + + /** + * Number of steals. Directly accessed (and reset) by pool when + * idle. + */ + int stealCount; + + /** + * True if this worker should or did terminate + */ + volatile boolean terminate; + + /** + * Set to true before LockSupport.park; false on return + */ + volatile boolean parked; + + /** + * True if use local fifo, not default lifo, for local polling. + * Shadows value from ForkJoinPool. + */ + final boolean locallyFifo; + + /** + * The task most recently stolen from another worker (or + * submission queue). All uses are surrounded by enough volatile + * reads/writes to maintain as non-volatile. + */ + ForkJoinTask currentSteal; + + /** + * The task currently being joined, set only when actively trying + * to help other stealers in helpJoinTask. All uses are surrounded + * by enough volatile reads/writes to maintain as non-volatile. + */ + ForkJoinTask currentJoin; + + /** + * Creates a ForkJoinWorkerThread operating in the given pool. + * + * @param pool the pool this thread works in + * @throws NullPointerException if pool is null + */ + protected ForkJoinWorkerThread(ForkJoinPool pool) { + super(pool.nextWorkerName()); + this.pool = pool; + int k = pool.registerWorker(this); + poolIndex = k; + eventCount = ~k & SMASK; // clear wait count + locallyFifo = pool.locallyFifo; + Thread.UncaughtExceptionHandler ueh = pool.ueh; + if (ueh != null) + setUncaughtExceptionHandler(ueh); + setDaemon(true); + } + + // Public methods + + /** + * Returns the pool hosting this thread. + * + * @return the pool + */ + public ForkJoinPool getPool() { + return pool; + } + + /** + * Returns the index number of this thread in its pool. The + * returned value ranges from zero to the maximum number of + * threads (minus one) that have ever been created in the pool. + * This method may be useful for applications that track status or + * collect results per-worker rather than per-task. + * + * @return the index number + */ + public int getPoolIndex() { + return poolIndex; + } + + // Randomization + + /** + * Computes next value for random victim probes and backoffs. + * Scans don't require a very high quality generator, but also not + * a crummy one. Marsaglia xor-shift is cheap and works well + * enough. Note: This is manually inlined in FJP.scan() to avoid + * writes inside busy loops. + */ + private int nextSeed() { + int r = seed; + r ^= r << 13; + r ^= r >>> 17; + r ^= r << 5; + return seed = r; + } + + // Run State management + + /** + * Initializes internal state after construction but before + * processing any tasks. If you override this method, you must + * invoke {@code super.onStart()} at the beginning of the method. + * Initialization requires care: Most fields must have legal + * default values, to ensure that attempted accesses from other + * threads work correctly even before this thread starts + * processing tasks. + */ + protected void onStart() { + queue = new ForkJoinTask[INITIAL_QUEUE_CAPACITY]; + int r = pool.workerSeedGenerator.nextInt(); + seed = (r == 0) ? 1 : r; // must be nonzero + } + + /** + * Performs cleanup associated with termination of this worker + * thread. If you override this method, you must invoke + * {@code super.onTermination} at the end of the overridden method. + * + * @param exception the exception causing this thread to abort due + * to an unrecoverable error, or {@code null} if completed normally + */ + protected void onTermination(Throwable exception) { + try { + terminate = true; + cancelTasks(); + pool.deregisterWorker(this, exception); + } catch (Throwable ex) { // Shouldn't ever happen + if (exception == null) // but if so, at least rethrown + exception = ex; + } finally { + if (exception != null) + UNSAFE.throwException(exception); + } + } + + /** + * This method is required to be public, but should never be + * called explicitly. It performs the main run loop to execute + * {@link ForkJoinTask}s. + */ + public void run() { + Throwable exception = null; + try { + onStart(); + pool.work(this); + } catch (Throwable ex) { + exception = ex; + } finally { + onTermination(exception); + } + } + + /* + * Intrinsics-based atomic writes for queue slots. These are + * basically the same as methods in AtomicReferenceArray, but + * specialized for (1) ForkJoinTask elements (2) requirement that + * nullness and bounds checks have already been performed by + * callers and (3) effective offsets are known not to overflow + * from int to long (because of MAXIMUM_QUEUE_CAPACITY). We don't + * need corresponding version for reads: plain array reads are OK + * because they are protected by other volatile reads and are + * confirmed by CASes. + * + * Most uses don't actually call these methods, but instead + * contain inlined forms that enable more predictable + * optimization. We don't define the version of write used in + * pushTask at all, but instead inline there a store-fenced array + * slot write. + * + * Also in most methods, as a performance (not correctness) issue, + * we'd like to encourage compilers not to arbitrarily postpone + * setting queueTop after writing slot. Currently there is no + * intrinsic for arranging this, but using Unsafe putOrderedInt + * may be a preferable strategy on some compilers even though its + * main effect is a pre-, not post- fence. To simplify possible + * changes, the option is left in comments next to the associated + * assignments. + */ + + /** + * CASes slot i of array q from t to null. Caller must ensure q is + * non-null and index is in range. + */ + private static final boolean casSlotNull(ForkJoinTask[] q, int i, + ForkJoinTask t) { + return UNSAFE.compareAndSwapObject(q, (i << ASHIFT) + ABASE, t, null); + } + + /** + * Performs a volatile write of the given task at given slot of + * array q. Caller must ensure q is non-null and index is in + * range. This method is used only during resets and backouts. + */ + private static final void writeSlot(ForkJoinTask[] q, int i, + ForkJoinTask t) { + UNSAFE.putObjectVolatile(q, (i << ASHIFT) + ABASE, t); + } + + // queue methods + + /** + * Pushes a task. Call only from this thread. + * + * @param t the task. Caller must ensure non-null. + */ + final void pushTask(ForkJoinTask t) { + ForkJoinTask[] q; int s, m; + if ((q = queue) != null) { // ignore if queue removed + long u = (((s = queueTop) & (m = q.length - 1)) << ASHIFT) + ABASE; + UNSAFE.putOrderedObject(q, u, t); + queueTop = s + 1; // or use putOrderedInt + if ((s -= queueBase) <= 2) + pool.signalWork(); + else if (s == m) + growQueue(); + } + } + + /** + * Creates or doubles queue array. Transfers elements by + * emulating steals (deqs) from old array and placing, oldest + * first, into new array. + */ + private void growQueue() { + ForkJoinTask[] oldQ = queue; + int size = oldQ != null ? oldQ.length << 1 : INITIAL_QUEUE_CAPACITY; + if (size > MAXIMUM_QUEUE_CAPACITY) + throw new RejectedExecutionException("Queue capacity exceeded"); + if (size < INITIAL_QUEUE_CAPACITY) + size = INITIAL_QUEUE_CAPACITY; + ForkJoinTask[] q = queue = new ForkJoinTask[size]; + int mask = size - 1; + int top = queueTop; + int oldMask; + if (oldQ != null && (oldMask = oldQ.length - 1) >= 0) { + for (int b = queueBase; b != top; ++b) { + long u = ((b & oldMask) << ASHIFT) + ABASE; + Object x = UNSAFE.getObjectVolatile(oldQ, u); + if (x != null && UNSAFE.compareAndSwapObject(oldQ, u, x, null)) + UNSAFE.putObjectVolatile + (q, ((b & mask) << ASHIFT) + ABASE, x); + } + } + } + + /** + * Tries to take a task from the base of the queue, failing if + * empty or contended. Note: Specializations of this code appear + * in locallyDeqTask and elsewhere. + * + * @return a task, or null if none or contended + */ + final ForkJoinTask deqTask() { + ForkJoinTask t; ForkJoinTask[] q; int b, i; + if (queueTop != (b = queueBase) && + (q = queue) != null && // must read q after b + (i = (q.length - 1) & b) >= 0 && + (t = q[i]) != null && queueBase == b && + UNSAFE.compareAndSwapObject(q, (i << ASHIFT) + ABASE, t, null)) { + queueBase = b + 1; + return t; + } + return null; + } + + /** + * Tries to take a task from the base of own queue. Called only + * by this thread. + * + * @return a task, or null if none + */ + final ForkJoinTask locallyDeqTask() { + ForkJoinTask t; int m, b, i; + ForkJoinTask[] q = queue; + if (q != null && (m = q.length - 1) >= 0) { + while (queueTop != (b = queueBase)) { + if ((t = q[i = m & b]) != null && + queueBase == b && + UNSAFE.compareAndSwapObject(q, (i << ASHIFT) + ABASE, + t, null)) { + queueBase = b + 1; + return t; + } + } + } + return null; + } + + /** + * Returns a popped task, or null if empty. + * Called only by this thread. + */ + private ForkJoinTask popTask() { + int m; + ForkJoinTask[] q = queue; + if (q != null && (m = q.length - 1) >= 0) { + for (int s; (s = queueTop) != queueBase;) { + int i = m & --s; + long u = (i << ASHIFT) + ABASE; // raw offset + ForkJoinTask t = q[i]; + if (t == null) // lost to stealer + break; + if (UNSAFE.compareAndSwapObject(q, u, t, null)) { + queueTop = s; // or putOrderedInt + return t; + } + } + } + return null; + } + + /** + * Specialized version of popTask to pop only if topmost element + * is the given task. Called only by this thread. + * + * @param t the task. Caller must ensure non-null. + */ + final boolean unpushTask(ForkJoinTask t) { + ForkJoinTask[] q; + int s; + if ((q = queue) != null && (s = queueTop) != queueBase && + UNSAFE.compareAndSwapObject + (q, (((q.length - 1) & --s) << ASHIFT) + ABASE, t, null)) { + queueTop = s; // or putOrderedInt + return true; + } + return false; + } + + /** + * Returns next task, or null if empty or contended. + */ + final ForkJoinTask peekTask() { + int m; + ForkJoinTask[] q = queue; + if (q == null || (m = q.length - 1) < 0) + return null; + int i = locallyFifo ? queueBase : (queueTop - 1); + return q[i & m]; + } + + // Support methods for ForkJoinPool + + /** + * Runs the given task, plus any local tasks until queue is empty + */ + final void execTask(ForkJoinTask t) { + currentSteal = t; + for (;;) { + if (t != null) + t.doExec(); + if (queueTop == queueBase) + break; + t = locallyFifo ? locallyDeqTask() : popTask(); + } + ++stealCount; + currentSteal = null; + } + + /** + * Removes and cancels all tasks in queue. Can be called from any + * thread. + */ + final void cancelTasks() { + ForkJoinTask cj = currentJoin; // try to cancel ongoing tasks + if (cj != null && cj.status >= 0) + cj.cancelIgnoringExceptions(); + ForkJoinTask cs = currentSteal; + if (cs != null && cs.status >= 0) + cs.cancelIgnoringExceptions(); + while (queueBase != queueTop) { + ForkJoinTask t = deqTask(); + if (t != null) + t.cancelIgnoringExceptions(); + } + } + + /** + * Drains tasks to given collection c. + * + * @return the number of tasks drained + */ + final int drainTasksTo(Collection> c) { + int n = 0; + while (queueBase != queueTop) { + ForkJoinTask t = deqTask(); + if (t != null) { + c.add(t); + ++n; + } + } + return n; + } + + // Support methods for ForkJoinTask + + /** + * Returns an estimate of the number of tasks in the queue. + */ + final int getQueueSize() { + return queueTop - queueBase; + } + + /** + * Gets and removes a local task. + * + * @return a task, if available + */ + final ForkJoinTask pollLocalTask() { + return locallyFifo ? locallyDeqTask() : popTask(); + } + + /** + * Gets and removes a local or stolen task. + * + * @return a task, if available + */ + final ForkJoinTask pollTask() { + ForkJoinWorkerThread[] ws; + ForkJoinTask t = pollLocalTask(); + if (t != null || (ws = pool.workers) == null) + return t; + int n = ws.length; // cheap version of FJP.scan + int steps = n << 1; + int r = nextSeed(); + int i = 0; + while (i < steps) { + ForkJoinWorkerThread w = ws[(i++ + r) & (n - 1)]; + if (w != null && w.queueBase != w.queueTop && w.queue != null) { + if ((t = w.deqTask()) != null) + return t; + i = 0; + } + } + return null; + } + + /** + * The maximum stolen->joining link depth allowed in helpJoinTask, + * as well as the maximum number of retries (allowing on average + * one staleness retry per level) per attempt to instead try + * compensation. Depths for legitimate chains are unbounded, but + * we use a fixed constant to avoid (otherwise unchecked) cycles + * and bound staleness of traversal parameters at the expense of + * sometimes blocking when we could be helping. + */ + private static final int MAX_HELP = 16; + + /** + * Possibly runs some tasks and/or blocks, until joinMe is done. + * + * @param joinMe the task to join + * @return completion status on exit + */ + final int joinTask(ForkJoinTask joinMe) { + ForkJoinTask prevJoin = currentJoin; + currentJoin = joinMe; + for (int s, retries = MAX_HELP;;) { + if ((s = joinMe.status) < 0) { + currentJoin = prevJoin; + return s; + } + if (retries > 0) { + if (queueTop != queueBase) { + if (!localHelpJoinTask(joinMe)) + retries = 0; // cannot help + } + else if (retries == MAX_HELP >>> 1) { + --retries; // check uncommon case + if (tryDeqAndExec(joinMe) >= 0) + Thread.yield(); // for politeness + } + else + retries = helpJoinTask(joinMe) ? MAX_HELP : retries - 1; + } + else { + retries = MAX_HELP; // restart if not done + pool.tryAwaitJoin(joinMe); + } + } + } + + /** + * If present, pops and executes the given task, or any other + * cancelled task + * + * @return false if any other non-cancelled task exists in local queue + */ + private boolean localHelpJoinTask(ForkJoinTask joinMe) { + int s, i; ForkJoinTask[] q; ForkJoinTask t; + if ((s = queueTop) != queueBase && (q = queue) != null && + (i = (q.length - 1) & --s) >= 0 && + (t = q[i]) != null) { + if (t != joinMe && t.status >= 0) + return false; + if (UNSAFE.compareAndSwapObject + (q, (i << ASHIFT) + ABASE, t, null)) { + queueTop = s; // or putOrderedInt + t.doExec(); + } + } + return true; + } + + /** + * Tries to locate and execute tasks for a stealer of the given + * task, or in turn one of its stealers, Traces + * currentSteal->currentJoin links looking for a thread working on + * a descendant of the given task and with a non-empty queue to + * steal back and execute tasks from. The implementation is very + * branchy to cope with potential inconsistencies or loops + * encountering chains that are stale, unknown, or of length + * greater than MAX_HELP links. All of these cases are dealt with + * by just retrying by caller. + * + * @param joinMe the task to join + * @param canSteal true if local queue is empty + * @return true if ran a task + */ + private boolean helpJoinTask(ForkJoinTask joinMe) { + boolean helped = false; + int m = pool.scanGuard & SMASK; + ForkJoinWorkerThread[] ws = pool.workers; + if (ws != null && ws.length > m && joinMe.status >= 0) { + int levels = MAX_HELP; // remaining chain length + ForkJoinTask task = joinMe; // base of chain + outer:for (ForkJoinWorkerThread thread = this;;) { + // Try to find v, the stealer of task, by first using hint + ForkJoinWorkerThread v = ws[thread.stealHint & m]; + if (v == null || v.currentSteal != task) { + for (int j = 0; ;) { // search array + if ((v = ws[j]) != null && v.currentSteal == task) { + thread.stealHint = j; + break; // save hint for next time + } + if (++j > m) + break outer; // can't find stealer + } + } + // Try to help v, using specialized form of deqTask + for (;;) { + ForkJoinTask[] q; int b, i; + if (joinMe.status < 0) + break outer; + if ((b = v.queueBase) == v.queueTop || + (q = v.queue) == null || + (i = (q.length-1) & b) < 0) + break; // empty + long u = (i << ASHIFT) + ABASE; + ForkJoinTask t = q[i]; + if (task.status < 0) + break outer; // stale + if (t != null && v.queueBase == b && + UNSAFE.compareAndSwapObject(q, u, t, null)) { + v.queueBase = b + 1; + v.stealHint = poolIndex; + ForkJoinTask ps = currentSteal; + currentSteal = t; + t.doExec(); + currentSteal = ps; + helped = true; + } + } + // Try to descend to find v's stealer + ForkJoinTask next = v.currentJoin; + if (--levels > 0 && task.status >= 0 && + next != null && next != task) { + task = next; + thread = v; + } + else + break; // max levels, stale, dead-end, or cyclic + } + } + return helped; + } + + /** + * Performs an uncommon case for joinTask: If task t is at base of + * some workers queue, steals and executes it. + * + * @param t the task + * @return t's status + */ + private int tryDeqAndExec(ForkJoinTask t) { + int m = pool.scanGuard & SMASK; + ForkJoinWorkerThread[] ws = pool.workers; + if (ws != null && ws.length > m && t.status >= 0) { + for (int j = 0; j <= m; ++j) { + ForkJoinTask[] q; int b, i; + ForkJoinWorkerThread v = ws[j]; + if (v != null && + (b = v.queueBase) != v.queueTop && + (q = v.queue) != null && + (i = (q.length - 1) & b) >= 0 && + q[i] == t) { + long u = (i << ASHIFT) + ABASE; + if (v.queueBase == b && + UNSAFE.compareAndSwapObject(q, u, t, null)) { + v.queueBase = b + 1; + v.stealHint = poolIndex; + ForkJoinTask ps = currentSteal; + currentSteal = t; + t.doExec(); + currentSteal = ps; + } + break; + } + } + } + return t.status; + } + + /** + * Implements ForkJoinTask.getSurplusQueuedTaskCount(). Returns + * an estimate of the number of tasks, offset by a function of + * number of idle workers. + * + * This method provides a cheap heuristic guide for task + * partitioning when programmers, frameworks, tools, or languages + * have little or no idea about task granularity. In essence by + * offering this method, we ask users only about tradeoffs in + * overhead vs expected throughput and its variance, rather than + * how finely to partition tasks. + * + * In a steady state strict (tree-structured) computation, each + * thread makes available for stealing enough tasks for other + * threads to remain active. Inductively, if all threads play by + * the same rules, each thread should make available only a + * constant number of tasks. + * + * The minimum useful constant is just 1. But using a value of 1 + * would require immediate replenishment upon each steal to + * maintain enough tasks, which is infeasible. Further, + * partitionings/granularities of offered tasks should minimize + * steal rates, which in general means that threads nearer the top + * of computation tree should generate more than those nearer the + * bottom. In perfect steady state, each thread is at + * approximately the same level of computation tree. However, + * producing extra tasks amortizes the uncertainty of progress and + * diffusion assumptions. + * + * So, users will want to use values larger, but not much larger + * than 1 to both smooth over transient shortages and hedge + * against uneven progress; as traded off against the cost of + * extra task overhead. We leave the user to pick a threshold + * value to compare with the results of this call to guide + * decisions, but recommend values such as 3. + * + * When all threads are active, it is on average OK to estimate + * surplus strictly locally. In steady-state, if one thread is + * maintaining say 2 surplus tasks, then so are others. So we can + * just use estimated queue length (although note that (queueTop - + * queueBase) can be an overestimate because of stealers lagging + * increments of queueBase). However, this strategy alone leads + * to serious mis-estimates in some non-steady-state conditions + * (ramp-up, ramp-down, other stalls). We can detect many of these + * by further considering the number of "idle" threads, that are + * known to have zero queued tasks, so compensate by a factor of + * (#idle/#active) threads. + */ + final int getEstimatedSurplusTaskCount() { + return queueTop - queueBase - pool.idlePerActive(); + } + + /** + * Runs tasks until {@code pool.isQuiescent()}. We piggyback on + * pool's active count ctl maintenance, but rather than blocking + * when tasks cannot be found, we rescan until all others cannot + * find tasks either. The bracketing by pool quiescerCounts + * updates suppresses pool auto-shutdown mechanics that could + * otherwise prematurely terminate the pool because all threads + * appear to be inactive. + */ + final void helpQuiescePool() { + boolean active = true; + ForkJoinTask ps = currentSteal; // to restore below + ForkJoinPool p = pool; + p.addQuiescerCount(1); + for (;;) { + ForkJoinWorkerThread[] ws = p.workers; + ForkJoinWorkerThread v = null; + int n; + if (queueTop != queueBase) + v = this; + else if (ws != null && (n = ws.length) > 1) { + ForkJoinWorkerThread w; + int r = nextSeed(); // cheap version of FJP.scan + int steps = n << 1; + for (int i = 0; i < steps; ++i) { + if ((w = ws[(i + r) & (n - 1)]) != null && + w.queueBase != w.queueTop) { + v = w; + break; + } + } + } + if (v != null) { + ForkJoinTask t; + if (!active) { + active = true; + p.addActiveCount(1); + } + if ((t = (v != this) ? v.deqTask() : + locallyFifo ? locallyDeqTask() : popTask()) != null) { + currentSteal = t; + t.doExec(); + currentSteal = ps; + } + } + else { + if (active) { + active = false; + p.addActiveCount(-1); + } + if (p.isQuiescent()) { + p.addActiveCount(1); + p.addQuiescerCount(-1); + break; + } + } + } + } + + // Unsafe mechanics + private static final sun.misc.Unsafe UNSAFE; + private static final long ABASE; + private static final int ASHIFT; + + static { + int s; + try { + UNSAFE = sun.misc.Unsafe.getUnsafe(); + Class a = ForkJoinTask[].class; + ABASE = UNSAFE.arrayBaseOffset(a); + s = UNSAFE.arrayIndexScale(a); + } catch (Exception e) { + throw new Error(e); + } + if ((s & (s-1)) != 0) + throw new Error("data type scale not a power of two"); + ASHIFT = 31 - Integer.numberOfLeadingZeros(s); + } + +} diff -r e1953d8b8338 -r c8af252ea9eb rt/emul/compact/src/main/java/java/util/concurrent/Future.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/Future.java Sat Mar 19 10:48:29 2016 +0100 @@ -0,0 +1,169 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +package java.util.concurrent; + +/** + * A Future represents the result of an asynchronous + * computation. Methods are provided to check if the computation is + * complete, to wait for its completion, and to retrieve the result of + * the computation. The result can only be retrieved using method + * get when the computation has completed, blocking if + * necessary until it is ready. Cancellation is performed by the + * cancel method. Additional methods are provided to + * determine if the task completed normally or was cancelled. Once a + * computation has completed, the computation cannot be cancelled. + * If you would like to use a Future for the sake + * of cancellability but not provide a usable result, you can + * declare types of the form {@code Future} and + * return null as a result of the underlying task. + * + *

+ * Sample Usage (Note that the following classes are all + * made-up.)

+ *

 {@code
+ * interface ArchiveSearcher { String search(String target); }
+ * class App {
+ *   ExecutorService executor = ...
+ *   ArchiveSearcher searcher = ...
+ *   void showSearch(final String target)
+ *       throws InterruptedException {
+ *     Future future
+ *       = executor.submit(new Callable() {
+ *         public String call() {
+ *             return searcher.search(target);
+ *         }});
+ *     displayOtherThings(); // do other things while searching
+ *     try {
+ *       displayText(future.get()); // use future
+ *     } catch (ExecutionException ex) { cleanup(); return; }
+ *   }
+ * }}
+ * + * The {@link FutureTask} class is an implementation of Future that + * implements Runnable, and so may be executed by an Executor. + * For example, the above construction with submit could be replaced by: + *
 {@code
+ *     FutureTask future =
+ *       new FutureTask(new Callable() {
+ *         public String call() {
+ *           return searcher.search(target);
+ *       }});
+ *     executor.execute(future);}
+ * + *

Memory consistency effects: Actions taken by the asynchronous computation + * happen-before + * actions following the corresponding {@code Future.get()} in another thread. + * + * @see FutureTask + * @see Executor + * @since 1.5 + * @author Doug Lea + * @param The result type returned by this Future's get method + */ +public interface Future { + + /** + * Attempts to cancel execution of this task. This attempt will + * fail if the task has already completed, has already been cancelled, + * or could not be cancelled for some other reason. If successful, + * and this task has not started when cancel is called, + * this task should never run. If the task has already started, + * then the mayInterruptIfRunning parameter determines + * whether the thread executing this task should be interrupted in + * an attempt to stop the task. + * + *

After this method returns, subsequent calls to {@link #isDone} will + * always return true. Subsequent calls to {@link #isCancelled} + * will always return true if this method returned true. + * + * @param mayInterruptIfRunning true if the thread executing this + * task should be interrupted; otherwise, in-progress tasks are allowed + * to complete + * @return false if the task could not be cancelled, + * typically because it has already completed normally; + * true otherwise + */ + boolean cancel(boolean mayInterruptIfRunning); + + /** + * Returns true if this task was cancelled before it completed + * normally. + * + * @return true if this task was cancelled before it completed + */ + boolean isCancelled(); + + /** + * Returns true if this task completed. + * + * Completion may be due to normal termination, an exception, or + * cancellation -- in all of these cases, this method will return + * true. + * + * @return true if this task completed + */ + boolean isDone(); + + /** + * Waits if necessary for the computation to complete, and then + * retrieves its result. + * + * @return the computed result + * @throws CancellationException if the computation was cancelled + * @throws ExecutionException if the computation threw an + * exception + * @throws InterruptedException if the current thread was interrupted + * while waiting + */ + V get() throws InterruptedException, ExecutionException; + + /** + * Waits if necessary for at most the given time for the computation + * to complete, and then retrieves its result, if available. + * + * @param timeout the maximum time to wait + * @param unit the time unit of the timeout argument + * @return the computed result + * @throws CancellationException if the computation was cancelled + * @throws ExecutionException if the computation threw an + * exception + * @throws InterruptedException if the current thread was interrupted + * while waiting + * @throws TimeoutException if the wait timed out + */ + V get(long timeout, TimeUnit unit) + throws InterruptedException, ExecutionException, TimeoutException; +} diff -r e1953d8b8338 -r c8af252ea9eb rt/emul/compact/src/main/java/java/util/concurrent/FutureTask.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/FutureTask.java Sat Mar 19 10:48:29 2016 +0100 @@ -0,0 +1,360 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +package java.util.concurrent; +import java.util.concurrent.locks.*; + +/** + * A cancellable asynchronous computation. This class provides a base + * implementation of {@link Future}, with methods to start and cancel + * a computation, query to see if the computation is complete, and + * retrieve the result of the computation. The result can only be + * retrieved when the computation has completed; the get + * method will block if the computation has not yet completed. Once + * the computation has completed, the computation cannot be restarted + * or cancelled. + * + *

A FutureTask can be used to wrap a {@link Callable} or + * {@link java.lang.Runnable} object. Because FutureTask + * implements Runnable, a FutureTask can be + * submitted to an {@link Executor} for execution. + * + *

In addition to serving as a standalone class, this class provides + * protected functionality that may be useful when creating + * customized task classes. + * + * @since 1.5 + * @author Doug Lea + * @param The result type returned by this FutureTask's get method + */ +public class FutureTask implements RunnableFuture { + /** Synchronization control for FutureTask */ + private final Sync sync; + + /** + * Creates a FutureTask that will, upon running, execute the + * given Callable. + * + * @param callable the callable task + * @throws NullPointerException if callable is null + */ + public FutureTask(Callable callable) { + if (callable == null) + throw new NullPointerException(); + sync = new Sync(callable); + } + + /** + * Creates a FutureTask that will, upon running, execute the + * given Runnable, and arrange that get will return the + * given result on successful completion. + * + * @param runnable the runnable task + * @param result the result to return on successful completion. If + * you don't need a particular result, consider using + * constructions of the form: + * {@code Future f = new FutureTask(runnable, null)} + * @throws NullPointerException if runnable is null + */ + public FutureTask(Runnable runnable, V result) { + sync = new Sync(Executors.callable(runnable, result)); + } + + public boolean isCancelled() { + return sync.innerIsCancelled(); + } + + public boolean isDone() { + return sync.innerIsDone(); + } + + public boolean cancel(boolean mayInterruptIfRunning) { + return sync.innerCancel(mayInterruptIfRunning); + } + + /** + * @throws CancellationException {@inheritDoc} + */ + public V get() throws InterruptedException, ExecutionException { + return sync.innerGet(); + } + + /** + * @throws CancellationException {@inheritDoc} + */ + public V get(long timeout, TimeUnit unit) + throws InterruptedException, ExecutionException, TimeoutException { + return sync.innerGet(unit.toNanos(timeout)); + } + + /** + * Protected method invoked when this task transitions to state + * isDone (whether normally or via cancellation). The + * default implementation does nothing. Subclasses may override + * this method to invoke completion callbacks or perform + * bookkeeping. Note that you can query status inside the + * implementation of this method to determine whether this task + * has been cancelled. + */ + protected void done() { } + + /** + * Sets the result of this Future to the given value unless + * this future has already been set or has been cancelled. + * This method is invoked internally by the run method + * upon successful completion of the computation. + * @param v the value + */ + protected void set(V v) { + sync.innerSet(v); + } + + /** + * Causes this future to report an ExecutionException + * with the given throwable as its cause, unless this Future has + * already been set or has been cancelled. + * This method is invoked internally by the run method + * upon failure of the computation. + * @param t the cause of failure + */ + protected void setException(Throwable t) { + sync.innerSetException(t); + } + + // The following (duplicated) doc comment can be removed once + // + // 6270645: Javadoc comments should be inherited from most derived + // superinterface or superclass + // is fixed. + /** + * Sets this Future to the result of its computation + * unless it has been cancelled. + */ + public void run() { + sync.innerRun(); + } + + /** + * Executes the computation without setting its result, and then + * resets this Future to initial state, failing to do so if the + * computation encounters an exception or is cancelled. This is + * designed for use with tasks that intrinsically execute more + * than once. + * @return true if successfully run and reset + */ + protected boolean runAndReset() { + return sync.innerRunAndReset(); + } + + /** + * Synchronization control for FutureTask. Note that this must be + * a non-static inner class in order to invoke the protected + * done method. For clarity, all inner class support + * methods are same as outer, prefixed with "inner". + * + * Uses AQS sync state to represent run status + */ + private final class Sync extends AbstractQueuedSynchronizer { + private static final long serialVersionUID = -7828117401763700385L; + + /** State value representing that task is ready to run */ + private static final int READY = 0; + /** State value representing that task is running */ + private static final int RUNNING = 1; + /** State value representing that task ran */ + private static final int RAN = 2; + /** State value representing that task was cancelled */ + private static final int CANCELLED = 4; + + /** The underlying callable */ + private final Callable callable; + /** The result to return from get() */ + private V result; + /** The exception to throw from get() */ + private Throwable exception; + + /** + * The thread running task. When nulled after set/cancel, this + * indicates that the results are accessible. Must be + * volatile, to ensure visibility upon completion. + */ + private volatile Thread runner; + + Sync(Callable callable) { + this.callable = callable; + } + + private boolean ranOrCancelled(int state) { + return (state & (RAN | CANCELLED)) != 0; + } + + /** + * Implements AQS base acquire to succeed if ran or cancelled + */ + protected int tryAcquireShared(int ignore) { + return innerIsDone() ? 1 : -1; + } + + /** + * Implements AQS base release to always signal after setting + * final done status by nulling runner thread. + */ + protected boolean tryReleaseShared(int ignore) { + runner = null; + return true; + } + + boolean innerIsCancelled() { + return getState() == CANCELLED; + } + + boolean innerIsDone() { + return ranOrCancelled(getState()) && runner == null; + } + + V innerGet() throws InterruptedException, ExecutionException { + acquireSharedInterruptibly(0); + if (getState() == CANCELLED) + throw new CancellationException(); + if (exception != null) + throw new ExecutionException(exception); + return result; + } + + V innerGet(long nanosTimeout) throws InterruptedException, ExecutionException, TimeoutException { + if (!tryAcquireSharedNanos(0, nanosTimeout)) + throw new TimeoutException(); + if (getState() == CANCELLED) + throw new CancellationException(); + if (exception != null) + throw new ExecutionException(exception); + return result; + } + + void innerSet(V v) { + for (;;) { + int s = getState(); + if (s == RAN) + return; + if (s == CANCELLED) { + // aggressively release to set runner to null, + // in case we are racing with a cancel request + // that will try to interrupt runner + releaseShared(0); + return; + } + if (compareAndSetState(s, RAN)) { + result = v; + releaseShared(0); + done(); + return; + } + } + } + + void innerSetException(Throwable t) { + for (;;) { + int s = getState(); + if (s == RAN) + return; + if (s == CANCELLED) { + // aggressively release to set runner to null, + // in case we are racing with a cancel request + // that will try to interrupt runner + releaseShared(0); + return; + } + if (compareAndSetState(s, RAN)) { + exception = t; + releaseShared(0); + done(); + return; + } + } + } + + boolean innerCancel(boolean mayInterruptIfRunning) { + for (;;) { + int s = getState(); + if (ranOrCancelled(s)) + return false; + if (compareAndSetState(s, CANCELLED)) + break; + } + if (mayInterruptIfRunning) { + Thread r = runner; + if (r != null) + r.interrupt(); + } + releaseShared(0); + done(); + return true; + } + + void innerRun() { + if (!compareAndSetState(READY, RUNNING)) + return; + + runner = Thread.currentThread(); + if (getState() == RUNNING) { // recheck after setting thread + V result; + try { + result = callable.call(); + } catch (Throwable ex) { + setException(ex); + return; + } + set(result); + } else { + releaseShared(0); // cancel + } + } + + boolean innerRunAndReset() { + if (!compareAndSetState(READY, RUNNING)) + return false; + try { + runner = Thread.currentThread(); + if (getState() == RUNNING) + callable.call(); // don't set result + runner = null; + return compareAndSetState(RUNNING, READY); + } catch (Throwable ex) { + setException(ex); + return false; + } + } + } +} diff -r e1953d8b8338 -r c8af252ea9eb rt/emul/compact/src/main/java/java/util/concurrent/LinkedBlockingDeque.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/LinkedBlockingDeque.java Sat Mar 19 10:48:29 2016 +0100 @@ -0,0 +1,1198 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +package java.util.concurrent; + +import java.util.AbstractQueue; +import java.util.Collection; +import java.util.Iterator; +import java.util.NoSuchElementException; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.ReentrantLock; + +/** + * An optionally-bounded {@linkplain BlockingDeque blocking deque} based on + * linked nodes. + * + *

The optional capacity bound constructor argument serves as a + * way to prevent excessive expansion. The capacity, if unspecified, + * is equal to {@link Integer#MAX_VALUE}. Linked nodes are + * dynamically created upon each insertion unless this would bring the + * deque above capacity. + * + *

Most operations run in constant time (ignoring time spent + * blocking). Exceptions include {@link #remove(Object) remove}, + * {@link #removeFirstOccurrence removeFirstOccurrence}, {@link + * #removeLastOccurrence removeLastOccurrence}, {@link #contains + * contains}, {@link #iterator iterator.remove()}, and the bulk + * operations, all of which run in linear time. + * + *

This class and its iterator implement all of the + * optional methods of the {@link Collection} and {@link + * Iterator} interfaces. + * + *

This class is a member of the + * + * Java Collections Framework. + * + * @since 1.6 + * @author Doug Lea + * @param the type of elements held in this collection + */ +public class LinkedBlockingDeque + extends AbstractQueue + implements BlockingDeque, java.io.Serializable { + + /* + * Implemented as a simple doubly-linked list protected by a + * single lock and using conditions to manage blocking. + * + * To implement weakly consistent iterators, it appears we need to + * keep all Nodes GC-reachable from a predecessor dequeued Node. + * That would cause two problems: + * - allow a rogue Iterator to cause unbounded memory retention + * - cause cross-generational linking of old Nodes to new Nodes if + * a Node was tenured while live, which generational GCs have a + * hard time dealing with, causing repeated major collections. + * However, only non-deleted Nodes need to be reachable from + * dequeued Nodes, and reachability does not necessarily have to + * be of the kind understood by the GC. We use the trick of + * linking a Node that has just been dequeued to itself. Such a + * self-link implicitly means to jump to "first" (for next links) + * or "last" (for prev links). + */ + + /* + * We have "diamond" multiple interface/abstract class inheritance + * here, and that introduces ambiguities. Often we want the + * BlockingDeque javadoc combined with the AbstractQueue + * implementation, so a lot of method specs are duplicated here. + */ + + private static final long serialVersionUID = -387911632671998426L; + + /** Doubly-linked list node class */ + static final class Node { + /** + * The item, or null if this node has been removed. + */ + E item; + + /** + * One of: + * - the real predecessor Node + * - this Node, meaning the predecessor is tail + * - null, meaning there is no predecessor + */ + Node prev; + + /** + * One of: + * - the real successor Node + * - this Node, meaning the successor is head + * - null, meaning there is no successor + */ + Node next; + + Node(E x) { + item = x; + } + } + + /** + * Pointer to first node. + * Invariant: (first == null && last == null) || + * (first.prev == null && first.item != null) + */ + transient Node first; + + /** + * Pointer to last node. + * Invariant: (first == null && last == null) || + * (last.next == null && last.item != null) + */ + transient Node last; + + /** Number of items in the deque */ + private transient int count; + + /** Maximum number of items in the deque */ + private final int capacity; + + /** Main lock guarding all access */ + final ReentrantLock lock = new ReentrantLock(); + + /** Condition for waiting takes */ + private final Condition notEmpty = lock.newCondition(); + + /** Condition for waiting puts */ + private final Condition notFull = lock.newCondition(); + + /** + * Creates a {@code LinkedBlockingDeque} with a capacity of + * {@link Integer#MAX_VALUE}. + */ + public LinkedBlockingDeque() { + this(Integer.MAX_VALUE); + } + + /** + * Creates a {@code LinkedBlockingDeque} with the given (fixed) capacity. + * + * @param capacity the capacity of this deque + * @throws IllegalArgumentException if {@code capacity} is less than 1 + */ + public LinkedBlockingDeque(int capacity) { + if (capacity <= 0) throw new IllegalArgumentException(); + this.capacity = capacity; + } + + /** + * Creates a {@code LinkedBlockingDeque} with a capacity of + * {@link Integer#MAX_VALUE}, initially containing the elements of + * the given collection, added in traversal order of the + * collection's iterator. + * + * @param c the collection of elements to initially contain + * @throws NullPointerException if the specified collection or any + * of its elements are null + */ + public LinkedBlockingDeque(Collection c) { + this(Integer.MAX_VALUE); + final ReentrantLock lock = this.lock; + lock.lock(); // Never contended, but necessary for visibility + try { + for (E e : c) { + if (e == null) + throw new NullPointerException(); + if (!linkLast(new Node(e))) + throw new IllegalStateException("Deque full"); + } + } finally { + lock.unlock(); + } + } + + + // Basic linking and unlinking operations, called only while holding lock + + /** + * Links node as first element, or returns false if full. + */ + private boolean linkFirst(Node node) { + // assert lock.isHeldByCurrentThread(); + if (count >= capacity) + return false; + Node f = first; + node.next = f; + first = node; + if (last == null) + last = node; + else + f.prev = node; + ++count; + notEmpty.signal(); + return true; + } + + /** + * Links node as last element, or returns false if full. + */ + private boolean linkLast(Node node) { + // assert lock.isHeldByCurrentThread(); + if (count >= capacity) + return false; + Node l = last; + node.prev = l; + last = node; + if (first == null) + first = node; + else + l.next = node; + ++count; + notEmpty.signal(); + return true; + } + + /** + * Removes and returns first element, or null if empty. + */ + private E unlinkFirst() { + // assert lock.isHeldByCurrentThread(); + Node f = first; + if (f == null) + return null; + Node n = f.next; + E item = f.item; + f.item = null; + f.next = f; // help GC + first = n; + if (n == null) + last = null; + else + n.prev = null; + --count; + notFull.signal(); + return item; + } + + /** + * Removes and returns last element, or null if empty. + */ + private E unlinkLast() { + // assert lock.isHeldByCurrentThread(); + Node l = last; + if (l == null) + return null; + Node p = l.prev; + E item = l.item; + l.item = null; + l.prev = l; // help GC + last = p; + if (p == null) + first = null; + else + p.next = null; + --count; + notFull.signal(); + return item; + } + + /** + * Unlinks x. + */ + void unlink(Node x) { + // assert lock.isHeldByCurrentThread(); + Node p = x.prev; + Node n = x.next; + if (p == null) { + unlinkFirst(); + } else if (n == null) { + unlinkLast(); + } else { + p.next = n; + n.prev = p; + x.item = null; + // Don't mess with x's links. They may still be in use by + // an iterator. + --count; + notFull.signal(); + } + } + + // BlockingDeque methods + + /** + * @throws IllegalStateException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + */ + public void addFirst(E e) { + if (!offerFirst(e)) + throw new IllegalStateException("Deque full"); + } + + /** + * @throws IllegalStateException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + */ + public void addLast(E e) { + if (!offerLast(e)) + throw new IllegalStateException("Deque full"); + } + + /** + * @throws NullPointerException {@inheritDoc} + */ + public boolean offerFirst(E e) { + if (e == null) throw new NullPointerException(); + Node node = new Node(e); + final ReentrantLock lock = this.lock; + lock.lock(); + try { + return linkFirst(node); + } finally { + lock.unlock(); + } + } + + /** + * @throws NullPointerException {@inheritDoc} + */ + public boolean offerLast(E e) { + if (e == null) throw new NullPointerException(); + Node node = new Node(e); + final ReentrantLock lock = this.lock; + lock.lock(); + try { + return linkLast(node); + } finally { + lock.unlock(); + } + } + + /** + * @throws NullPointerException {@inheritDoc} + * @throws InterruptedException {@inheritDoc} + */ + public void putFirst(E e) throws InterruptedException { + if (e == null) throw new NullPointerException(); + Node node = new Node(e); + final ReentrantLock lock = this.lock; + lock.lock(); + try { + while (!linkFirst(node)) + notFull.await(); + } finally { + lock.unlock(); + } + } + + /** + * @throws NullPointerException {@inheritDoc} + * @throws InterruptedException {@inheritDoc} + */ + public void putLast(E e) throws InterruptedException { + if (e == null) throw new NullPointerException(); + Node node = new Node(e); + final ReentrantLock lock = this.lock; + lock.lock(); + try { + while (!linkLast(node)) + notFull.await(); + } finally { + lock.unlock(); + } + } + + /** + * @throws NullPointerException {@inheritDoc} + * @throws InterruptedException {@inheritDoc} + */ + public boolean offerFirst(E e, long timeout, TimeUnit unit) + throws InterruptedException { + if (e == null) throw new NullPointerException(); + Node node = new Node(e); + long nanos = unit.toNanos(timeout); + final ReentrantLock lock = this.lock; + lock.lockInterruptibly(); + try { + while (!linkFirst(node)) { + if (nanos <= 0) + return false; + nanos = notFull.awaitNanos(nanos); + } + return true; + } finally { + lock.unlock(); + } + } + + /** + * @throws NullPointerException {@inheritDoc} + * @throws InterruptedException {@inheritDoc} + */ + public boolean offerLast(E e, long timeout, TimeUnit unit) + throws InterruptedException { + if (e == null) throw new NullPointerException(); + Node node = new Node(e); + long nanos = unit.toNanos(timeout); + final ReentrantLock lock = this.lock; + lock.lockInterruptibly(); + try { + while (!linkLast(node)) { + if (nanos <= 0) + return false; + nanos = notFull.awaitNanos(nanos); + } + return true; + } finally { + lock.unlock(); + } + } + + /** + * @throws NoSuchElementException {@inheritDoc} + */ + public E removeFirst() { + E x = pollFirst(); + if (x == null) throw new NoSuchElementException(); + return x; + } + + /** + * @throws NoSuchElementException {@inheritDoc} + */ + public E removeLast() { + E x = pollLast(); + if (x == null) throw new NoSuchElementException(); + return x; + } + + public E pollFirst() { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + return unlinkFirst(); + } finally { + lock.unlock(); + } + } + + public E pollLast() { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + return unlinkLast(); + } finally { + lock.unlock(); + } + } + + public E takeFirst() throws InterruptedException { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + E x; + while ( (x = unlinkFirst()) == null) + notEmpty.await(); + return x; + } finally { + lock.unlock(); + } + } + + public E takeLast() throws InterruptedException { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + E x; + while ( (x = unlinkLast()) == null) + notEmpty.await(); + return x; + } finally { + lock.unlock(); + } + } + + public E pollFirst(long timeout, TimeUnit unit) + throws InterruptedException { + long nanos = unit.toNanos(timeout); + final ReentrantLock lock = this.lock; + lock.lockInterruptibly(); + try { + E x; + while ( (x = unlinkFirst()) == null) { + if (nanos <= 0) + return null; + nanos = notEmpty.awaitNanos(nanos); + } + return x; + } finally { + lock.unlock(); + } + } + + public E pollLast(long timeout, TimeUnit unit) + throws InterruptedException { + long nanos = unit.toNanos(timeout); + final ReentrantLock lock = this.lock; + lock.lockInterruptibly(); + try { + E x; + while ( (x = unlinkLast()) == null) { + if (nanos <= 0) + return null; + nanos = notEmpty.awaitNanos(nanos); + } + return x; + } finally { + lock.unlock(); + } + } + + /** + * @throws NoSuchElementException {@inheritDoc} + */ + public E getFirst() { + E x = peekFirst(); + if (x == null) throw new NoSuchElementException(); + return x; + } + + /** + * @throws NoSuchElementException {@inheritDoc} + */ + public E getLast() { + E x = peekLast(); + if (x == null) throw new NoSuchElementException(); + return x; + } + + public E peekFirst() { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + return (first == null) ? null : first.item; + } finally { + lock.unlock(); + } + } + + public E peekLast() { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + return (last == null) ? null : last.item; + } finally { + lock.unlock(); + } + } + + public boolean removeFirstOccurrence(Object o) { + if (o == null) return false; + final ReentrantLock lock = this.lock; + lock.lock(); + try { + for (Node p = first; p != null; p = p.next) { + if (o.equals(p.item)) { + unlink(p); + return true; + } + } + return false; + } finally { + lock.unlock(); + } + } + + public boolean removeLastOccurrence(Object o) { + if (o == null) return false; + final ReentrantLock lock = this.lock; + lock.lock(); + try { + for (Node p = last; p != null; p = p.prev) { + if (o.equals(p.item)) { + unlink(p); + return true; + } + } + return false; + } finally { + lock.unlock(); + } + } + + // BlockingQueue methods + + /** + * Inserts the specified element at the end of this deque unless it would + * violate capacity restrictions. When using a capacity-restricted deque, + * it is generally preferable to use method {@link #offer(Object) offer}. + * + *

This method is equivalent to {@link #addLast}. + * + * @throws IllegalStateException if the element cannot be added at this + * time due to capacity restrictions + * @throws NullPointerException if the specified element is null + */ + public boolean add(E e) { + addLast(e); + return true; + } + + /** + * @throws NullPointerException if the specified element is null + */ + public boolean offer(E e) { + return offerLast(e); + } + + /** + * @throws NullPointerException {@inheritDoc} + * @throws InterruptedException {@inheritDoc} + */ + public void put(E e) throws InterruptedException { + putLast(e); + } + + /** + * @throws NullPointerException {@inheritDoc} + * @throws InterruptedException {@inheritDoc} + */ + public boolean offer(E e, long timeout, TimeUnit unit) + throws InterruptedException { + return offerLast(e, timeout, unit); + } + + /** + * Retrieves and removes the head of the queue represented by this deque. + * This method differs from {@link #poll poll} only in that it throws an + * exception if this deque is empty. + * + *

This method is equivalent to {@link #removeFirst() removeFirst}. + * + * @return the head of the queue represented by this deque + * @throws NoSuchElementException if this deque is empty + */ + public E remove() { + return removeFirst(); + } + + public E poll() { + return pollFirst(); + } + + public E take() throws InterruptedException { + return takeFirst(); + } + + public E poll(long timeout, TimeUnit unit) throws InterruptedException { + return pollFirst(timeout, unit); + } + + /** + * Retrieves, but does not remove, the head of the queue represented by + * this deque. This method differs from {@link #peek peek} only in that + * it throws an exception if this deque is empty. + * + *

This method is equivalent to {@link #getFirst() getFirst}. + * + * @return the head of the queue represented by this deque + * @throws NoSuchElementException if this deque is empty + */ + public E element() { + return getFirst(); + } + + public E peek() { + return peekFirst(); + } + + /** + * Returns the number of additional elements that this deque can ideally + * (in the absence of memory or resource constraints) accept without + * blocking. This is always equal to the initial capacity of this deque + * less the current {@code size} of this deque. + * + *

Note that you cannot always tell if an attempt to insert + * an element will succeed by inspecting {@code remainingCapacity} + * because it may be the case that another thread is about to + * insert or remove an element. + */ + public int remainingCapacity() { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + return capacity - count; + } finally { + lock.unlock(); + } + } + + /** + * @throws UnsupportedOperationException {@inheritDoc} + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + * @throws IllegalArgumentException {@inheritDoc} + */ + public int drainTo(Collection c) { + return drainTo(c, Integer.MAX_VALUE); + } + + /** + * @throws UnsupportedOperationException {@inheritDoc} + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + * @throws IllegalArgumentException {@inheritDoc} + */ + public int drainTo(Collection c, int maxElements) { + if (c == null) + throw new NullPointerException(); + if (c == this) + throw new IllegalArgumentException(); + final ReentrantLock lock = this.lock; + lock.lock(); + try { + int n = Math.min(maxElements, count); + for (int i = 0; i < n; i++) { + c.add(first.item); // In this order, in case add() throws. + unlinkFirst(); + } + return n; + } finally { + lock.unlock(); + } + } + + // Stack methods + + /** + * @throws IllegalStateException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + */ + public void push(E e) { + addFirst(e); + } + + /** + * @throws NoSuchElementException {@inheritDoc} + */ + public E pop() { + return removeFirst(); + } + + // Collection methods + + /** + * Removes the first occurrence of the specified element from this deque. + * If the deque does not contain the element, it is unchanged. + * More formally, removes the first element {@code e} such that + * {@code o.equals(e)} (if such an element exists). + * Returns {@code true} if this deque contained the specified element + * (or equivalently, if this deque changed as a result of the call). + * + *

This method is equivalent to + * {@link #removeFirstOccurrence(Object) removeFirstOccurrence}. + * + * @param o element to be removed from this deque, if present + * @return {@code true} if this deque changed as a result of the call + */ + public boolean remove(Object o) { + return removeFirstOccurrence(o); + } + + /** + * Returns the number of elements in this deque. + * + * @return the number of elements in this deque + */ + public int size() { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + return count; + } finally { + lock.unlock(); + } + } + + /** + * Returns {@code true} if this deque contains the specified element. + * More formally, returns {@code true} if and only if this deque contains + * at least one element {@code e} such that {@code o.equals(e)}. + * + * @param o object to be checked for containment in this deque + * @return {@code true} if this deque contains the specified element + */ + public boolean contains(Object o) { + if (o == null) return false; + final ReentrantLock lock = this.lock; + lock.lock(); + try { + for (Node p = first; p != null; p = p.next) + if (o.equals(p.item)) + return true; + return false; + } finally { + lock.unlock(); + } + } + + /* + * TODO: Add support for more efficient bulk operations. + * + * We don't want to acquire the lock for every iteration, but we + * also want other threads a chance to interact with the + * collection, especially when count is close to capacity. + */ + +// /** +// * Adds all of the elements in the specified collection to this +// * queue. Attempts to addAll of a queue to itself result in +// * {@code IllegalArgumentException}. Further, the behavior of +// * this operation is undefined if the specified collection is +// * modified while the operation is in progress. +// * +// * @param c collection containing elements to be added to this queue +// * @return {@code true} if this queue changed as a result of the call +// * @throws ClassCastException {@inheritDoc} +// * @throws NullPointerException {@inheritDoc} +// * @throws IllegalArgumentException {@inheritDoc} +// * @throws IllegalStateException {@inheritDoc} +// * @see #add(Object) +// */ +// public boolean addAll(Collection c) { +// if (c == null) +// throw new NullPointerException(); +// if (c == this) +// throw new IllegalArgumentException(); +// final ReentrantLock lock = this.lock; +// lock.lock(); +// try { +// boolean modified = false; +// for (E e : c) +// if (linkLast(e)) +// modified = true; +// return modified; +// } finally { +// lock.unlock(); +// } +// } + + /** + * Returns an array containing all of the elements in this deque, in + * proper sequence (from first to last element). + * + *

The returned array will be "safe" in that no references to it are + * maintained by this deque. (In other words, this method must allocate + * a new array). The caller is thus free to modify the returned array. + * + *

This method acts as bridge between array-based and collection-based + * APIs. + * + * @return an array containing all of the elements in this deque + */ + @SuppressWarnings("unchecked") + public Object[] toArray() { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + Object[] a = new Object[count]; + int k = 0; + for (Node p = first; p != null; p = p.next) + a[k++] = p.item; + return a; + } finally { + lock.unlock(); + } + } + + /** + * Returns an array containing all of the elements in this deque, in + * proper sequence; the runtime type of the returned array is that of + * the specified array. If the deque fits in the specified array, it + * is returned therein. Otherwise, a new array is allocated with the + * runtime type of the specified array and the size of this deque. + * + *

If this deque fits in the specified array with room to spare + * (i.e., the array has more elements than this deque), the element in + * the array immediately following the end of the deque is set to + * {@code null}. + * + *

Like the {@link #toArray()} method, this method acts as bridge between + * array-based and collection-based APIs. Further, this method allows + * precise control over the runtime type of the output array, and may, + * under certain circumstances, be used to save allocation costs. + * + *

Suppose {@code x} is a deque known to contain only strings. + * The following code can be used to dump the deque into a newly + * allocated array of {@code String}: + * + *

+     *     String[] y = x.toArray(new String[0]);
+ * + * Note that {@code toArray(new Object[0])} is identical in function to + * {@code toArray()}. + * + * @param a the array into which the elements of the deque are to + * be stored, if it is big enough; otherwise, a new array of the + * same runtime type is allocated for this purpose + * @return an array containing all of the elements in this deque + * @throws ArrayStoreException if the runtime type of the specified array + * is not a supertype of the runtime type of every element in + * this deque + * @throws NullPointerException if the specified array is null + */ + @SuppressWarnings("unchecked") + public T[] toArray(T[] a) { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + if (a.length < count) + a = (T[])java.lang.reflect.Array.newInstance + (a.getClass().getComponentType(), count); + + int k = 0; + for (Node p = first; p != null; p = p.next) + a[k++] = (T)p.item; + if (a.length > k) + a[k] = null; + return a; + } finally { + lock.unlock(); + } + } + + public String toString() { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + Node p = first; + if (p == null) + return "[]"; + + StringBuilder sb = new StringBuilder(); + sb.append('['); + for (;;) { + E e = p.item; + sb.append(e == this ? "(this Collection)" : e); + p = p.next; + if (p == null) + return sb.append(']').toString(); + sb.append(',').append(' '); + } + } finally { + lock.unlock(); + } + } + + /** + * Atomically removes all of the elements from this deque. + * The deque will be empty after this call returns. + */ + public void clear() { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + for (Node f = first; f != null; ) { + f.item = null; + Node n = f.next; + f.prev = null; + f.next = null; + f = n; + } + first = last = null; + count = 0; + notFull.signalAll(); + } finally { + lock.unlock(); + } + } + + /** + * Returns an iterator over the elements in this deque in proper sequence. + * The elements will be returned in order from first (head) to last (tail). + * + *

The returned iterator is a "weakly consistent" iterator that + * will never throw {@link java.util.ConcurrentModificationException + * ConcurrentModificationException}, and guarantees to traverse + * elements as they existed upon construction of the iterator, and + * may (but is not guaranteed to) reflect any modifications + * subsequent to construction. + * + * @return an iterator over the elements in this deque in proper sequence + */ + public Iterator iterator() { + return new Itr(); + } + + /** + * Returns an iterator over the elements in this deque in reverse + * sequential order. The elements will be returned in order from + * last (tail) to first (head). + * + *

The returned iterator is a "weakly consistent" iterator that + * will never throw {@link java.util.ConcurrentModificationException + * ConcurrentModificationException}, and guarantees to traverse + * elements as they existed upon construction of the iterator, and + * may (but is not guaranteed to) reflect any modifications + * subsequent to construction. + * + * @return an iterator over the elements in this deque in reverse order + */ + public Iterator descendingIterator() { + return new DescendingItr(); + } + + /** + * Base class for Iterators for LinkedBlockingDeque + */ + private abstract class AbstractItr implements Iterator { + /** + * The next node to return in next() + */ + Node next; + + /** + * nextItem holds on to item fields because once we claim that + * an element exists in hasNext(), we must return item read + * under lock (in advance()) even if it was in the process of + * being removed when hasNext() was called. + */ + E nextItem; + + /** + * Node returned by most recent call to next. Needed by remove. + * Reset to null if this element is deleted by a call to remove. + */ + private Node lastRet; + + abstract Node firstNode(); + abstract Node nextNode(Node n); + + AbstractItr() { + // set to initial position + final ReentrantLock lock = LinkedBlockingDeque.this.lock; + lock.lock(); + try { + next = firstNode(); + nextItem = (next == null) ? null : next.item; + } finally { + lock.unlock(); + } + } + + /** + * Returns the successor node of the given non-null, but + * possibly previously deleted, node. + */ + private Node succ(Node n) { + // Chains of deleted nodes ending in null or self-links + // are possible if multiple interior nodes are removed. + for (;;) { + Node s = nextNode(n); + if (s == null) + return null; + else if (s.item != null) + return s; + else if (s == n) + return firstNode(); + else + n = s; + } + } + + /** + * Advances next. + */ + void advance() { + final ReentrantLock lock = LinkedBlockingDeque.this.lock; + lock.lock(); + try { + // assert next != null; + next = succ(next); + nextItem = (next == null) ? null : next.item; + } finally { + lock.unlock(); + } + } + + public boolean hasNext() { + return next != null; + } + + public E next() { + if (next == null) + throw new NoSuchElementException(); + lastRet = next; + E x = nextItem; + advance(); + return x; + } + + public void remove() { + Node n = lastRet; + if (n == null) + throw new IllegalStateException(); + lastRet = null; + final ReentrantLock lock = LinkedBlockingDeque.this.lock; + lock.lock(); + try { + if (n.item != null) + unlink(n); + } finally { + lock.unlock(); + } + } + } + + /** Forward iterator */ + private class Itr extends AbstractItr { + Node firstNode() { return first; } + Node nextNode(Node n) { return n.next; } + } + + /** Descending iterator */ + private class DescendingItr extends AbstractItr { + Node firstNode() { return last; } + Node nextNode(Node n) { return n.prev; } + } + + /** + * Save the state of this deque to a stream (that is, serialize it). + * + * @serialData The capacity (int), followed by elements (each an + * {@code Object}) in the proper order, followed by a null + * @param s the stream + */ + private void writeObject(java.io.ObjectOutputStream s) + throws java.io.IOException { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + // Write out capacity and any hidden stuff + s.defaultWriteObject(); + // Write out all elements in the proper order. + for (Node p = first; p != null; p = p.next) + s.writeObject(p.item); + // Use trailing null as sentinel + s.writeObject(null); + } finally { + lock.unlock(); + } + } + + /** + * Reconstitute this deque from a stream (that is, + * deserialize it). + * @param s the stream + */ + private void readObject(java.io.ObjectInputStream s) + throws java.io.IOException, ClassNotFoundException { + s.defaultReadObject(); + count = 0; + first = null; + last = null; + // Read in all elements and place in queue + for (;;) { + @SuppressWarnings("unchecked") + E item = (E)s.readObject(); + if (item == null) + break; + add(item); + } + } + +} diff -r e1953d8b8338 -r c8af252ea9eb rt/emul/compact/src/main/java/java/util/concurrent/LinkedBlockingQueue.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/LinkedBlockingQueue.java Sat Mar 19 10:48:29 2016 +0100 @@ -0,0 +1,910 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +package java.util.concurrent; + +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.ReentrantLock; +import java.util.AbstractQueue; +import java.util.Collection; +import java.util.Iterator; +import java.util.NoSuchElementException; + +/** + * An optionally-bounded {@linkplain BlockingQueue blocking queue} based on + * linked nodes. + * This queue orders elements FIFO (first-in-first-out). + * The head of the queue is that element that has been on the + * queue the longest time. + * The tail of the queue is that element that has been on the + * queue the shortest time. New elements + * are inserted at the tail of the queue, and the queue retrieval + * operations obtain elements at the head of the queue. + * Linked queues typically have higher throughput than array-based queues but + * less predictable performance in most concurrent applications. + * + *

The optional capacity bound constructor argument serves as a + * way to prevent excessive queue expansion. The capacity, if unspecified, + * is equal to {@link Integer#MAX_VALUE}. Linked nodes are + * dynamically created upon each insertion unless this would bring the + * queue above capacity. + * + *

This class and its iterator implement all of the + * optional methods of the {@link Collection} and {@link + * Iterator} interfaces. + * + *

This class is a member of the + * + * Java Collections Framework. + * + * @since 1.5 + * @author Doug Lea + * @param the type of elements held in this collection + * + */ +public class LinkedBlockingQueue extends AbstractQueue + implements BlockingQueue, java.io.Serializable { + private static final long serialVersionUID = -6903933977591709194L; + + /* + * A variant of the "two lock queue" algorithm. The putLock gates + * entry to put (and offer), and has an associated condition for + * waiting puts. Similarly for the takeLock. The "count" field + * that they both rely on is maintained as an atomic to avoid + * needing to get both locks in most cases. Also, to minimize need + * for puts to get takeLock and vice-versa, cascading notifies are + * used. When a put notices that it has enabled at least one take, + * it signals taker. That taker in turn signals others if more + * items have been entered since the signal. And symmetrically for + * takes signalling puts. Operations such as remove(Object) and + * iterators acquire both locks. + * + * Visibility between writers and readers is provided as follows: + * + * Whenever an element is enqueued, the putLock is acquired and + * count updated. A subsequent reader guarantees visibility to the + * enqueued Node by either acquiring the putLock (via fullyLock) + * or by acquiring the takeLock, and then reading n = count.get(); + * this gives visibility to the first n items. + * + * To implement weakly consistent iterators, it appears we need to + * keep all Nodes GC-reachable from a predecessor dequeued Node. + * That would cause two problems: + * - allow a rogue Iterator to cause unbounded memory retention + * - cause cross-generational linking of old Nodes to new Nodes if + * a Node was tenured while live, which generational GCs have a + * hard time dealing with, causing repeated major collections. + * However, only non-deleted Nodes need to be reachable from + * dequeued Nodes, and reachability does not necessarily have to + * be of the kind understood by the GC. We use the trick of + * linking a Node that has just been dequeued to itself. Such a + * self-link implicitly means to advance to head.next. + */ + + /** + * Linked list node class + */ + static class Node { + E item; + + /** + * One of: + * - the real successor Node + * - this Node, meaning the successor is head.next + * - null, meaning there is no successor (this is the last node) + */ + Node next; + + Node(E x) { item = x; } + } + + /** The capacity bound, or Integer.MAX_VALUE if none */ + private final int capacity; + + /** Current number of elements */ + private final AtomicInteger count = new AtomicInteger(0); + + /** + * Head of linked list. + * Invariant: head.item == null + */ + private transient Node head; + + /** + * Tail of linked list. + * Invariant: last.next == null + */ + private transient Node last; + + /** Lock held by take, poll, etc */ + private final ReentrantLock takeLock = new ReentrantLock(); + + /** Wait queue for waiting takes */ + private final Condition notEmpty = takeLock.newCondition(); + + /** Lock held by put, offer, etc */ + private final ReentrantLock putLock = new ReentrantLock(); + + /** Wait queue for waiting puts */ + private final Condition notFull = putLock.newCondition(); + + /** + * Signals a waiting take. Called only from put/offer (which do not + * otherwise ordinarily lock takeLock.) + */ + private void signalNotEmpty() { + final ReentrantLock takeLock = this.takeLock; + takeLock.lock(); + try { + notEmpty.signal(); + } finally { + takeLock.unlock(); + } + } + + /** + * Signals a waiting put. Called only from take/poll. + */ + private void signalNotFull() { + final ReentrantLock putLock = this.putLock; + putLock.lock(); + try { + notFull.signal(); + } finally { + putLock.unlock(); + } + } + + /** + * Links node at end of queue. + * + * @param node the node + */ + private void enqueue(Node node) { + // assert putLock.isHeldByCurrentThread(); + // assert last.next == null; + last = last.next = node; + } + + /** + * Removes a node from head of queue. + * + * @return the node + */ + private E dequeue() { + // assert takeLock.isHeldByCurrentThread(); + // assert head.item == null; + Node h = head; + Node first = h.next; + h.next = h; // help GC + head = first; + E x = first.item; + first.item = null; + return x; + } + + /** + * Lock to prevent both puts and takes. + */ + void fullyLock() { + putLock.lock(); + takeLock.lock(); + } + + /** + * Unlock to allow both puts and takes. + */ + void fullyUnlock() { + takeLock.unlock(); + putLock.unlock(); + } + +// /** +// * Tells whether both locks are held by current thread. +// */ +// boolean isFullyLocked() { +// return (putLock.isHeldByCurrentThread() && +// takeLock.isHeldByCurrentThread()); +// } + + /** + * Creates a {@code LinkedBlockingQueue} with a capacity of + * {@link Integer#MAX_VALUE}. + */ + public LinkedBlockingQueue() { + this(Integer.MAX_VALUE); + } + + /** + * Creates a {@code LinkedBlockingQueue} with the given (fixed) capacity. + * + * @param capacity the capacity of this queue + * @throws IllegalArgumentException if {@code capacity} is not greater + * than zero + */ + public LinkedBlockingQueue(int capacity) { + if (capacity <= 0) throw new IllegalArgumentException(); + this.capacity = capacity; + last = head = new Node(null); + } + + /** + * Creates a {@code LinkedBlockingQueue} with a capacity of + * {@link Integer#MAX_VALUE}, initially containing the elements of the + * given collection, + * added in traversal order of the collection's iterator. + * + * @param c the collection of elements to initially contain + * @throws NullPointerException if the specified collection or any + * of its elements are null + */ + public LinkedBlockingQueue(Collection c) { + this(Integer.MAX_VALUE); + final ReentrantLock putLock = this.putLock; + putLock.lock(); // Never contended, but necessary for visibility + try { + int n = 0; + for (E e : c) { + if (e == null) + throw new NullPointerException(); + if (n == capacity) + throw new IllegalStateException("Queue full"); + enqueue(new Node(e)); + ++n; + } + count.set(n); + } finally { + putLock.unlock(); + } + } + + + // this doc comment is overridden to remove the reference to collections + // greater in size than Integer.MAX_VALUE + /** + * Returns the number of elements in this queue. + * + * @return the number of elements in this queue + */ + public int size() { + return count.get(); + } + + // this doc comment is a modified copy of the inherited doc comment, + // without the reference to unlimited queues. + /** + * Returns the number of additional elements that this queue can ideally + * (in the absence of memory or resource constraints) accept without + * blocking. This is always equal to the initial capacity of this queue + * less the current {@code size} of this queue. + * + *

Note that you cannot always tell if an attempt to insert + * an element will succeed by inspecting {@code remainingCapacity} + * because it may be the case that another thread is about to + * insert or remove an element. + */ + public int remainingCapacity() { + return capacity - count.get(); + } + + /** + * Inserts the specified element at the tail of this queue, waiting if + * necessary for space to become available. + * + * @throws InterruptedException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + */ + public void put(E e) throws InterruptedException { + if (e == null) throw new NullPointerException(); + // Note: convention in all put/take/etc is to preset local var + // holding count negative to indicate failure unless set. + int c = -1; + Node node = new Node(e); + final ReentrantLock putLock = this.putLock; + final AtomicInteger count = this.count; + putLock.lockInterruptibly(); + try { + /* + * Note that count is used in wait guard even though it is + * not protected by lock. This works because count can + * only decrease at this point (all other puts are shut + * out by lock), and we (or some other waiting put) are + * signalled if it ever changes from capacity. Similarly + * for all other uses of count in other wait guards. + */ + while (count.get() == capacity) { + notFull.await(); + } + enqueue(node); + c = count.getAndIncrement(); + if (c + 1 < capacity) + notFull.signal(); + } finally { + putLock.unlock(); + } + if (c == 0) + signalNotEmpty(); + } + + /** + * Inserts the specified element at the tail of this queue, waiting if + * necessary up to the specified wait time for space to become available. + * + * @return {@code true} if successful, or {@code false} if + * the specified waiting time elapses before space is available. + * @throws InterruptedException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + */ + public boolean offer(E e, long timeout, TimeUnit unit) + throws InterruptedException { + + if (e == null) throw new NullPointerException(); + long nanos = unit.toNanos(timeout); + int c = -1; + final ReentrantLock putLock = this.putLock; + final AtomicInteger count = this.count; + putLock.lockInterruptibly(); + try { + while (count.get() == capacity) { + if (nanos <= 0) + return false; + nanos = notFull.awaitNanos(nanos); + } + enqueue(new Node(e)); + c = count.getAndIncrement(); + if (c + 1 < capacity) + notFull.signal(); + } finally { + putLock.unlock(); + } + if (c == 0) + signalNotEmpty(); + return true; + } + + /** + * Inserts the specified element at the tail of this queue if it is + * possible to do so immediately without exceeding the queue's capacity, + * returning {@code true} upon success and {@code false} if this queue + * is full. + * When using a capacity-restricted queue, this method is generally + * preferable to method {@link BlockingQueue#add add}, which can fail to + * insert an element only by throwing an exception. + * + * @throws NullPointerException if the specified element is null + */ + public boolean offer(E e) { + if (e == null) throw new NullPointerException(); + final AtomicInteger count = this.count; + if (count.get() == capacity) + return false; + int c = -1; + Node node = new Node(e); + final ReentrantLock putLock = this.putLock; + putLock.lock(); + try { + if (count.get() < capacity) { + enqueue(node); + c = count.getAndIncrement(); + if (c + 1 < capacity) + notFull.signal(); + } + } finally { + putLock.unlock(); + } + if (c == 0) + signalNotEmpty(); + return c >= 0; + } + + + public E take() throws InterruptedException { + E x; + int c = -1; + final AtomicInteger count = this.count; + final ReentrantLock takeLock = this.takeLock; + takeLock.lockInterruptibly(); + try { + while (count.get() == 0) { + notEmpty.await(); + } + x = dequeue(); + c = count.getAndDecrement(); + if (c > 1) + notEmpty.signal(); + } finally { + takeLock.unlock(); + } + if (c == capacity) + signalNotFull(); + return x; + } + + public E poll(long timeout, TimeUnit unit) throws InterruptedException { + E x = null; + int c = -1; + long nanos = unit.toNanos(timeout); + final AtomicInteger count = this.count; + final ReentrantLock takeLock = this.takeLock; + takeLock.lockInterruptibly(); + try { + while (count.get() == 0) { + if (nanos <= 0) + return null; + nanos = notEmpty.awaitNanos(nanos); + } + x = dequeue(); + c = count.getAndDecrement(); + if (c > 1) + notEmpty.signal(); + } finally { + takeLock.unlock(); + } + if (c == capacity) + signalNotFull(); + return x; + } + + public E poll() { + final AtomicInteger count = this.count; + if (count.get() == 0) + return null; + E x = null; + int c = -1; + final ReentrantLock takeLock = this.takeLock; + takeLock.lock(); + try { + if (count.get() > 0) { + x = dequeue(); + c = count.getAndDecrement(); + if (c > 1) + notEmpty.signal(); + } + } finally { + takeLock.unlock(); + } + if (c == capacity) + signalNotFull(); + return x; + } + + public E peek() { + if (count.get() == 0) + return null; + final ReentrantLock takeLock = this.takeLock; + takeLock.lock(); + try { + Node first = head.next; + if (first == null) + return null; + else + return first.item; + } finally { + takeLock.unlock(); + } + } + + /** + * Unlinks interior Node p with predecessor trail. + */ + void unlink(Node p, Node trail) { + // assert isFullyLocked(); + // p.next is not changed, to allow iterators that are + // traversing p to maintain their weak-consistency guarantee. + p.item = null; + trail.next = p.next; + if (last == p) + last = trail; + if (count.getAndDecrement() == capacity) + notFull.signal(); + } + + /** + * Removes a single instance of the specified element from this queue, + * if it is present. More formally, removes an element {@code e} such + * that {@code o.equals(e)}, if this queue contains one or more such + * elements. + * Returns {@code true} if this queue contained the specified element + * (or equivalently, if this queue changed as a result of the call). + * + * @param o element to be removed from this queue, if present + * @return {@code true} if this queue changed as a result of the call + */ + public boolean remove(Object o) { + if (o == null) return false; + fullyLock(); + try { + for (Node trail = head, p = trail.next; + p != null; + trail = p, p = p.next) { + if (o.equals(p.item)) { + unlink(p, trail); + return true; + } + } + return false; + } finally { + fullyUnlock(); + } + } + + /** + * Returns {@code true} if this queue contains the specified element. + * More formally, returns {@code true} if and only if this queue contains + * at least one element {@code e} such that {@code o.equals(e)}. + * + * @param o object to be checked for containment in this queue + * @return {@code true} if this queue contains the specified element + */ + public boolean contains(Object o) { + if (o == null) return false; + fullyLock(); + try { + for (Node p = head.next; p != null; p = p.next) + if (o.equals(p.item)) + return true; + return false; + } finally { + fullyUnlock(); + } + } + + /** + * Returns an array containing all of the elements in this queue, in + * proper sequence. + * + *

The returned array will be "safe" in that no references to it are + * maintained by this queue. (In other words, this method must allocate + * a new array). The caller is thus free to modify the returned array. + * + *

This method acts as bridge between array-based and collection-based + * APIs. + * + * @return an array containing all of the elements in this queue + */ + public Object[] toArray() { + fullyLock(); + try { + int size = count.get(); + Object[] a = new Object[size]; + int k = 0; + for (Node p = head.next; p != null; p = p.next) + a[k++] = p.item; + return a; + } finally { + fullyUnlock(); + } + } + + /** + * Returns an array containing all of the elements in this queue, in + * proper sequence; the runtime type of the returned array is that of + * the specified array. If the queue fits in the specified array, it + * is returned therein. Otherwise, a new array is allocated with the + * runtime type of the specified array and the size of this queue. + * + *

If this queue fits in the specified array with room to spare + * (i.e., the array has more elements than this queue), the element in + * the array immediately following the end of the queue is set to + * {@code null}. + * + *

Like the {@link #toArray()} method, this method acts as bridge between + * array-based and collection-based APIs. Further, this method allows + * precise control over the runtime type of the output array, and may, + * under certain circumstances, be used to save allocation costs. + * + *

Suppose {@code x} is a queue known to contain only strings. + * The following code can be used to dump the queue into a newly + * allocated array of {@code String}: + * + *

+     *     String[] y = x.toArray(new String[0]);
+ * + * Note that {@code toArray(new Object[0])} is identical in function to + * {@code toArray()}. + * + * @param a the array into which the elements of the queue are to + * be stored, if it is big enough; otherwise, a new array of the + * same runtime type is allocated for this purpose + * @return an array containing all of the elements in this queue + * @throws ArrayStoreException if the runtime type of the specified array + * is not a supertype of the runtime type of every element in + * this queue + * @throws NullPointerException if the specified array is null + */ + @SuppressWarnings("unchecked") + public T[] toArray(T[] a) { + fullyLock(); + try { + int size = count.get(); + if (a.length < size) + a = (T[])java.lang.reflect.Array.newInstance + (a.getClass().getComponentType(), size); + + int k = 0; + for (Node p = head.next; p != null; p = p.next) + a[k++] = (T)p.item; + if (a.length > k) + a[k] = null; + return a; + } finally { + fullyUnlock(); + } + } + + public String toString() { + fullyLock(); + try { + Node p = head.next; + if (p == null) + return "[]"; + + StringBuilder sb = new StringBuilder(); + sb.append('['); + for (;;) { + E e = p.item; + sb.append(e == this ? "(this Collection)" : e); + p = p.next; + if (p == null) + return sb.append(']').toString(); + sb.append(',').append(' '); + } + } finally { + fullyUnlock(); + } + } + + /** + * Atomically removes all of the elements from this queue. + * The queue will be empty after this call returns. + */ + public void clear() { + fullyLock(); + try { + for (Node p, h = head; (p = h.next) != null; h = p) { + h.next = h; + p.item = null; + } + head = last; + // assert head.item == null && head.next == null; + if (count.getAndSet(0) == capacity) + notFull.signal(); + } finally { + fullyUnlock(); + } + } + + /** + * @throws UnsupportedOperationException {@inheritDoc} + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + * @throws IllegalArgumentException {@inheritDoc} + */ + public int drainTo(Collection c) { + return drainTo(c, Integer.MAX_VALUE); + } + + /** + * @throws UnsupportedOperationException {@inheritDoc} + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + * @throws IllegalArgumentException {@inheritDoc} + */ + public int drainTo(Collection c, int maxElements) { + if (c == null) + throw new NullPointerException(); + if (c == this) + throw new IllegalArgumentException(); + boolean signalNotFull = false; + final ReentrantLock takeLock = this.takeLock; + takeLock.lock(); + try { + int n = Math.min(maxElements, count.get()); + // count.get provides visibility to first n Nodes + Node h = head; + int i = 0; + try { + while (i < n) { + Node p = h.next; + c.add(p.item); + p.item = null; + h.next = h; + h = p; + ++i; + } + return n; + } finally { + // Restore invariants even if c.add() threw + if (i > 0) { + // assert h.item == null; + head = h; + signalNotFull = (count.getAndAdd(-i) == capacity); + } + } + } finally { + takeLock.unlock(); + if (signalNotFull) + signalNotFull(); + } + } + + /** + * Returns an iterator over the elements in this queue in proper sequence. + * The elements will be returned in order from first (head) to last (tail). + * + *

The returned iterator is a "weakly consistent" iterator that + * will never throw {@link java.util.ConcurrentModificationException + * ConcurrentModificationException}, and guarantees to traverse + * elements as they existed upon construction of the iterator, and + * may (but is not guaranteed to) reflect any modifications + * subsequent to construction. + * + * @return an iterator over the elements in this queue in proper sequence + */ + public Iterator iterator() { + return new Itr(); + } + + private class Itr implements Iterator { + /* + * Basic weakly-consistent iterator. At all times hold the next + * item to hand out so that if hasNext() reports true, we will + * still have it to return even if lost race with a take etc. + */ + private Node current; + private Node lastRet; + private E currentElement; + + Itr() { + fullyLock(); + try { + current = head.next; + if (current != null) + currentElement = current.item; + } finally { + fullyUnlock(); + } + } + + public boolean hasNext() { + return current != null; + } + + /** + * Returns the next live successor of p, or null if no such. + * + * Unlike other traversal methods, iterators need to handle both: + * - dequeued nodes (p.next == p) + * - (possibly multiple) interior removed nodes (p.item == null) + */ + private Node nextNode(Node p) { + for (;;) { + Node s = p.next; + if (s == p) + return head.next; + if (s == null || s.item != null) + return s; + p = s; + } + } + + public E next() { + fullyLock(); + try { + if (current == null) + throw new NoSuchElementException(); + E x = currentElement; + lastRet = current; + current = nextNode(current); + currentElement = (current == null) ? null : current.item; + return x; + } finally { + fullyUnlock(); + } + } + + public void remove() { + if (lastRet == null) + throw new IllegalStateException(); + fullyLock(); + try { + Node node = lastRet; + lastRet = null; + for (Node trail = head, p = trail.next; + p != null; + trail = p, p = p.next) { + if (p == node) { + unlink(p, trail); + break; + } + } + } finally { + fullyUnlock(); + } + } + } + + /** + * Save the state to a stream (that is, serialize it). + * + * @serialData The capacity is emitted (int), followed by all of + * its elements (each an {@code Object}) in the proper order, + * followed by a null + * @param s the stream + */ + private void writeObject(java.io.ObjectOutputStream s) + throws java.io.IOException { + + fullyLock(); + try { + // Write out any hidden stuff, plus capacity + s.defaultWriteObject(); + + // Write out all elements in the proper order. + for (Node p = head.next; p != null; p = p.next) + s.writeObject(p.item); + + // Use trailing null as sentinel + s.writeObject(null); + } finally { + fullyUnlock(); + } + } + + /** + * Reconstitute this queue instance from a stream (that is, + * deserialize it). + * + * @param s the stream + */ + private void readObject(java.io.ObjectInputStream s) + throws java.io.IOException, ClassNotFoundException { + // Read in capacity, and any hidden stuff + s.defaultReadObject(); + + count.set(0); + last = head = new Node(null); + + // Read in all elements and place in queue + for (;;) { + @SuppressWarnings("unchecked") + E item = (E)s.readObject(); + if (item == null) + break; + add(item); + } + } +} diff -r e1953d8b8338 -r c8af252ea9eb rt/emul/compact/src/main/java/java/util/concurrent/LinkedTransferQueue.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/LinkedTransferQueue.java Sat Mar 19 10:48:29 2016 +0100 @@ -0,0 +1,1351 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +package java.util.concurrent; + +import java.util.AbstractQueue; +import java.util.Collection; +import java.util.Iterator; +import java.util.NoSuchElementException; +import java.util.Queue; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.LockSupport; + +/** + * An unbounded {@link TransferQueue} based on linked nodes. + * This queue orders elements FIFO (first-in-first-out) with respect + * to any given producer. The head of the queue is that + * element that has been on the queue the longest time for some + * producer. The tail of the queue is that element that has + * been on the queue the shortest time for some producer. + * + *

Beware that, unlike in most collections, the {@code size} method + * is NOT a constant-time operation. Because of the + * asynchronous nature of these queues, determining the current number + * of elements requires a traversal of the elements, and so may report + * inaccurate results if this collection is modified during traversal. + * Additionally, the bulk operations {@code addAll}, + * {@code removeAll}, {@code retainAll}, {@code containsAll}, + * {@code equals}, and {@code toArray} are not guaranteed + * to be performed atomically. For example, an iterator operating + * concurrently with an {@code addAll} operation might view only some + * of the added elements. + * + *

This class and its iterator implement all of the + * optional methods of the {@link Collection} and {@link + * Iterator} interfaces. + * + *

Memory consistency effects: As with other concurrent + * collections, actions in a thread prior to placing an object into a + * {@code LinkedTransferQueue} + * happen-before + * actions subsequent to the access or removal of that element from + * the {@code LinkedTransferQueue} in another thread. + * + *

This class is a member of the + * + * Java Collections Framework. + * + * @since 1.7 + * @author Doug Lea + * @param the type of elements held in this collection + */ +public class LinkedTransferQueue extends AbstractQueue + implements TransferQueue, java.io.Serializable { + private static final long serialVersionUID = -3223113410248163686L; + + /* + * *** Overview of Dual Queues with Slack *** + * + * Dual Queues, introduced by Scherer and Scott + * (http://www.cs.rice.edu/~wns1/papers/2004-DISC-DDS.pdf) are + * (linked) queues in which nodes may represent either data or + * requests. When a thread tries to enqueue a data node, but + * encounters a request node, it instead "matches" and removes it; + * and vice versa for enqueuing requests. Blocking Dual Queues + * arrange that threads enqueuing unmatched requests block until + * other threads provide the match. Dual Synchronous Queues (see + * Scherer, Lea, & Scott + * http://www.cs.rochester.edu/u/scott/papers/2009_Scherer_CACM_SSQ.pdf) + * additionally arrange that threads enqueuing unmatched data also + * block. Dual Transfer Queues support all of these modes, as + * dictated by callers. + * + * A FIFO dual queue may be implemented using a variation of the + * Michael & Scott (M&S) lock-free queue algorithm + * (http://www.cs.rochester.edu/u/scott/papers/1996_PODC_queues.pdf). + * It maintains two pointer fields, "head", pointing to a + * (matched) node that in turn points to the first actual + * (unmatched) queue node (or null if empty); and "tail" that + * points to the last node on the queue (or again null if + * empty). For example, here is a possible queue with four data + * elements: + * + * head tail + * | | + * v v + * M -> U -> U -> U -> U + * + * The M&S queue algorithm is known to be prone to scalability and + * overhead limitations when maintaining (via CAS) these head and + * tail pointers. This has led to the development of + * contention-reducing variants such as elimination arrays (see + * Moir et al http://portal.acm.org/citation.cfm?id=1074013) and + * optimistic back pointers (see Ladan-Mozes & Shavit + * http://people.csail.mit.edu/edya/publications/OptimisticFIFOQueue-journal.pdf). + * However, the nature of dual queues enables a simpler tactic for + * improving M&S-style implementations when dual-ness is needed. + * + * In a dual queue, each node must atomically maintain its match + * status. While there are other possible variants, we implement + * this here as: for a data-mode node, matching entails CASing an + * "item" field from a non-null data value to null upon match, and + * vice-versa for request nodes, CASing from null to a data + * value. (Note that the linearization properties of this style of + * queue are easy to verify -- elements are made available by + * linking, and unavailable by matching.) Compared to plain M&S + * queues, this property of dual queues requires one additional + * successful atomic operation per enq/deq pair. But it also + * enables lower cost variants of queue maintenance mechanics. (A + * variation of this idea applies even for non-dual queues that + * support deletion of interior elements, such as + * j.u.c.ConcurrentLinkedQueue.) + * + * Once a node is matched, its match status can never again + * change. We may thus arrange that the linked list of them + * contain a prefix of zero or more matched nodes, followed by a + * suffix of zero or more unmatched nodes. (Note that we allow + * both the prefix and suffix to be zero length, which in turn + * means that we do not use a dummy header.) If we were not + * concerned with either time or space efficiency, we could + * correctly perform enqueue and dequeue operations by traversing + * from a pointer to the initial node; CASing the item of the + * first unmatched node on match and CASing the next field of the + * trailing node on appends. (Plus some special-casing when + * initially empty). While this would be a terrible idea in + * itself, it does have the benefit of not requiring ANY atomic + * updates on head/tail fields. + * + * We introduce here an approach that lies between the extremes of + * never versus always updating queue (head and tail) pointers. + * This offers a tradeoff between sometimes requiring extra + * traversal steps to locate the first and/or last unmatched + * nodes, versus the reduced overhead and contention of fewer + * updates to queue pointers. For example, a possible snapshot of + * a queue is: + * + * head tail + * | | + * v v + * M -> M -> U -> U -> U -> U + * + * The best value for this "slack" (the targeted maximum distance + * between the value of "head" and the first unmatched node, and + * similarly for "tail") is an empirical matter. We have found + * that using very small constants in the range of 1-3 work best + * over a range of platforms. Larger values introduce increasing + * costs of cache misses and risks of long traversal chains, while + * smaller values increase CAS contention and overhead. + * + * Dual queues with slack differ from plain M&S dual queues by + * virtue of only sometimes updating head or tail pointers when + * matching, appending, or even traversing nodes; in order to + * maintain a targeted slack. The idea of "sometimes" may be + * operationalized in several ways. The simplest is to use a + * per-operation counter incremented on each traversal step, and + * to try (via CAS) to update the associated queue pointer + * whenever the count exceeds a threshold. Another, that requires + * more overhead, is to use random number generators to update + * with a given probability per traversal step. + * + * In any strategy along these lines, because CASes updating + * fields may fail, the actual slack may exceed targeted + * slack. However, they may be retried at any time to maintain + * targets. Even when using very small slack values, this + * approach works well for dual queues because it allows all + * operations up to the point of matching or appending an item + * (hence potentially allowing progress by another thread) to be + * read-only, thus not introducing any further contention. As + * described below, we implement this by performing slack + * maintenance retries only after these points. + * + * As an accompaniment to such techniques, traversal overhead can + * be further reduced without increasing contention of head + * pointer updates: Threads may sometimes shortcut the "next" link + * path from the current "head" node to be closer to the currently + * known first unmatched node, and similarly for tail. Again, this + * may be triggered with using thresholds or randomization. + * + * These ideas must be further extended to avoid unbounded amounts + * of costly-to-reclaim garbage caused by the sequential "next" + * links of nodes starting at old forgotten head nodes: As first + * described in detail by Boehm + * (http://portal.acm.org/citation.cfm?doid=503272.503282) if a GC + * delays noticing that any arbitrarily old node has become + * garbage, all newer dead nodes will also be unreclaimed. + * (Similar issues arise in non-GC environments.) To cope with + * this in our implementation, upon CASing to advance the head + * pointer, we set the "next" link of the previous head to point + * only to itself; thus limiting the length of connected dead lists. + * (We also take similar care to wipe out possibly garbage + * retaining values held in other Node fields.) However, doing so + * adds some further complexity to traversal: If any "next" + * pointer links to itself, it indicates that the current thread + * has lagged behind a head-update, and so the traversal must + * continue from the "head". Traversals trying to find the + * current tail starting from "tail" may also encounter + * self-links, in which case they also continue at "head". + * + * It is tempting in slack-based scheme to not even use CAS for + * updates (similarly to Ladan-Mozes & Shavit). However, this + * cannot be done for head updates under the above link-forgetting + * mechanics because an update may leave head at a detached node. + * And while direct writes are possible for tail updates, they + * increase the risk of long retraversals, and hence long garbage + * chains, which can be much more costly than is worthwhile + * considering that the cost difference of performing a CAS vs + * write is smaller when they are not triggered on each operation + * (especially considering that writes and CASes equally require + * additional GC bookkeeping ("write barriers") that are sometimes + * more costly than the writes themselves because of contention). + * + * *** Overview of implementation *** + * + * We use a threshold-based approach to updates, with a slack + * threshold of two -- that is, we update head/tail when the + * current pointer appears to be two or more steps away from the + * first/last node. The slack value is hard-wired: a path greater + * than one is naturally implemented by checking equality of + * traversal pointers except when the list has only one element, + * in which case we keep slack threshold at one. Avoiding tracking + * explicit counts across method calls slightly simplifies an + * already-messy implementation. Using randomization would + * probably work better if there were a low-quality dirt-cheap + * per-thread one available, but even ThreadLocalRandom is too + * heavy for these purposes. + * + * With such a small slack threshold value, it is not worthwhile + * to augment this with path short-circuiting (i.e., unsplicing + * interior nodes) except in the case of cancellation/removal (see + * below). + * + * We allow both the head and tail fields to be null before any + * nodes are enqueued; initializing upon first append. This + * simplifies some other logic, as well as providing more + * efficient explicit control paths instead of letting JVMs insert + * implicit NullPointerExceptions when they are null. While not + * currently fully implemented, we also leave open the possibility + * of re-nulling these fields when empty (which is complicated to + * arrange, for little benefit.) + * + * All enqueue/dequeue operations are handled by the single method + * "xfer" with parameters indicating whether to act as some form + * of offer, put, poll, take, or transfer (each possibly with + * timeout). The relative complexity of using one monolithic + * method outweighs the code bulk and maintenance problems of + * using separate methods for each case. + * + * Operation consists of up to three phases. The first is + * implemented within method xfer, the second in tryAppend, and + * the third in method awaitMatch. + * + * 1. Try to match an existing node + * + * Starting at head, skip already-matched nodes until finding + * an unmatched node of opposite mode, if one exists, in which + * case matching it and returning, also if necessary updating + * head to one past the matched node (or the node itself if the + * list has no other unmatched nodes). If the CAS misses, then + * a loop retries advancing head by two steps until either + * success or the slack is at most two. By requiring that each + * attempt advances head by two (if applicable), we ensure that + * the slack does not grow without bound. Traversals also check + * if the initial head is now off-list, in which case they + * start at the new head. + * + * If no candidates are found and the call was untimed + * poll/offer, (argument "how" is NOW) return. + * + * 2. Try to append a new node (method tryAppend) + * + * Starting at current tail pointer, find the actual last node + * and try to append a new node (or if head was null, establish + * the first node). Nodes can be appended only if their + * predecessors are either already matched or are of the same + * mode. If we detect otherwise, then a new node with opposite + * mode must have been appended during traversal, so we must + * restart at phase 1. The traversal and update steps are + * otherwise similar to phase 1: Retrying upon CAS misses and + * checking for staleness. In particular, if a self-link is + * encountered, then we can safely jump to a node on the list + * by continuing the traversal at current head. + * + * On successful append, if the call was ASYNC, return. + * + * 3. Await match or cancellation (method awaitMatch) + * + * Wait for another thread to match node; instead cancelling if + * the current thread was interrupted or the wait timed out. On + * multiprocessors, we use front-of-queue spinning: If a node + * appears to be the first unmatched node in the queue, it + * spins a bit before blocking. In either case, before blocking + * it tries to unsplice any nodes between the current "head" + * and the first unmatched node. + * + * Front-of-queue spinning vastly improves performance of + * heavily contended queues. And so long as it is relatively + * brief and "quiet", spinning does not much impact performance + * of less-contended queues. During spins threads check their + * interrupt status and generate a thread-local random number + * to decide to occasionally perform a Thread.yield. While + * yield has underdefined specs, we assume that might it help, + * and will not hurt in limiting impact of spinning on busy + * systems. We also use smaller (1/2) spins for nodes that are + * not known to be front but whose predecessors have not + * blocked -- these "chained" spins avoid artifacts of + * front-of-queue rules which otherwise lead to alternating + * nodes spinning vs blocking. Further, front threads that + * represent phase changes (from data to request node or vice + * versa) compared to their predecessors receive additional + * chained spins, reflecting longer paths typically required to + * unblock threads during phase changes. + * + * + * ** Unlinking removed interior nodes ** + * + * In addition to minimizing garbage retention via self-linking + * described above, we also unlink removed interior nodes. These + * may arise due to timed out or interrupted waits, or calls to + * remove(x) or Iterator.remove. Normally, given a node that was + * at one time known to be the predecessor of some node s that is + * to be removed, we can unsplice s by CASing the next field of + * its predecessor if it still points to s (otherwise s must + * already have been removed or is now offlist). But there are two + * situations in which we cannot guarantee to make node s + * unreachable in this way: (1) If s is the trailing node of list + * (i.e., with null next), then it is pinned as the target node + * for appends, so can only be removed later after other nodes are + * appended. (2) We cannot necessarily unlink s given a + * predecessor node that is matched (including the case of being + * cancelled): the predecessor may already be unspliced, in which + * case some previous reachable node may still point to s. + * (For further explanation see Herlihy & Shavit "The Art of + * Multiprocessor Programming" chapter 9). Although, in both + * cases, we can rule out the need for further action if either s + * or its predecessor are (or can be made to be) at, or fall off + * from, the head of list. + * + * Without taking these into account, it would be possible for an + * unbounded number of supposedly removed nodes to remain + * reachable. Situations leading to such buildup are uncommon but + * can occur in practice; for example when a series of short timed + * calls to poll repeatedly time out but never otherwise fall off + * the list because of an untimed call to take at the front of the + * queue. + * + * When these cases arise, rather than always retraversing the + * entire list to find an actual predecessor to unlink (which + * won't help for case (1) anyway), we record a conservative + * estimate of possible unsplice failures (in "sweepVotes"). + * We trigger a full sweep when the estimate exceeds a threshold + * ("SWEEP_THRESHOLD") indicating the maximum number of estimated + * removal failures to tolerate before sweeping through, unlinking + * cancelled nodes that were not unlinked upon initial removal. + * We perform sweeps by the thread hitting threshold (rather than + * background threads or by spreading work to other threads) + * because in the main contexts in which removal occurs, the + * caller is already timed-out, cancelled, or performing a + * potentially O(n) operation (e.g. remove(x)), none of which are + * time-critical enough to warrant the overhead that alternatives + * would impose on other threads. + * + * Because the sweepVotes estimate is conservative, and because + * nodes become unlinked "naturally" as they fall off the head of + * the queue, and because we allow votes to accumulate even while + * sweeps are in progress, there are typically significantly fewer + * such nodes than estimated. Choice of a threshold value + * balances the likelihood of wasted effort and contention, versus + * providing a worst-case bound on retention of interior nodes in + * quiescent queues. The value defined below was chosen + * empirically to balance these under various timeout scenarios. + * + * Note that we cannot self-link unlinked interior nodes during + * sweeps. However, the associated garbage chains terminate when + * some successor ultimately falls off the head of the list and is + * self-linked. + */ + + /** True if on multiprocessor */ + private static final boolean MP = + Runtime.getRuntime().availableProcessors() > 1; + + /** + * The number of times to spin (with randomly interspersed calls + * to Thread.yield) on multiprocessor before blocking when a node + * is apparently the first waiter in the queue. See above for + * explanation. Must be a power of two. The value is empirically + * derived -- it works pretty well across a variety of processors, + * numbers of CPUs, and OSes. + */ + private static final int FRONT_SPINS = 1 << 7; + + /** + * The number of times to spin before blocking when a node is + * preceded by another node that is apparently spinning. Also + * serves as an increment to FRONT_SPINS on phase changes, and as + * base average frequency for yielding during spins. Must be a + * power of two. + */ + private static final int CHAINED_SPINS = FRONT_SPINS >>> 1; + + /** + * The maximum number of estimated removal failures (sweepVotes) + * to tolerate before sweeping through the queue unlinking + * cancelled nodes that were not unlinked upon initial + * removal. See above for explanation. The value must be at least + * two to avoid useless sweeps when removing trailing nodes. + */ + static final int SWEEP_THRESHOLD = 32; + + /** + * Queue nodes. Uses Object, not E, for items to allow forgetting + * them after use. Relies heavily on Unsafe mechanics to minimize + * unnecessary ordering constraints: Writes that are intrinsically + * ordered wrt other accesses or CASes use simple relaxed forms. + */ + static final class Node { + final boolean isData; // false if this is a request node + volatile Object item; // initially non-null if isData; CASed to match + volatile Node next; + volatile Thread waiter; // null until waiting + + // CAS methods for fields + final boolean casNext(Node cmp, Node val) { + return UNSAFE.compareAndSwapObject(this, nextOffset, cmp, val); + } + + final boolean casItem(Object cmp, Object val) { + // assert cmp == null || cmp.getClass() != Node.class; + return UNSAFE.compareAndSwapObject(this, itemOffset, cmp, val); + } + + /** + * Constructs a new node. Uses relaxed write because item can + * only be seen after publication via casNext. + */ + Node(Object item, boolean isData) { + UNSAFE.putObject(this, itemOffset, item); // relaxed write + this.isData = isData; + } + + /** + * Links node to itself to avoid garbage retention. Called + * only after CASing head field, so uses relaxed write. + */ + final void forgetNext() { + UNSAFE.putObject(this, nextOffset, this); + } + + /** + * Sets item to self and waiter to null, to avoid garbage + * retention after matching or cancelling. Uses relaxed writes + * because order is already constrained in the only calling + * contexts: item is forgotten only after volatile/atomic + * mechanics that extract items. Similarly, clearing waiter + * follows either CAS or return from park (if ever parked; + * else we don't care). + */ + final void forgetContents() { + UNSAFE.putObject(this, itemOffset, this); + UNSAFE.putObject(this, waiterOffset, null); + } + + /** + * Returns true if this node has been matched, including the + * case of artificial matches due to cancellation. + */ + final boolean isMatched() { + Object x = item; + return (x == this) || ((x == null) == isData); + } + + /** + * Returns true if this is an unmatched request node. + */ + final boolean isUnmatchedRequest() { + return !isData && item == null; + } + + /** + * Returns true if a node with the given mode cannot be + * appended to this node because this node is unmatched and + * has opposite data mode. + */ + final boolean cannotPrecede(boolean haveData) { + boolean d = isData; + Object x; + return d != haveData && (x = item) != this && (x != null) == d; + } + + /** + * Tries to artificially match a data node -- used by remove. + */ + final boolean tryMatchData() { + // assert isData; + Object x = item; + if (x != null && x != this && casItem(x, null)) { + LockSupport.unpark(waiter); + return true; + } + return false; + } + + private static final long serialVersionUID = -3375979862319811754L; + + // Unsafe mechanics + private static final sun.misc.Unsafe UNSAFE; + private static final long itemOffset; + private static final long nextOffset; + private static final long waiterOffset; + static { + try { + UNSAFE = sun.misc.Unsafe.getUnsafe(); + Class k = Node.class; + itemOffset = UNSAFE.objectFieldOffset + (k.getDeclaredField("item")); + nextOffset = UNSAFE.objectFieldOffset + (k.getDeclaredField("next")); + waiterOffset = UNSAFE.objectFieldOffset + (k.getDeclaredField("waiter")); + } catch (Exception e) { + throw new Error(e); + } + } + } + + /** head of the queue; null until first enqueue */ + transient volatile Node head; + + /** tail of the queue; null until first append */ + private transient volatile Node tail; + + /** The number of apparent failures to unsplice removed nodes */ + private transient volatile int sweepVotes; + + // CAS methods for fields + private boolean casTail(Node cmp, Node val) { + return UNSAFE.compareAndSwapObject(this, tailOffset, cmp, val); + } + + private boolean casHead(Node cmp, Node val) { + return UNSAFE.compareAndSwapObject(this, headOffset, cmp, val); + } + + private boolean casSweepVotes(int cmp, int val) { + return UNSAFE.compareAndSwapInt(this, sweepVotesOffset, cmp, val); + } + + /* + * Possible values for "how" argument in xfer method. + */ + private static final int NOW = 0; // for untimed poll, tryTransfer + private static final int ASYNC = 1; // for offer, put, add + private static final int SYNC = 2; // for transfer, take + private static final int TIMED = 3; // for timed poll, tryTransfer + + @SuppressWarnings("unchecked") + static E cast(Object item) { + // assert item == null || item.getClass() != Node.class; + return (E) item; + } + + /** + * Implements all queuing methods. See above for explanation. + * + * @param e the item or null for take + * @param haveData true if this is a put, else a take + * @param how NOW, ASYNC, SYNC, or TIMED + * @param nanos timeout in nanosecs, used only if mode is TIMED + * @return an item if matched, else e + * @throws NullPointerException if haveData mode but e is null + */ + private E xfer(E e, boolean haveData, int how, long nanos) { + if (haveData && (e == null)) + throw new NullPointerException(); + Node s = null; // the node to append, if needed + + retry: + for (;;) { // restart on append race + + for (Node h = head, p = h; p != null;) { // find & match first node + boolean isData = p.isData; + Object item = p.item; + if (item != p && (item != null) == isData) { // unmatched + if (isData == haveData) // can't match + break; + if (p.casItem(item, e)) { // match + for (Node q = p; q != h;) { + Node n = q.next; // update by 2 unless singleton + if (head == h && casHead(h, n == null ? q : n)) { + h.forgetNext(); + break; + } // advance and retry + if ((h = head) == null || + (q = h.next) == null || !q.isMatched()) + break; // unless slack < 2 + } + LockSupport.unpark(p.waiter); + return this.cast(item); + } + } + Node n = p.next; + p = (p != n) ? n : (h = head); // Use head if p offlist + } + + if (how != NOW) { // No matches available + if (s == null) + s = new Node(e, haveData); + Node pred = tryAppend(s, haveData); + if (pred == null) + continue retry; // lost race vs opposite mode + if (how != ASYNC) + return awaitMatch(s, pred, e, (how == TIMED), nanos); + } + return e; // not waiting + } + } + + /** + * Tries to append node s as tail. + * + * @param s the node to append + * @param haveData true if appending in data mode + * @return null on failure due to losing race with append in + * different mode, else s's predecessor, or s itself if no + * predecessor + */ + private Node tryAppend(Node s, boolean haveData) { + for (Node t = tail, p = t;;) { // move p to last node and append + Node n, u; // temps for reads of next & tail + if (p == null && (p = head) == null) { + if (casHead(null, s)) + return s; // initialize + } + else if (p.cannotPrecede(haveData)) + return null; // lost race vs opposite mode + else if ((n = p.next) != null) // not last; keep traversing + p = p != t && t != (u = tail) ? (t = u) : // stale tail + (p != n) ? n : null; // restart if off list + else if (!p.casNext(null, s)) + p = p.next; // re-read on CAS failure + else { + if (p != t) { // update if slack now >= 2 + while ((tail != t || !casTail(t, s)) && + (t = tail) != null && + (s = t.next) != null && // advance and retry + (s = s.next) != null && s != t); + } + return p; + } + } + } + + /** + * Spins/yields/blocks until node s is matched or caller gives up. + * + * @param s the waiting node + * @param pred the predecessor of s, or s itself if it has no + * predecessor, or null if unknown (the null case does not occur + * in any current calls but may in possible future extensions) + * @param e the comparison value for checking match + * @param timed if true, wait only until timeout elapses + * @param nanos timeout in nanosecs, used only if timed is true + * @return matched item, or e if unmatched on interrupt or timeout + */ + private E awaitMatch(Node s, Node pred, E e, boolean timed, long nanos) { + long lastTime = timed ? System.nanoTime() : 0L; + Thread w = Thread.currentThread(); + int spins = -1; // initialized after first item and cancel checks + ThreadLocalRandom randomYields = null; // bound if needed + + for (;;) { + Object item = s.item; + if (item != e) { // matched + // assert item != s; + s.forgetContents(); // avoid garbage + return this.cast(item); + } + if ((w.isInterrupted() || (timed && nanos <= 0)) && + s.casItem(e, s)) { // cancel + unsplice(pred, s); + return e; + } + + if (spins < 0) { // establish spins at/near front + if ((spins = spinsFor(pred, s.isData)) > 0) + randomYields = ThreadLocalRandom.current(); + } + else if (spins > 0) { // spin + --spins; + if (randomYields.nextInt(CHAINED_SPINS) == 0) + Thread.yield(); // occasionally yield + } + else if (s.waiter == null) { + s.waiter = w; // request unpark then recheck + } + else if (timed) { + long now = System.nanoTime(); + if ((nanos -= now - lastTime) > 0) + LockSupport.parkNanos(this, nanos); + lastTime = now; + } + else { + LockSupport.park(this); + } + } + } + + /** + * Returns spin/yield value for a node with given predecessor and + * data mode. See above for explanation. + */ + private static int spinsFor(Node pred, boolean haveData) { + if (MP && pred != null) { + if (pred.isData != haveData) // phase change + return FRONT_SPINS + CHAINED_SPINS; + if (pred.isMatched()) // probably at front + return FRONT_SPINS; + if (pred.waiter == null) // pred apparently spinning + return CHAINED_SPINS; + } + return 0; + } + + /* -------------- Traversal methods -------------- */ + + /** + * Returns the successor of p, or the head node if p.next has been + * linked to self, which will only be true if traversing with a + * stale pointer that is now off the list. + */ + final Node succ(Node p) { + Node next = p.next; + return (p == next) ? head : next; + } + + /** + * Returns the first unmatched node of the given mode, or null if + * none. Used by methods isEmpty, hasWaitingConsumer. + */ + private Node firstOfMode(boolean isData) { + for (Node p = head; p != null; p = succ(p)) { + if (!p.isMatched()) + return (p.isData == isData) ? p : null; + } + return null; + } + + /** + * Returns the item in the first unmatched node with isData; or + * null if none. Used by peek. + */ + private E firstDataItem() { + for (Node p = head; p != null; p = succ(p)) { + Object item = p.item; + if (p.isData) { + if (item != null && item != p) + return this.cast(item); + } + else if (item == null) + return null; + } + return null; + } + + /** + * Traverses and counts unmatched nodes of the given mode. + * Used by methods size and getWaitingConsumerCount. + */ + private int countOfMode(boolean data) { + int count = 0; + for (Node p = head; p != null; ) { + if (!p.isMatched()) { + if (p.isData != data) + return 0; + if (++count == Integer.MAX_VALUE) // saturated + break; + } + Node n = p.next; + if (n != p) + p = n; + else { + count = 0; + p = head; + } + } + return count; + } + + final class Itr implements Iterator { + private Node nextNode; // next node to return item for + private E nextItem; // the corresponding item + private Node lastRet; // last returned node, to support remove + private Node lastPred; // predecessor to unlink lastRet + + /** + * Moves to next node after prev, or first node if prev null. + */ + private void advance(Node prev) { + /* + * To track and avoid buildup of deleted nodes in the face + * of calls to both Queue.remove and Itr.remove, we must + * include variants of unsplice and sweep upon each + * advance: Upon Itr.remove, we may need to catch up links + * from lastPred, and upon other removes, we might need to + * skip ahead from stale nodes and unsplice deleted ones + * found while advancing. + */ + + Node r, b; // reset lastPred upon possible deletion of lastRet + if ((r = lastRet) != null && !r.isMatched()) + lastPred = r; // next lastPred is old lastRet + else if ((b = lastPred) == null || b.isMatched()) + lastPred = null; // at start of list + else { + Node s, n; // help with removal of lastPred.next + while ((s = b.next) != null && + s != b && s.isMatched() && + (n = s.next) != null && n != s) + b.casNext(s, n); + } + + this.lastRet = prev; + + for (Node p = prev, s, n;;) { + s = (p == null) ? head : p.next; + if (s == null) + break; + else if (s == p) { + p = null; + continue; + } + Object item = s.item; + if (s.isData) { + if (item != null && item != s) { + nextItem = LinkedTransferQueue.cast(item); + nextNode = s; + return; + } + } + else if (item == null) + break; + // assert s.isMatched(); + if (p == null) + p = s; + else if ((n = s.next) == null) + break; + else if (s == n) + p = null; + else + p.casNext(s, n); + } + nextNode = null; + nextItem = null; + } + + Itr() { + advance(null); + } + + public final boolean hasNext() { + return nextNode != null; + } + + public final E next() { + Node p = nextNode; + if (p == null) throw new NoSuchElementException(); + E e = nextItem; + advance(p); + return e; + } + + public final void remove() { + final Node lastRet = this.lastRet; + if (lastRet == null) + throw new IllegalStateException(); + this.lastRet = null; + if (lastRet.tryMatchData()) + unsplice(lastPred, lastRet); + } + } + + /* -------------- Removal methods -------------- */ + + /** + * Unsplices (now or later) the given deleted/cancelled node with + * the given predecessor. + * + * @param pred a node that was at one time known to be the + * predecessor of s, or null or s itself if s is/was at head + * @param s the node to be unspliced + */ + final void unsplice(Node pred, Node s) { + s.forgetContents(); // forget unneeded fields + /* + * See above for rationale. Briefly: if pred still points to + * s, try to unlink s. If s cannot be unlinked, because it is + * trailing node or pred might be unlinked, and neither pred + * nor s are head or offlist, add to sweepVotes, and if enough + * votes have accumulated, sweep. + */ + if (pred != null && pred != s && pred.next == s) { + Node n = s.next; + if (n == null || + (n != s && pred.casNext(s, n) && pred.isMatched())) { + for (;;) { // check if at, or could be, head + Node h = head; + if (h == pred || h == s || h == null) + return; // at head or list empty + if (!h.isMatched()) + break; + Node hn = h.next; + if (hn == null) + return; // now empty + if (hn != h && casHead(h, hn)) + h.forgetNext(); // advance head + } + if (pred.next != pred && s.next != s) { // recheck if offlist + for (;;) { // sweep now if enough votes + int v = sweepVotes; + if (v < SWEEP_THRESHOLD) { + if (casSweepVotes(v, v + 1)) + break; + } + else if (casSweepVotes(v, 0)) { + sweep(); + break; + } + } + } + } + } + } + + /** + * Unlinks matched (typically cancelled) nodes encountered in a + * traversal from head. + */ + private void sweep() { + for (Node p = head, s, n; p != null && (s = p.next) != null; ) { + if (!s.isMatched()) + // Unmatched nodes are never self-linked + p = s; + else if ((n = s.next) == null) // trailing node is pinned + break; + else if (s == n) // stale + // No need to also check for p == s, since that implies s == n + p = head; + else + p.casNext(s, n); + } + } + + /** + * Main implementation of remove(Object) + */ + private boolean findAndRemove(Object e) { + if (e != null) { + for (Node pred = null, p = head; p != null; ) { + Object item = p.item; + if (p.isData) { + if (item != null && item != p && e.equals(item) && + p.tryMatchData()) { + unsplice(pred, p); + return true; + } + } + else if (item == null) + break; + pred = p; + if ((p = p.next) == pred) { // stale + pred = null; + p = head; + } + } + } + return false; + } + + + /** + * Creates an initially empty {@code LinkedTransferQueue}. + */ + public LinkedTransferQueue() { + } + + /** + * Creates a {@code LinkedTransferQueue} + * initially containing the elements of the given collection, + * added in traversal order of the collection's iterator. + * + * @param c the collection of elements to initially contain + * @throws NullPointerException if the specified collection or any + * of its elements are null + */ + public LinkedTransferQueue(Collection c) { + this(); + addAll(c); + } + + /** + * Inserts the specified element at the tail of this queue. + * As the queue is unbounded, this method will never block. + * + * @throws NullPointerException if the specified element is null + */ + public void put(E e) { + xfer(e, true, ASYNC, 0); + } + + /** + * Inserts the specified element at the tail of this queue. + * As the queue is unbounded, this method will never block or + * return {@code false}. + * + * @return {@code true} (as specified by + * {@link BlockingQueue#offer(Object,long,TimeUnit) BlockingQueue.offer}) + * @throws NullPointerException if the specified element is null + */ + public boolean offer(E e, long timeout, TimeUnit unit) { + xfer(e, true, ASYNC, 0); + return true; + } + + /** + * Inserts the specified element at the tail of this queue. + * As the queue is unbounded, this method will never return {@code false}. + * + * @return {@code true} (as specified by {@link Queue#offer}) + * @throws NullPointerException if the specified element is null + */ + public boolean offer(E e) { + xfer(e, true, ASYNC, 0); + return true; + } + + /** + * Inserts the specified element at the tail of this queue. + * As the queue is unbounded, this method will never throw + * {@link IllegalStateException} or return {@code false}. + * + * @return {@code true} (as specified by {@link Collection#add}) + * @throws NullPointerException if the specified element is null + */ + public boolean add(E e) { + xfer(e, true, ASYNC, 0); + return true; + } + + /** + * Transfers the element to a waiting consumer immediately, if possible. + * + *

More precisely, transfers the specified element immediately + * if there exists a consumer already waiting to receive it (in + * {@link #take} or timed {@link #poll(long,TimeUnit) poll}), + * otherwise returning {@code false} without enqueuing the element. + * + * @throws NullPointerException if the specified element is null + */ + public boolean tryTransfer(E e) { + return xfer(e, true, NOW, 0) == null; + } + + /** + * Transfers the element to a consumer, waiting if necessary to do so. + * + *

More precisely, transfers the specified element immediately + * if there exists a consumer already waiting to receive it (in + * {@link #take} or timed {@link #poll(long,TimeUnit) poll}), + * else inserts the specified element at the tail of this queue + * and waits until the element is received by a consumer. + * + * @throws NullPointerException if the specified element is null + */ + public void transfer(E e) throws InterruptedException { + if (xfer(e, true, SYNC, 0) != null) { + Thread.interrupted(); // failure possible only due to interrupt + throw new InterruptedException(); + } + } + + /** + * Transfers the element to a consumer if it is possible to do so + * before the timeout elapses. + * + *

More precisely, transfers the specified element immediately + * if there exists a consumer already waiting to receive it (in + * {@link #take} or timed {@link #poll(long,TimeUnit) poll}), + * else inserts the specified element at the tail of this queue + * and waits until the element is received by a consumer, + * returning {@code false} if the specified wait time elapses + * before the element can be transferred. + * + * @throws NullPointerException if the specified element is null + */ + public boolean tryTransfer(E e, long timeout, TimeUnit unit) + throws InterruptedException { + if (xfer(e, true, TIMED, unit.toNanos(timeout)) == null) + return true; + if (!Thread.interrupted()) + return false; + throw new InterruptedException(); + } + + public E take() throws InterruptedException { + E e = xfer(null, false, SYNC, 0); + if (e != null) + return e; + Thread.interrupted(); + throw new InterruptedException(); + } + + public E poll(long timeout, TimeUnit unit) throws InterruptedException { + E e = xfer(null, false, TIMED, unit.toNanos(timeout)); + if (e != null || !Thread.interrupted()) + return e; + throw new InterruptedException(); + } + + public E poll() { + return xfer(null, false, NOW, 0); + } + + /** + * @throws NullPointerException {@inheritDoc} + * @throws IllegalArgumentException {@inheritDoc} + */ + public int drainTo(Collection c) { + if (c == null) + throw new NullPointerException(); + if (c == this) + throw new IllegalArgumentException(); + int n = 0; + E e; + while ( (e = poll()) != null) { + c.add(e); + ++n; + } + return n; + } + + /** + * @throws NullPointerException {@inheritDoc} + * @throws IllegalArgumentException {@inheritDoc} + */ + public int drainTo(Collection c, int maxElements) { + if (c == null) + throw new NullPointerException(); + if (c == this) + throw new IllegalArgumentException(); + int n = 0; + E e; + while (n < maxElements && (e = poll()) != null) { + c.add(e); + ++n; + } + return n; + } + + /** + * Returns an iterator over the elements in this queue in proper sequence. + * The elements will be returned in order from first (head) to last (tail). + * + *

The returned iterator is a "weakly consistent" iterator that + * will never throw {@link java.util.ConcurrentModificationException + * ConcurrentModificationException}, and guarantees to traverse + * elements as they existed upon construction of the iterator, and + * may (but is not guaranteed to) reflect any modifications + * subsequent to construction. + * + * @return an iterator over the elements in this queue in proper sequence + */ + public Iterator iterator() { + return new Itr(); + } + + public E peek() { + return firstDataItem(); + } + + /** + * Returns {@code true} if this queue contains no elements. + * + * @return {@code true} if this queue contains no elements + */ + public boolean isEmpty() { + for (Node p = head; p != null; p = succ(p)) { + if (!p.isMatched()) + return !p.isData; + } + return true; + } + + public boolean hasWaitingConsumer() { + return firstOfMode(false) != null; + } + + /** + * Returns the number of elements in this queue. If this queue + * contains more than {@code Integer.MAX_VALUE} elements, returns + * {@code Integer.MAX_VALUE}. + * + *

Beware that, unlike in most collections, this method is + * NOT a constant-time operation. Because of the + * asynchronous nature of these queues, determining the current + * number of elements requires an O(n) traversal. + * + * @return the number of elements in this queue + */ + public int size() { + return countOfMode(true); + } + + public int getWaitingConsumerCount() { + return countOfMode(false); + } + + /** + * Removes a single instance of the specified element from this queue, + * if it is present. More formally, removes an element {@code e} such + * that {@code o.equals(e)}, if this queue contains one or more such + * elements. + * Returns {@code true} if this queue contained the specified element + * (or equivalently, if this queue changed as a result of the call). + * + * @param o element to be removed from this queue, if present + * @return {@code true} if this queue changed as a result of the call + */ + public boolean remove(Object o) { + return findAndRemove(o); + } + + /** + * Returns {@code true} if this queue contains the specified element. + * More formally, returns {@code true} if and only if this queue contains + * at least one element {@code e} such that {@code o.equals(e)}. + * + * @param o object to be checked for containment in this queue + * @return {@code true} if this queue contains the specified element + */ + public boolean contains(Object o) { + if (o == null) return false; + for (Node p = head; p != null; p = succ(p)) { + Object item = p.item; + if (p.isData) { + if (item != null && item != p && o.equals(item)) + return true; + } + else if (item == null) + break; + } + return false; + } + + /** + * Always returns {@code Integer.MAX_VALUE} because a + * {@code LinkedTransferQueue} is not capacity constrained. + * + * @return {@code Integer.MAX_VALUE} (as specified by + * {@link BlockingQueue#remainingCapacity()}) + */ + public int remainingCapacity() { + return Integer.MAX_VALUE; + } + + /** + * Saves the state to a stream (that is, serializes it). + * + * @serialData All of the elements (each an {@code E}) in + * the proper order, followed by a null + * @param s the stream + */ + private void writeObject(java.io.ObjectOutputStream s) + throws java.io.IOException { + s.defaultWriteObject(); + for (E e : this) + s.writeObject(e); + // Use trailing null as sentinel + s.writeObject(null); + } + + /** + * Reconstitutes the Queue instance from a stream (that is, + * deserializes it). + * + * @param s the stream + */ + private void readObject(java.io.ObjectInputStream s) + throws java.io.IOException, ClassNotFoundException { + s.defaultReadObject(); + for (;;) { + @SuppressWarnings("unchecked") E item = (E) s.readObject(); + if (item == null) + break; + else + offer(item); + } + } + + // Unsafe mechanics + + private static final sun.misc.Unsafe UNSAFE; + private static final long headOffset; + private static final long tailOffset; + private static final long sweepVotesOffset; + static { + try { + UNSAFE = sun.misc.Unsafe.getUnsafe(); + Class k = LinkedTransferQueue.class; + headOffset = UNSAFE.objectFieldOffset + (k.getDeclaredField("head")); + tailOffset = UNSAFE.objectFieldOffset + (k.getDeclaredField("tail")); + sweepVotesOffset = UNSAFE.objectFieldOffset + (k.getDeclaredField("sweepVotes")); + } catch (Exception e) { + throw new Error(e); + } + } +} diff -r e1953d8b8338 -r c8af252ea9eb rt/emul/compact/src/main/java/java/util/concurrent/Phaser.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/Phaser.java Sat Mar 19 10:48:29 2016 +0100 @@ -0,0 +1,1152 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +package java.util.concurrent; + +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.atomic.AtomicReference; +import java.util.concurrent.locks.LockSupport; + +/** + * A reusable synchronization barrier, similar in functionality to + * {@link java.util.concurrent.CyclicBarrier CyclicBarrier} and + * {@link java.util.concurrent.CountDownLatch CountDownLatch} + * but supporting more flexible usage. + * + *

Registration. Unlike the case for other barriers, the + * number of parties registered to synchronize on a phaser + * may vary over time. Tasks may be registered at any time (using + * methods {@link #register}, {@link #bulkRegister}, or forms of + * constructors establishing initial numbers of parties), and + * optionally deregistered upon any arrival (using {@link + * #arriveAndDeregister}). As is the case with most basic + * synchronization constructs, registration and deregistration affect + * only internal counts; they do not establish any further internal + * bookkeeping, so tasks cannot query whether they are registered. + * (However, you can introduce such bookkeeping by subclassing this + * class.) + * + *

Synchronization. Like a {@code CyclicBarrier}, a {@code + * Phaser} may be repeatedly awaited. Method {@link + * #arriveAndAwaitAdvance} has effect analogous to {@link + * java.util.concurrent.CyclicBarrier#await CyclicBarrier.await}. Each + * generation of a phaser has an associated phase number. The phase + * number starts at zero, and advances when all parties arrive at the + * phaser, wrapping around to zero after reaching {@code + * Integer.MAX_VALUE}. The use of phase numbers enables independent + * control of actions upon arrival at a phaser and upon awaiting + * others, via two kinds of methods that may be invoked by any + * registered party: + * + *

    + * + *
  • Arrival. Methods {@link #arrive} and + * {@link #arriveAndDeregister} record arrival. These methods + * do not block, but return an associated arrival phase + * number; that is, the phase number of the phaser to which + * the arrival applied. When the final party for a given phase + * arrives, an optional action is performed and the phase + * advances. These actions are performed by the party + * triggering a phase advance, and are arranged by overriding + * method {@link #onAdvance(int, int)}, which also controls + * termination. Overriding this method is similar to, but more + * flexible than, providing a barrier action to a {@code + * CyclicBarrier}. + * + *
  • Waiting. Method {@link #awaitAdvance} requires an + * argument indicating an arrival phase number, and returns when + * the phaser advances to (or is already at) a different phase. + * Unlike similar constructions using {@code CyclicBarrier}, + * method {@code awaitAdvance} continues to wait even if the + * waiting thread is interrupted. Interruptible and timeout + * versions are also available, but exceptions encountered while + * tasks wait interruptibly or with timeout do not change the + * state of the phaser. If necessary, you can perform any + * associated recovery within handlers of those exceptions, + * often after invoking {@code forceTermination}. Phasers may + * also be used by tasks executing in a {@link ForkJoinPool}, + * which will ensure sufficient parallelism to execute tasks + * when others are blocked waiting for a phase to advance. + * + *
+ * + *

Termination. A phaser may enter a termination + * state, that may be checked using method {@link #isTerminated}. Upon + * termination, all synchronization methods immediately return without + * waiting for advance, as indicated by a negative return value. + * Similarly, attempts to register upon termination have no effect. + * Termination is triggered when an invocation of {@code onAdvance} + * returns {@code true}. The default implementation returns {@code + * true} if a deregistration has caused the number of registered + * parties to become zero. As illustrated below, when phasers control + * actions with a fixed number of iterations, it is often convenient + * to override this method to cause termination when the current phase + * number reaches a threshold. Method {@link #forceTermination} is + * also available to abruptly release waiting threads and allow them + * to terminate. + * + *

Tiering. Phasers may be tiered (i.e., + * constructed in tree structures) to reduce contention. Phasers with + * large numbers of parties that would otherwise experience heavy + * synchronization contention costs may instead be set up so that + * groups of sub-phasers share a common parent. This may greatly + * increase throughput even though it incurs greater per-operation + * overhead. + * + *

In a tree of tiered phasers, registration and deregistration of + * child phasers with their parent are managed automatically. + * Whenever the number of registered parties of a child phaser becomes + * non-zero (as established in the {@link #Phaser(Phaser,int)} + * constructor, {@link #register}, or {@link #bulkRegister}), the + * child phaser is registered with its parent. Whenever the number of + * registered parties becomes zero as the result of an invocation of + * {@link #arriveAndDeregister}, the child phaser is deregistered + * from its parent. + * + *

Monitoring. While synchronization methods may be invoked + * only by registered parties, the current state of a phaser may be + * monitored by any caller. At any given moment there are {@link + * #getRegisteredParties} parties in total, of which {@link + * #getArrivedParties} have arrived at the current phase ({@link + * #getPhase}). When the remaining ({@link #getUnarrivedParties}) + * parties arrive, the phase advances. The values returned by these + * methods may reflect transient states and so are not in general + * useful for synchronization control. Method {@link #toString} + * returns snapshots of these state queries in a form convenient for + * informal monitoring. + * + *

Sample usages: + * + *

A {@code Phaser} may be used instead of a {@code CountDownLatch} + * to control a one-shot action serving a variable number of parties. + * The typical idiom is for the method setting this up to first + * register, then start the actions, then deregister, as in: + * + *

 {@code
+ * void runTasks(List tasks) {
+ *   final Phaser phaser = new Phaser(1); // "1" to register self
+ *   // create and start threads
+ *   for (final Runnable task : tasks) {
+ *     phaser.register();
+ *     new Thread() {
+ *       public void run() {
+ *         phaser.arriveAndAwaitAdvance(); // await all creation
+ *         task.run();
+ *       }
+ *     }.start();
+ *   }
+ *
+ *   // allow threads to start and deregister self
+ *   phaser.arriveAndDeregister();
+ * }}
+ * + *

One way to cause a set of threads to repeatedly perform actions + * for a given number of iterations is to override {@code onAdvance}: + * + *

 {@code
+ * void startTasks(List tasks, final int iterations) {
+ *   final Phaser phaser = new Phaser() {
+ *     protected boolean onAdvance(int phase, int registeredParties) {
+ *       return phase >= iterations || registeredParties == 0;
+ *     }
+ *   };
+ *   phaser.register();
+ *   for (final Runnable task : tasks) {
+ *     phaser.register();
+ *     new Thread() {
+ *       public void run() {
+ *         do {
+ *           task.run();
+ *           phaser.arriveAndAwaitAdvance();
+ *         } while (!phaser.isTerminated());
+ *       }
+ *     }.start();
+ *   }
+ *   phaser.arriveAndDeregister(); // deregister self, don't wait
+ * }}
+ * + * If the main task must later await termination, it + * may re-register and then execute a similar loop: + *
 {@code
+ *   // ...
+ *   phaser.register();
+ *   while (!phaser.isTerminated())
+ *     phaser.arriveAndAwaitAdvance();}
+ * + *

Related constructions may be used to await particular phase numbers + * in contexts where you are sure that the phase will never wrap around + * {@code Integer.MAX_VALUE}. For example: + * + *

 {@code
+ * void awaitPhase(Phaser phaser, int phase) {
+ *   int p = phaser.register(); // assumes caller not already registered
+ *   while (p < phase) {
+ *     if (phaser.isTerminated())
+ *       // ... deal with unexpected termination
+ *     else
+ *       p = phaser.arriveAndAwaitAdvance();
+ *   }
+ *   phaser.arriveAndDeregister();
+ * }}
+ * + * + *

To create a set of {@code n} tasks using a tree of phasers, you + * could use code of the following form, assuming a Task class with a + * constructor accepting a {@code Phaser} that it registers with upon + * construction. After invocation of {@code build(new Task[n], 0, n, + * new Phaser())}, these tasks could then be started, for example by + * submitting to a pool: + * + *

 {@code
+ * void build(Task[] tasks, int lo, int hi, Phaser ph) {
+ *   if (hi - lo > TASKS_PER_PHASER) {
+ *     for (int i = lo; i < hi; i += TASKS_PER_PHASER) {
+ *       int j = Math.min(i + TASKS_PER_PHASER, hi);
+ *       build(tasks, i, j, new Phaser(ph));
+ *     }
+ *   } else {
+ *     for (int i = lo; i < hi; ++i)
+ *       tasks[i] = new Task(ph);
+ *       // assumes new Task(ph) performs ph.register()
+ *   }
+ * }}
+ * + * The best value of {@code TASKS_PER_PHASER} depends mainly on + * expected synchronization rates. A value as low as four may + * be appropriate for extremely small per-phase task bodies (thus + * high rates), or up to hundreds for extremely large ones. + * + *

Implementation notes: This implementation restricts the + * maximum number of parties to 65535. Attempts to register additional + * parties result in {@code IllegalStateException}. However, you can and + * should create tiered phasers to accommodate arbitrarily large sets + * of participants. + * + * @since 1.7 + * @author Doug Lea + */ +public class Phaser { + /* + * This class implements an extension of X10 "clocks". Thanks to + * Vijay Saraswat for the idea, and to Vivek Sarkar for + * enhancements to extend functionality. + */ + + /** + * Primary state representation, holding four bit-fields: + * + * unarrived -- the number of parties yet to hit barrier (bits 0-15) + * parties -- the number of parties to wait (bits 16-31) + * phase -- the generation of the barrier (bits 32-62) + * terminated -- set if barrier is terminated (bit 63 / sign) + * + * Except that a phaser with no registered parties is + * distinguished by the otherwise illegal state of having zero + * parties and one unarrived parties (encoded as EMPTY below). + * + * To efficiently maintain atomicity, these values are packed into + * a single (atomic) long. Good performance relies on keeping + * state decoding and encoding simple, and keeping race windows + * short. + * + * All state updates are performed via CAS except initial + * registration of a sub-phaser (i.e., one with a non-null + * parent). In this (relatively rare) case, we use built-in + * synchronization to lock while first registering with its + * parent. + * + * The phase of a subphaser is allowed to lag that of its + * ancestors until it is actually accessed -- see method + * reconcileState. + */ + private volatile long state; + + private static final int MAX_PARTIES = 0xffff; + private static final int MAX_PHASE = Integer.MAX_VALUE; + private static final int PARTIES_SHIFT = 16; + private static final int PHASE_SHIFT = 32; + private static final int UNARRIVED_MASK = 0xffff; // to mask ints + private static final long PARTIES_MASK = 0xffff0000L; // to mask longs + private static final long TERMINATION_BIT = 1L << 63; + + // some special values + private static final int ONE_ARRIVAL = 1; + private static final int ONE_PARTY = 1 << PARTIES_SHIFT; + private static final int EMPTY = 1; + + // The following unpacking methods are usually manually inlined + + private static int unarrivedOf(long s) { + int counts = (int)s; + return (counts == EMPTY) ? 0 : counts & UNARRIVED_MASK; + } + + private static int partiesOf(long s) { + return (int)s >>> PARTIES_SHIFT; + } + + private static int phaseOf(long s) { + return (int)(s >>> PHASE_SHIFT); + } + + private static int arrivedOf(long s) { + int counts = (int)s; + return (counts == EMPTY) ? 0 : + (counts >>> PARTIES_SHIFT) - (counts & UNARRIVED_MASK); + } + + /** + * The parent of this phaser, or null if none + */ + private final Phaser parent; + + /** + * The root of phaser tree. Equals this if not in a tree. + */ + private final Phaser root; + + /** + * Heads of Treiber stacks for waiting threads. To eliminate + * contention when releasing some threads while adding others, we + * use two of them, alternating across even and odd phases. + * Subphasers share queues with root to speed up releases. + */ + private final AtomicReference evenQ; + private final AtomicReference oddQ; + + private AtomicReference queueFor(int phase) { + return ((phase & 1) == 0) ? evenQ : oddQ; + } + + /** + * Returns message string for bounds exceptions on arrival. + */ + private String badArrive(long s) { + return "Attempted arrival of unregistered party for " + + stateToString(s); + } + + /** + * Returns message string for bounds exceptions on registration. + */ + private String badRegister(long s) { + return "Attempt to register more than " + + MAX_PARTIES + " parties for " + stateToString(s); + } + + /** + * Main implementation for methods arrive and arriveAndDeregister. + * Manually tuned to speed up and minimize race windows for the + * common case of just decrementing unarrived field. + * + * @param deregister false for arrive, true for arriveAndDeregister + */ + private int doArrive(boolean deregister) { + int adj = deregister ? ONE_ARRIVAL|ONE_PARTY : ONE_ARRIVAL; + final Phaser root = this.root; + for (;;) { + long s = (root == this) ? state : reconcileState(); + int phase = (int)(s >>> PHASE_SHIFT); + int counts = (int)s; + int unarrived = (counts & UNARRIVED_MASK) - 1; + if (phase < 0) + return phase; + else if (counts == EMPTY || unarrived < 0) { + if (root == this || reconcileState() == s) + throw new IllegalStateException(badArrive(s)); + } + else if (UNSAFE.compareAndSwapLong(this, stateOffset, s, s-=adj)) { + if (unarrived == 0) { + long n = s & PARTIES_MASK; // base of next state + int nextUnarrived = (int)n >>> PARTIES_SHIFT; + if (root != this) + return parent.doArrive(nextUnarrived == 0); + if (onAdvance(phase, nextUnarrived)) + n |= TERMINATION_BIT; + else if (nextUnarrived == 0) + n |= EMPTY; + else + n |= nextUnarrived; + n |= (long)((phase + 1) & MAX_PHASE) << PHASE_SHIFT; + UNSAFE.compareAndSwapLong(this, stateOffset, s, n); + releaseWaiters(phase); + } + return phase; + } + } + } + + /** + * Implementation of register, bulkRegister + * + * @param registrations number to add to both parties and + * unarrived fields. Must be greater than zero. + */ + private int doRegister(int registrations) { + // adjustment to state + long adj = ((long)registrations << PARTIES_SHIFT) | registrations; + final Phaser parent = this.parent; + int phase; + for (;;) { + long s = state; + int counts = (int)s; + int parties = counts >>> PARTIES_SHIFT; + int unarrived = counts & UNARRIVED_MASK; + if (registrations > MAX_PARTIES - parties) + throw new IllegalStateException(badRegister(s)); + else if ((phase = (int)(s >>> PHASE_SHIFT)) < 0) + break; + else if (counts != EMPTY) { // not 1st registration + if (parent == null || reconcileState() == s) { + if (unarrived == 0) // wait out advance + root.internalAwaitAdvance(phase, null); + else if (UNSAFE.compareAndSwapLong(this, stateOffset, + s, s + adj)) + break; + } + } + else if (parent == null) { // 1st root registration + long next = ((long)phase << PHASE_SHIFT) | adj; + if (UNSAFE.compareAndSwapLong(this, stateOffset, s, next)) + break; + } + else { + synchronized (this) { // 1st sub registration + if (state == s) { // recheck under lock + parent.doRegister(1); + do { // force current phase + phase = (int)(root.state >>> PHASE_SHIFT); + // assert phase < 0 || (int)state == EMPTY; + } while (!UNSAFE.compareAndSwapLong + (this, stateOffset, state, + ((long)phase << PHASE_SHIFT) | adj)); + break; + } + } + } + } + return phase; + } + + /** + * Resolves lagged phase propagation from root if necessary. + * Reconciliation normally occurs when root has advanced but + * subphasers have not yet done so, in which case they must finish + * their own advance by setting unarrived to parties (or if + * parties is zero, resetting to unregistered EMPTY state). + * However, this method may also be called when "floating" + * subphasers with possibly some unarrived parties are merely + * catching up to current phase, in which case counts are + * unaffected. + * + * @return reconciled state + */ + private long reconcileState() { + final Phaser root = this.root; + long s = state; + if (root != this) { + int phase, u, p; + // CAS root phase with current parties; possibly trip unarrived + while ((phase = (int)(root.state >>> PHASE_SHIFT)) != + (int)(s >>> PHASE_SHIFT) && + !UNSAFE.compareAndSwapLong + (this, stateOffset, s, + s = (((long)phase << PHASE_SHIFT) | + (s & PARTIES_MASK) | + ((p = (int)s >>> PARTIES_SHIFT) == 0 ? EMPTY : + (u = (int)s & UNARRIVED_MASK) == 0 ? p : u)))) + s = state; + } + return s; + } + + /** + * Creates a new phaser with no initially registered parties, no + * parent, and initial phase number 0. Any thread using this + * phaser will need to first register for it. + */ + public Phaser() { + this(null, 0); + } + + /** + * Creates a new phaser with the given number of registered + * unarrived parties, no parent, and initial phase number 0. + * + * @param parties the number of parties required to advance to the + * next phase + * @throws IllegalArgumentException if parties less than zero + * or greater than the maximum number of parties supported + */ + public Phaser(int parties) { + this(null, parties); + } + + /** + * Equivalent to {@link #Phaser(Phaser, int) Phaser(parent, 0)}. + * + * @param parent the parent phaser + */ + public Phaser(Phaser parent) { + this(parent, 0); + } + + /** + * Creates a new phaser with the given parent and number of + * registered unarrived parties. When the given parent is non-null + * and the given number of parties is greater than zero, this + * child phaser is registered with its parent. + * + * @param parent the parent phaser + * @param parties the number of parties required to advance to the + * next phase + * @throws IllegalArgumentException if parties less than zero + * or greater than the maximum number of parties supported + */ + public Phaser(Phaser parent, int parties) { + if (parties >>> PARTIES_SHIFT != 0) + throw new IllegalArgumentException("Illegal number of parties"); + int phase = 0; + this.parent = parent; + if (parent != null) { + final Phaser root = parent.root; + this.root = root; + this.evenQ = root.evenQ; + this.oddQ = root.oddQ; + if (parties != 0) + phase = parent.doRegister(1); + } + else { + this.root = this; + this.evenQ = new AtomicReference(); + this.oddQ = new AtomicReference(); + } + this.state = (parties == 0) ? (long)EMPTY : + ((long)phase << PHASE_SHIFT) | + ((long)parties << PARTIES_SHIFT) | + ((long)parties); + } + + /** + * Adds a new unarrived party to this phaser. If an ongoing + * invocation of {@link #onAdvance} is in progress, this method + * may await its completion before returning. If this phaser has + * a parent, and this phaser previously had no registered parties, + * this child phaser is also registered with its parent. If + * this phaser is terminated, the attempt to register has + * no effect, and a negative value is returned. + * + * @return the arrival phase number to which this registration + * applied. If this value is negative, then this phaser has + * terminated, in which case registration has no effect. + * @throws IllegalStateException if attempting to register more + * than the maximum supported number of parties + */ + public int register() { + return doRegister(1); + } + + /** + * Adds the given number of new unarrived parties to this phaser. + * If an ongoing invocation of {@link #onAdvance} is in progress, + * this method may await its completion before returning. If this + * phaser has a parent, and the given number of parties is greater + * than zero, and this phaser previously had no registered + * parties, this child phaser is also registered with its parent. + * If this phaser is terminated, the attempt to register has no + * effect, and a negative value is returned. + * + * @param parties the number of additional parties required to + * advance to the next phase + * @return the arrival phase number to which this registration + * applied. If this value is negative, then this phaser has + * terminated, in which case registration has no effect. + * @throws IllegalStateException if attempting to register more + * than the maximum supported number of parties + * @throws IllegalArgumentException if {@code parties < 0} + */ + public int bulkRegister(int parties) { + if (parties < 0) + throw new IllegalArgumentException(); + if (parties == 0) + return getPhase(); + return doRegister(parties); + } + + /** + * Arrives at this phaser, without waiting for others to arrive. + * + *

It is a usage error for an unregistered party to invoke this + * method. However, this error may result in an {@code + * IllegalStateException} only upon some subsequent operation on + * this phaser, if ever. + * + * @return the arrival phase number, or a negative value if terminated + * @throws IllegalStateException if not terminated and the number + * of unarrived parties would become negative + */ + public int arrive() { + return doArrive(false); + } + + /** + * Arrives at this phaser and deregisters from it without waiting + * for others to arrive. Deregistration reduces the number of + * parties required to advance in future phases. If this phaser + * has a parent, and deregistration causes this phaser to have + * zero parties, this phaser is also deregistered from its parent. + * + *

It is a usage error for an unregistered party to invoke this + * method. However, this error may result in an {@code + * IllegalStateException} only upon some subsequent operation on + * this phaser, if ever. + * + * @return the arrival phase number, or a negative value if terminated + * @throws IllegalStateException if not terminated and the number + * of registered or unarrived parties would become negative + */ + public int arriveAndDeregister() { + return doArrive(true); + } + + /** + * Arrives at this phaser and awaits others. Equivalent in effect + * to {@code awaitAdvance(arrive())}. If you need to await with + * interruption or timeout, you can arrange this with an analogous + * construction using one of the other forms of the {@code + * awaitAdvance} method. If instead you need to deregister upon + * arrival, use {@code awaitAdvance(arriveAndDeregister())}. + * + *

It is a usage error for an unregistered party to invoke this + * method. However, this error may result in an {@code + * IllegalStateException} only upon some subsequent operation on + * this phaser, if ever. + * + * @return the arrival phase number, or the (negative) + * {@linkplain #getPhase() current phase} if terminated + * @throws IllegalStateException if not terminated and the number + * of unarrived parties would become negative + */ + public int arriveAndAwaitAdvance() { + // Specialization of doArrive+awaitAdvance eliminating some reads/paths + final Phaser root = this.root; + for (;;) { + long s = (root == this) ? state : reconcileState(); + int phase = (int)(s >>> PHASE_SHIFT); + int counts = (int)s; + int unarrived = (counts & UNARRIVED_MASK) - 1; + if (phase < 0) + return phase; + else if (counts == EMPTY || unarrived < 0) { + if (reconcileState() == s) + throw new IllegalStateException(badArrive(s)); + } + else if (UNSAFE.compareAndSwapLong(this, stateOffset, s, + s -= ONE_ARRIVAL)) { + if (unarrived != 0) + return root.internalAwaitAdvance(phase, null); + if (root != this) + return parent.arriveAndAwaitAdvance(); + long n = s & PARTIES_MASK; // base of next state + int nextUnarrived = (int)n >>> PARTIES_SHIFT; + if (onAdvance(phase, nextUnarrived)) + n |= TERMINATION_BIT; + else if (nextUnarrived == 0) + n |= EMPTY; + else + n |= nextUnarrived; + int nextPhase = (phase + 1) & MAX_PHASE; + n |= (long)nextPhase << PHASE_SHIFT; + if (!UNSAFE.compareAndSwapLong(this, stateOffset, s, n)) + return (int)(state >>> PHASE_SHIFT); // terminated + releaseWaiters(phase); + return nextPhase; + } + } + } + + /** + * Awaits the phase of this phaser to advance from the given phase + * value, returning immediately if the current phase is not equal + * to the given phase value or this phaser is terminated. + * + * @param phase an arrival phase number, or negative value if + * terminated; this argument is normally the value returned by a + * previous call to {@code arrive} or {@code arriveAndDeregister}. + * @return the next arrival phase number, or the argument if it is + * negative, or the (negative) {@linkplain #getPhase() current phase} + * if terminated + */ + public int awaitAdvance(int phase) { + final Phaser root = this.root; + long s = (root == this) ? state : reconcileState(); + int p = (int)(s >>> PHASE_SHIFT); + if (phase < 0) + return phase; + if (p == phase) + return root.internalAwaitAdvance(phase, null); + return p; + } + + /** + * Awaits the phase of this phaser to advance from the given phase + * value, throwing {@code InterruptedException} if interrupted + * while waiting, or returning immediately if the current phase is + * not equal to the given phase value or this phaser is + * terminated. + * + * @param phase an arrival phase number, or negative value if + * terminated; this argument is normally the value returned by a + * previous call to {@code arrive} or {@code arriveAndDeregister}. + * @return the next arrival phase number, or the argument if it is + * negative, or the (negative) {@linkplain #getPhase() current phase} + * if terminated + * @throws InterruptedException if thread interrupted while waiting + */ + public int awaitAdvanceInterruptibly(int phase) + throws InterruptedException { + final Phaser root = this.root; + long s = (root == this) ? state : reconcileState(); + int p = (int)(s >>> PHASE_SHIFT); + if (phase < 0) + return phase; + if (p == phase) { + QNode node = new QNode(this, phase, true, false, 0L); + p = root.internalAwaitAdvance(phase, node); + if (node.wasInterrupted) + throw new InterruptedException(); + } + return p; + } + + /** + * Awaits the phase of this phaser to advance from the given phase + * value or the given timeout to elapse, throwing {@code + * InterruptedException} if interrupted while waiting, or + * returning immediately if the current phase is not equal to the + * given phase value or this phaser is terminated. + * + * @param phase an arrival phase number, or negative value if + * terminated; this argument is normally the value returned by a + * previous call to {@code arrive} or {@code arriveAndDeregister}. + * @param timeout how long to wait before giving up, in units of + * {@code unit} + * @param unit a {@code TimeUnit} determining how to interpret the + * {@code timeout} parameter + * @return the next arrival phase number, or the argument if it is + * negative, or the (negative) {@linkplain #getPhase() current phase} + * if terminated + * @throws InterruptedException if thread interrupted while waiting + * @throws TimeoutException if timed out while waiting + */ + public int awaitAdvanceInterruptibly(int phase, + long timeout, TimeUnit unit) + throws InterruptedException, TimeoutException { + long nanos = unit.toNanos(timeout); + final Phaser root = this.root; + long s = (root == this) ? state : reconcileState(); + int p = (int)(s >>> PHASE_SHIFT); + if (phase < 0) + return phase; + if (p == phase) { + QNode node = new QNode(this, phase, true, true, nanos); + p = root.internalAwaitAdvance(phase, node); + if (node.wasInterrupted) + throw new InterruptedException(); + else if (p == phase) + throw new TimeoutException(); + } + return p; + } + + /** + * Forces this phaser to enter termination state. Counts of + * registered parties are unaffected. If this phaser is a member + * of a tiered set of phasers, then all of the phasers in the set + * are terminated. If this phaser is already terminated, this + * method has no effect. This method may be useful for + * coordinating recovery after one or more tasks encounter + * unexpected exceptions. + */ + public void forceTermination() { + // Only need to change root state + final Phaser root = this.root; + long s; + while ((s = root.state) >= 0) { + if (UNSAFE.compareAndSwapLong(root, stateOffset, + s, s | TERMINATION_BIT)) { + // signal all threads + releaseWaiters(0); + releaseWaiters(1); + return; + } + } + } + + /** + * Returns the current phase number. The maximum phase number is + * {@code Integer.MAX_VALUE}, after which it restarts at + * zero. Upon termination, the phase number is negative, + * in which case the prevailing phase prior to termination + * may be obtained via {@code getPhase() + Integer.MIN_VALUE}. + * + * @return the phase number, or a negative value if terminated + */ + public final int getPhase() { + return (int)(root.state >>> PHASE_SHIFT); + } + + /** + * Returns the number of parties registered at this phaser. + * + * @return the number of parties + */ + public int getRegisteredParties() { + return partiesOf(state); + } + + /** + * Returns the number of registered parties that have arrived at + * the current phase of this phaser. If this phaser has terminated, + * the returned value is meaningless and arbitrary. + * + * @return the number of arrived parties + */ + public int getArrivedParties() { + return arrivedOf(reconcileState()); + } + + /** + * Returns the number of registered parties that have not yet + * arrived at the current phase of this phaser. If this phaser has + * terminated, the returned value is meaningless and arbitrary. + * + * @return the number of unarrived parties + */ + public int getUnarrivedParties() { + return unarrivedOf(reconcileState()); + } + + /** + * Returns the parent of this phaser, or {@code null} if none. + * + * @return the parent of this phaser, or {@code null} if none + */ + public Phaser getParent() { + return parent; + } + + /** + * Returns the root ancestor of this phaser, which is the same as + * this phaser if it has no parent. + * + * @return the root ancestor of this phaser + */ + public Phaser getRoot() { + return root; + } + + /** + * Returns {@code true} if this phaser has been terminated. + * + * @return {@code true} if this phaser has been terminated + */ + public boolean isTerminated() { + return root.state < 0L; + } + + /** + * Overridable method to perform an action upon impending phase + * advance, and to control termination. This method is invoked + * upon arrival of the party advancing this phaser (when all other + * waiting parties are dormant). If this method returns {@code + * true}, this phaser will be set to a final termination state + * upon advance, and subsequent calls to {@link #isTerminated} + * will return true. Any (unchecked) Exception or Error thrown by + * an invocation of this method is propagated to the party + * attempting to advance this phaser, in which case no advance + * occurs. + * + *

The arguments to this method provide the state of the phaser + * prevailing for the current transition. The effects of invoking + * arrival, registration, and waiting methods on this phaser from + * within {@code onAdvance} are unspecified and should not be + * relied on. + * + *

If this phaser is a member of a tiered set of phasers, then + * {@code onAdvance} is invoked only for its root phaser on each + * advance. + * + *

To support the most common use cases, the default + * implementation of this method returns {@code true} when the + * number of registered parties has become zero as the result of a + * party invoking {@code arriveAndDeregister}. You can disable + * this behavior, thus enabling continuation upon future + * registrations, by overriding this method to always return + * {@code false}: + * + *

 {@code
+     * Phaser phaser = new Phaser() {
+     *   protected boolean onAdvance(int phase, int parties) { return false; }
+     * }}
+ * + * @param phase the current phase number on entry to this method, + * before this phaser is advanced + * @param registeredParties the current number of registered parties + * @return {@code true} if this phaser should terminate + */ + protected boolean onAdvance(int phase, int registeredParties) { + return registeredParties == 0; + } + + /** + * Returns a string identifying this phaser, as well as its + * state. The state, in brackets, includes the String {@code + * "phase = "} followed by the phase number, {@code "parties = "} + * followed by the number of registered parties, and {@code + * "arrived = "} followed by the number of arrived parties. + * + * @return a string identifying this phaser, as well as its state + */ + public String toString() { + return stateToString(reconcileState()); + } + + /** + * Implementation of toString and string-based error messages + */ + private String stateToString(long s) { + return super.toString() + + "[phase = " + phaseOf(s) + + " parties = " + partiesOf(s) + + " arrived = " + arrivedOf(s) + "]"; + } + + // Waiting mechanics + + /** + * Removes and signals threads from queue for phase. + */ + private void releaseWaiters(int phase) { + QNode q; // first element of queue + Thread t; // its thread + AtomicReference head = (phase & 1) == 0 ? evenQ : oddQ; + while ((q = head.get()) != null && + q.phase != (int)(root.state >>> PHASE_SHIFT)) { + if (head.compareAndSet(q, q.next) && + (t = q.thread) != null) { + q.thread = null; + LockSupport.unpark(t); + } + } + } + + /** + * Variant of releaseWaiters that additionally tries to remove any + * nodes no longer waiting for advance due to timeout or + * interrupt. Currently, nodes are removed only if they are at + * head of queue, which suffices to reduce memory footprint in + * most usages. + * + * @return current phase on exit + */ + private int abortWait(int phase) { + AtomicReference head = (phase & 1) == 0 ? evenQ : oddQ; + for (;;) { + Thread t; + QNode q = head.get(); + int p = (int)(root.state >>> PHASE_SHIFT); + if (q == null || ((t = q.thread) != null && q.phase == p)) + return p; + if (head.compareAndSet(q, q.next) && t != null) { + q.thread = null; + LockSupport.unpark(t); + } + } + } + + /** The number of CPUs, for spin control */ + private static final int NCPU = Runtime.getRuntime().availableProcessors(); + + /** + * The number of times to spin before blocking while waiting for + * advance, per arrival while waiting. On multiprocessors, fully + * blocking and waking up a large number of threads all at once is + * usually a very slow process, so we use rechargeable spins to + * avoid it when threads regularly arrive: When a thread in + * internalAwaitAdvance notices another arrival before blocking, + * and there appear to be enough CPUs available, it spins + * SPINS_PER_ARRIVAL more times before blocking. The value trades + * off good-citizenship vs big unnecessary slowdowns. + */ + static final int SPINS_PER_ARRIVAL = (NCPU < 2) ? 1 : 1 << 8; + + /** + * Possibly blocks and waits for phase to advance unless aborted. + * Call only from root node. + * + * @param phase current phase + * @param node if non-null, the wait node to track interrupt and timeout; + * if null, denotes noninterruptible wait + * @return current phase + */ + private int internalAwaitAdvance(int phase, QNode node) { + releaseWaiters(phase-1); // ensure old queue clean + boolean queued = false; // true when node is enqueued + int lastUnarrived = 0; // to increase spins upon change + int spins = SPINS_PER_ARRIVAL; + long s; + int p; + while ((p = (int)((s = state) >>> PHASE_SHIFT)) == phase) { + if (node == null) { // spinning in noninterruptible mode + int unarrived = (int)s & UNARRIVED_MASK; + if (unarrived != lastUnarrived && + (lastUnarrived = unarrived) < NCPU) + spins += SPINS_PER_ARRIVAL; + boolean interrupted = Thread.interrupted(); + if (interrupted || --spins < 0) { // need node to record intr + node = new QNode(this, phase, false, false, 0L); + node.wasInterrupted = interrupted; + } + } + else if (node.isReleasable()) // done or aborted + break; + else if (!queued) { // push onto queue + AtomicReference head = (phase & 1) == 0 ? evenQ : oddQ; + QNode q = node.next = head.get(); + if ((q == null || q.phase == phase) && + (int)(state >>> PHASE_SHIFT) == phase) // avoid stale enq + queued = head.compareAndSet(q, node); + } + else { + try { + ForkJoinPool.managedBlock(node); + } catch (InterruptedException ie) { + node.wasInterrupted = true; + } + } + } + + if (node != null) { + if (node.thread != null) + node.thread = null; // avoid need for unpark() + if (node.wasInterrupted && !node.interruptible) + Thread.currentThread().interrupt(); + if (p == phase && (p = (int)(state >>> PHASE_SHIFT)) == phase) + return abortWait(phase); // possibly clean up on abort + } + releaseWaiters(phase); + return p; + } + + /** + * Wait nodes for Treiber stack representing wait queue + */ + static final class QNode implements ForkJoinPool.ManagedBlocker { + final Phaser phaser; + final int phase; + final boolean interruptible; + final boolean timed; + boolean wasInterrupted; + long nanos; + long lastTime; + volatile Thread thread; // nulled to cancel wait + QNode next; + + QNode(Phaser phaser, int phase, boolean interruptible, + boolean timed, long nanos) { + this.phaser = phaser; + this.phase = phase; + this.interruptible = interruptible; + this.nanos = nanos; + this.timed = timed; + this.lastTime = timed ? System.nanoTime() : 0L; + thread = Thread.currentThread(); + } + + public boolean isReleasable() { + if (thread == null) + return true; + if (phaser.getPhase() != phase) { + thread = null; + return true; + } + if (Thread.interrupted()) + wasInterrupted = true; + if (wasInterrupted && interruptible) { + thread = null; + return true; + } + if (timed) { + if (nanos > 0L) { + long now = System.nanoTime(); + nanos -= now - lastTime; + lastTime = now; + } + if (nanos <= 0L) { + thread = null; + return true; + } + } + return false; + } + + public boolean block() { + if (isReleasable()) + return true; + else if (!timed) + LockSupport.park(this); + else if (nanos > 0) + LockSupport.parkNanos(this, nanos); + return isReleasable(); + } + } + + // Unsafe mechanics + + private static final sun.misc.Unsafe UNSAFE; + private static final long stateOffset; + static { + try { + UNSAFE = sun.misc.Unsafe.getUnsafe(); + Class k = Phaser.class; + stateOffset = UNSAFE.objectFieldOffset + (k.getDeclaredField("state")); + } catch (Exception e) { + throw new Error(e); + } + } +} diff -r e1953d8b8338 -r c8af252ea9eb rt/emul/compact/src/main/java/java/util/concurrent/PriorityBlockingQueue.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/PriorityBlockingQueue.java Sat Mar 19 10:48:29 2016 +0100 @@ -0,0 +1,978 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +package java.util.concurrent; + +import java.util.concurrent.locks.*; +import java.util.*; + +/** + * An unbounded {@linkplain BlockingQueue blocking queue} that uses + * the same ordering rules as class {@link PriorityQueue} and supplies + * blocking retrieval operations. While this queue is logically + * unbounded, attempted additions may fail due to resource exhaustion + * (causing {@code OutOfMemoryError}). This class does not permit + * {@code null} elements. A priority queue relying on {@linkplain + * Comparable natural ordering} also does not permit insertion of + * non-comparable objects (doing so results in + * {@code ClassCastException}). + * + *

This class and its iterator implement all of the + * optional methods of the {@link Collection} and {@link + * Iterator} interfaces. The Iterator provided in method {@link + * #iterator()} is not guaranteed to traverse the elements of + * the PriorityBlockingQueue in any particular order. If you need + * ordered traversal, consider using + * {@code Arrays.sort(pq.toArray())}. Also, method {@code drainTo} + * can be used to remove some or all elements in priority + * order and place them in another collection. + * + *

Operations on this class make no guarantees about the ordering + * of elements with equal priority. If you need to enforce an + * ordering, you can define custom classes or comparators that use a + * secondary key to break ties in primary priority values. For + * example, here is a class that applies first-in-first-out + * tie-breaking to comparable elements. To use it, you would insert a + * {@code new FIFOEntry(anEntry)} instead of a plain entry object. + * + *

 {@code
+ * class FIFOEntry>
+ *     implements Comparable> {
+ *   static final AtomicLong seq = new AtomicLong(0);
+ *   final long seqNum;
+ *   final E entry;
+ *   public FIFOEntry(E entry) {
+ *     seqNum = seq.getAndIncrement();
+ *     this.entry = entry;
+ *   }
+ *   public E getEntry() { return entry; }
+ *   public int compareTo(FIFOEntry other) {
+ *     int res = entry.compareTo(other.entry);
+ *     if (res == 0 && other.entry != this.entry)
+ *       res = (seqNum < other.seqNum ? -1 : 1);
+ *     return res;
+ *   }
+ * }}
+ * + *

This class is a member of the + * + * Java Collections Framework. + * + * @since 1.5 + * @author Doug Lea + * @param the type of elements held in this collection + */ +public class PriorityBlockingQueue extends AbstractQueue + implements BlockingQueue, java.io.Serializable { + private static final long serialVersionUID = 5595510919245408276L; + + /* + * The implementation uses an array-based binary heap, with public + * operations protected with a single lock. However, allocation + * during resizing uses a simple spinlock (used only while not + * holding main lock) in order to allow takes to operate + * concurrently with allocation. This avoids repeated + * postponement of waiting consumers and consequent element + * build-up. The need to back away from lock during allocation + * makes it impossible to simply wrap delegated + * java.util.PriorityQueue operations within a lock, as was done + * in a previous version of this class. To maintain + * interoperability, a plain PriorityQueue is still used during + * serialization, which maintains compatibility at the espense of + * transiently doubling overhead. + */ + + /** + * Default array capacity. + */ + private static final int DEFAULT_INITIAL_CAPACITY = 11; + + /** + * The maximum size of array to allocate. + * Some VMs reserve some header words in an array. + * Attempts to allocate larger arrays may result in + * OutOfMemoryError: Requested array size exceeds VM limit + */ + private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; + + /** + * Priority queue represented as a balanced binary heap: the two + * children of queue[n] are queue[2*n+1] and queue[2*(n+1)]. The + * priority queue is ordered by comparator, or by the elements' + * natural ordering, if comparator is null: For each node n in the + * heap and each descendant d of n, n <= d. The element with the + * lowest value is in queue[0], assuming the queue is nonempty. + */ + private transient Object[] queue; + + /** + * The number of elements in the priority queue. + */ + private transient int size; + + /** + * The comparator, or null if priority queue uses elements' + * natural ordering. + */ + private transient Comparator comparator; + + /** + * Lock used for all public operations + */ + private final ReentrantLock lock; + + /** + * Condition for blocking when empty + */ + private final Condition notEmpty; + + /** + * Spinlock for allocation, acquired via CAS. + */ + private transient volatile int allocationSpinLock; + + /** + * A plain PriorityQueue used only for serialization, + * to maintain compatibility with previous versions + * of this class. Non-null only during serialization/deserialization. + */ + private PriorityQueue q; + + /** + * Creates a {@code PriorityBlockingQueue} with the default + * initial capacity (11) that orders its elements according to + * their {@linkplain Comparable natural ordering}. + */ + public PriorityBlockingQueue() { + this(DEFAULT_INITIAL_CAPACITY, null); + } + + /** + * Creates a {@code PriorityBlockingQueue} with the specified + * initial capacity that orders its elements according to their + * {@linkplain Comparable natural ordering}. + * + * @param initialCapacity the initial capacity for this priority queue + * @throws IllegalArgumentException if {@code initialCapacity} is less + * than 1 + */ + public PriorityBlockingQueue(int initialCapacity) { + this(initialCapacity, null); + } + + /** + * Creates a {@code PriorityBlockingQueue} with the specified initial + * capacity that orders its elements according to the specified + * comparator. + * + * @param initialCapacity the initial capacity for this priority queue + * @param comparator the comparator that will be used to order this + * priority queue. If {@code null}, the {@linkplain Comparable + * natural ordering} of the elements will be used. + * @throws IllegalArgumentException if {@code initialCapacity} is less + * than 1 + */ + public PriorityBlockingQueue(int initialCapacity, + Comparator comparator) { + if (initialCapacity < 1) + throw new IllegalArgumentException(); + this.lock = new ReentrantLock(); + this.notEmpty = lock.newCondition(); + this.comparator = comparator; + this.queue = new Object[initialCapacity]; + } + + /** + * Creates a {@code PriorityBlockingQueue} containing the elements + * in the specified collection. If the specified collection is a + * {@link SortedSet} or a {@link PriorityQueue}, this + * priority queue will be ordered according to the same ordering. + * Otherwise, this priority queue will be ordered according to the + * {@linkplain Comparable natural ordering} of its elements. + * + * @param c the collection whose elements are to be placed + * into this priority queue + * @throws ClassCastException if elements of the specified collection + * cannot be compared to one another according to the priority + * queue's ordering + * @throws NullPointerException if the specified collection or any + * of its elements are null + */ + public PriorityBlockingQueue(Collection c) { + this.lock = new ReentrantLock(); + this.notEmpty = lock.newCondition(); + boolean heapify = true; // true if not known to be in heap order + boolean screen = true; // true if must screen for nulls + if (c instanceof SortedSet) { + SortedSet ss = (SortedSet) c; + this.comparator = (Comparator) ss.comparator(); + heapify = false; + } + else if (c instanceof PriorityBlockingQueue) { + PriorityBlockingQueue pq = + (PriorityBlockingQueue) c; + this.comparator = (Comparator) pq.comparator(); + screen = false; + if (pq.getClass() == PriorityBlockingQueue.class) // exact match + heapify = false; + } + Object[] a = c.toArray(); + int n = a.length; + // If c.toArray incorrectly doesn't return Object[], copy it. + if (a.getClass() != Object[].class) + a = Arrays.copyOf(a, n, Object[].class); + if (screen && (n == 1 || this.comparator != null)) { + for (int i = 0; i < n; ++i) + if (a[i] == null) + throw new NullPointerException(); + } + this.queue = a; + this.size = n; + if (heapify) + heapify(); + } + + /** + * Tries to grow array to accommodate at least one more element + * (but normally expand by about 50%), giving up (allowing retry) + * on contention (which we expect to be rare). Call only while + * holding lock. + * + * @param array the heap array + * @param oldCap the length of the array + */ + private void tryGrow(Object[] array, int oldCap) { + lock.unlock(); // must release and then re-acquire main lock + Object[] newArray = null; + if (allocationSpinLock == 0 && + UNSAFE.compareAndSwapInt(this, allocationSpinLockOffset, + 0, 1)) { + try { + int newCap = oldCap + ((oldCap < 64) ? + (oldCap + 2) : // grow faster if small + (oldCap >> 1)); + if (newCap - MAX_ARRAY_SIZE > 0) { // possible overflow + int minCap = oldCap + 1; + if (minCap < 0 || minCap > MAX_ARRAY_SIZE) + throw new OutOfMemoryError(); + newCap = MAX_ARRAY_SIZE; + } + if (newCap > oldCap && queue == array) + newArray = new Object[newCap]; + } finally { + allocationSpinLock = 0; + } + } + if (newArray == null) // back off if another thread is allocating + Thread.yield(); + lock.lock(); + if (newArray != null && queue == array) { + queue = newArray; + System.arraycopy(array, 0, newArray, 0, oldCap); + } + } + + /** + * Mechanics for poll(). Call only while holding lock. + */ + private E extract() { + E result; + int n = size - 1; + if (n < 0) + result = null; + else { + Object[] array = queue; + result = (E) array[0]; + E x = (E) array[n]; + array[n] = null; + Comparator cmp = comparator; + if (cmp == null) + siftDownComparable(0, x, array, n); + else + siftDownUsingComparator(0, x, array, n, cmp); + size = n; + } + return result; + } + + /** + * Inserts item x at position k, maintaining heap invariant by + * promoting x up the tree until it is greater than or equal to + * its parent, or is the root. + * + * To simplify and speed up coercions and comparisons. the + * Comparable and Comparator versions are separated into different + * methods that are otherwise identical. (Similarly for siftDown.) + * These methods are static, with heap state as arguments, to + * simplify use in light of possible comparator exceptions. + * + * @param k the position to fill + * @param x the item to insert + * @param array the heap array + * @param n heap size + */ + private static void siftUpComparable(int k, T x, Object[] array) { + Comparable key = (Comparable) x; + while (k > 0) { + int parent = (k - 1) >>> 1; + Object e = array[parent]; + if (key.compareTo((T) e) >= 0) + break; + array[k] = e; + k = parent; + } + array[k] = key; + } + + private static void siftUpUsingComparator(int k, T x, Object[] array, + Comparator cmp) { + while (k > 0) { + int parent = (k - 1) >>> 1; + Object e = array[parent]; + if (cmp.compare(x, (T) e) >= 0) + break; + array[k] = e; + k = parent; + } + array[k] = x; + } + + /** + * Inserts item x at position k, maintaining heap invariant by + * demoting x down the tree repeatedly until it is less than or + * equal to its children or is a leaf. + * + * @param k the position to fill + * @param x the item to insert + * @param array the heap array + * @param n heap size + */ + private static void siftDownComparable(int k, T x, Object[] array, + int n) { + Comparable key = (Comparable)x; + int half = n >>> 1; // loop while a non-leaf + while (k < half) { + int child = (k << 1) + 1; // assume left child is least + Object c = array[child]; + int right = child + 1; + if (right < n && + ((Comparable) c).compareTo((T) array[right]) > 0) + c = array[child = right]; + if (key.compareTo((T) c) <= 0) + break; + array[k] = c; + k = child; + } + array[k] = key; + } + + private static void siftDownUsingComparator(int k, T x, Object[] array, + int n, + Comparator cmp) { + int half = n >>> 1; + while (k < half) { + int child = (k << 1) + 1; + Object c = array[child]; + int right = child + 1; + if (right < n && cmp.compare((T) c, (T) array[right]) > 0) + c = array[child = right]; + if (cmp.compare(x, (T) c) <= 0) + break; + array[k] = c; + k = child; + } + array[k] = x; + } + + /** + * Establishes the heap invariant (described above) in the entire tree, + * assuming nothing about the order of the elements prior to the call. + */ + private void heapify() { + Object[] array = queue; + int n = size; + int half = (n >>> 1) - 1; + Comparator cmp = comparator; + if (cmp == null) { + for (int i = half; i >= 0; i--) + siftDownComparable(i, (E) array[i], array, n); + } + else { + for (int i = half; i >= 0; i--) + siftDownUsingComparator(i, (E) array[i], array, n, cmp); + } + } + + /** + * Inserts the specified element into this priority queue. + * + * @param e the element to add + * @return {@code true} (as specified by {@link Collection#add}) + * @throws ClassCastException if the specified element cannot be compared + * with elements currently in the priority queue according to the + * priority queue's ordering + * @throws NullPointerException if the specified element is null + */ + public boolean add(E e) { + return offer(e); + } + + /** + * Inserts the specified element into this priority queue. + * As the queue is unbounded, this method will never return {@code false}. + * + * @param e the element to add + * @return {@code true} (as specified by {@link Queue#offer}) + * @throws ClassCastException if the specified element cannot be compared + * with elements currently in the priority queue according to the + * priority queue's ordering + * @throws NullPointerException if the specified element is null + */ + public boolean offer(E e) { + if (e == null) + throw new NullPointerException(); + final ReentrantLock lock = this.lock; + lock.lock(); + int n, cap; + Object[] array; + while ((n = size) >= (cap = (array = queue).length)) + tryGrow(array, cap); + try { + Comparator cmp = comparator; + if (cmp == null) + siftUpComparable(n, e, array); + else + siftUpUsingComparator(n, e, array, cmp); + size = n + 1; + notEmpty.signal(); + } finally { + lock.unlock(); + } + return true; + } + + /** + * Inserts the specified element into this priority queue. + * As the queue is unbounded, this method will never block. + * + * @param e the element to add + * @throws ClassCastException if the specified element cannot be compared + * with elements currently in the priority queue according to the + * priority queue's ordering + * @throws NullPointerException if the specified element is null + */ + public void put(E e) { + offer(e); // never need to block + } + + /** + * Inserts the specified element into this priority queue. + * As the queue is unbounded, this method will never block or + * return {@code false}. + * + * @param e the element to add + * @param timeout This parameter is ignored as the method never blocks + * @param unit This parameter is ignored as the method never blocks + * @return {@code true} (as specified by + * {@link BlockingQueue#offer(Object,long,TimeUnit) BlockingQueue.offer}) + * @throws ClassCastException if the specified element cannot be compared + * with elements currently in the priority queue according to the + * priority queue's ordering + * @throws NullPointerException if the specified element is null + */ + public boolean offer(E e, long timeout, TimeUnit unit) { + return offer(e); // never need to block + } + + public E poll() { + final ReentrantLock lock = this.lock; + lock.lock(); + E result; + try { + result = extract(); + } finally { + lock.unlock(); + } + return result; + } + + public E take() throws InterruptedException { + final ReentrantLock lock = this.lock; + lock.lockInterruptibly(); + E result; + try { + while ( (result = extract()) == null) + notEmpty.await(); + } finally { + lock.unlock(); + } + return result; + } + + public E poll(long timeout, TimeUnit unit) throws InterruptedException { + long nanos = unit.toNanos(timeout); + final ReentrantLock lock = this.lock; + lock.lockInterruptibly(); + E result; + try { + while ( (result = extract()) == null && nanos > 0) + nanos = notEmpty.awaitNanos(nanos); + } finally { + lock.unlock(); + } + return result; + } + + public E peek() { + final ReentrantLock lock = this.lock; + lock.lock(); + E result; + try { + result = size > 0 ? (E) queue[0] : null; + } finally { + lock.unlock(); + } + return result; + } + + /** + * Returns the comparator used to order the elements in this queue, + * or {@code null} if this queue uses the {@linkplain Comparable + * natural ordering} of its elements. + * + * @return the comparator used to order the elements in this queue, + * or {@code null} if this queue uses the natural + * ordering of its elements + */ + public Comparator comparator() { + return comparator; + } + + public int size() { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + return size; + } finally { + lock.unlock(); + } + } + + /** + * Always returns {@code Integer.MAX_VALUE} because + * a {@code PriorityBlockingQueue} is not capacity constrained. + * @return {@code Integer.MAX_VALUE} always + */ + public int remainingCapacity() { + return Integer.MAX_VALUE; + } + + private int indexOf(Object o) { + if (o != null) { + Object[] array = queue; + int n = size; + for (int i = 0; i < n; i++) + if (o.equals(array[i])) + return i; + } + return -1; + } + + /** + * Removes the ith element from queue. + */ + private void removeAt(int i) { + Object[] array = queue; + int n = size - 1; + if (n == i) // removed last element + array[i] = null; + else { + E moved = (E) array[n]; + array[n] = null; + Comparator cmp = comparator; + if (cmp == null) + siftDownComparable(i, moved, array, n); + else + siftDownUsingComparator(i, moved, array, n, cmp); + if (array[i] == moved) { + if (cmp == null) + siftUpComparable(i, moved, array); + else + siftUpUsingComparator(i, moved, array, cmp); + } + } + size = n; + } + + /** + * Removes a single instance of the specified element from this queue, + * if it is present. More formally, removes an element {@code e} such + * that {@code o.equals(e)}, if this queue contains one or more such + * elements. Returns {@code true} if and only if this queue contained + * the specified element (or equivalently, if this queue changed as a + * result of the call). + * + * @param o element to be removed from this queue, if present + * @return {@code true} if this queue changed as a result of the call + */ + public boolean remove(Object o) { + boolean removed = false; + final ReentrantLock lock = this.lock; + lock.lock(); + try { + int i = indexOf(o); + if (i != -1) { + removeAt(i); + removed = true; + } + } finally { + lock.unlock(); + } + return removed; + } + + + /** + * Identity-based version for use in Itr.remove + */ + private void removeEQ(Object o) { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + Object[] array = queue; + int n = size; + for (int i = 0; i < n; i++) { + if (o == array[i]) { + removeAt(i); + break; + } + } + } finally { + lock.unlock(); + } + } + + /** + * Returns {@code true} if this queue contains the specified element. + * More formally, returns {@code true} if and only if this queue contains + * at least one element {@code e} such that {@code o.equals(e)}. + * + * @param o object to be checked for containment in this queue + * @return {@code true} if this queue contains the specified element + */ + public boolean contains(Object o) { + int index; + final ReentrantLock lock = this.lock; + lock.lock(); + try { + index = indexOf(o); + } finally { + lock.unlock(); + } + return index != -1; + } + + /** + * Returns an array containing all of the elements in this queue. + * The returned array elements are in no particular order. + * + *

The returned array will be "safe" in that no references to it are + * maintained by this queue. (In other words, this method must allocate + * a new array). The caller is thus free to modify the returned array. + * + *

This method acts as bridge between array-based and collection-based + * APIs. + * + * @return an array containing all of the elements in this queue + */ + public Object[] toArray() { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + return Arrays.copyOf(queue, size); + } finally { + lock.unlock(); + } + } + + + public String toString() { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + int n = size; + if (n == 0) + return "[]"; + StringBuilder sb = new StringBuilder(); + sb.append('['); + for (int i = 0; i < n; ++i) { + E e = (E)queue[i]; + sb.append(e == this ? "(this Collection)" : e); + if (i != n - 1) + sb.append(',').append(' '); + } + return sb.append(']').toString(); + } finally { + lock.unlock(); + } + } + + /** + * @throws UnsupportedOperationException {@inheritDoc} + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + * @throws IllegalArgumentException {@inheritDoc} + */ + public int drainTo(Collection c) { + if (c == null) + throw new NullPointerException(); + if (c == this) + throw new IllegalArgumentException(); + final ReentrantLock lock = this.lock; + lock.lock(); + try { + int n = 0; + E e; + while ( (e = extract()) != null) { + c.add(e); + ++n; + } + return n; + } finally { + lock.unlock(); + } + } + + /** + * @throws UnsupportedOperationException {@inheritDoc} + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + * @throws IllegalArgumentException {@inheritDoc} + */ + public int drainTo(Collection c, int maxElements) { + if (c == null) + throw new NullPointerException(); + if (c == this) + throw new IllegalArgumentException(); + if (maxElements <= 0) + return 0; + final ReentrantLock lock = this.lock; + lock.lock(); + try { + int n = 0; + E e; + while (n < maxElements && (e = extract()) != null) { + c.add(e); + ++n; + } + return n; + } finally { + lock.unlock(); + } + } + + /** + * Atomically removes all of the elements from this queue. + * The queue will be empty after this call returns. + */ + public void clear() { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + Object[] array = queue; + int n = size; + size = 0; + for (int i = 0; i < n; i++) + array[i] = null; + } finally { + lock.unlock(); + } + } + + /** + * Returns an array containing all of the elements in this queue; the + * runtime type of the returned array is that of the specified array. + * The returned array elements are in no particular order. + * If the queue fits in the specified array, it is returned therein. + * Otherwise, a new array is allocated with the runtime type of the + * specified array and the size of this queue. + * + *

If this queue fits in the specified array with room to spare + * (i.e., the array has more elements than this queue), the element in + * the array immediately following the end of the queue is set to + * {@code null}. + * + *

Like the {@link #toArray()} method, this method acts as bridge between + * array-based and collection-based APIs. Further, this method allows + * precise control over the runtime type of the output array, and may, + * under certain circumstances, be used to save allocation costs. + * + *

Suppose {@code x} is a queue known to contain only strings. + * The following code can be used to dump the queue into a newly + * allocated array of {@code String}: + * + *

+     *     String[] y = x.toArray(new String[0]);
+ * + * Note that {@code toArray(new Object[0])} is identical in function to + * {@code toArray()}. + * + * @param a the array into which the elements of the queue are to + * be stored, if it is big enough; otherwise, a new array of the + * same runtime type is allocated for this purpose + * @return an array containing all of the elements in this queue + * @throws ArrayStoreException if the runtime type of the specified array + * is not a supertype of the runtime type of every element in + * this queue + * @throws NullPointerException if the specified array is null + */ + public T[] toArray(T[] a) { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + int n = size; + if (a.length < n) + // Make a new array of a's runtime type, but my contents: + return (T[]) Arrays.copyOf(queue, size, a.getClass()); + System.arraycopy(queue, 0, a, 0, n); + if (a.length > n) + a[n] = null; + return a; + } finally { + lock.unlock(); + } + } + + /** + * Returns an iterator over the elements in this queue. The + * iterator does not return the elements in any particular order. + * + *

The returned iterator is a "weakly consistent" iterator that + * will never throw {@link java.util.ConcurrentModificationException + * ConcurrentModificationException}, and guarantees to traverse + * elements as they existed upon construction of the iterator, and + * may (but is not guaranteed to) reflect any modifications + * subsequent to construction. + * + * @return an iterator over the elements in this queue + */ + public Iterator iterator() { + return new Itr(toArray()); + } + + /** + * Snapshot iterator that works off copy of underlying q array. + */ + final class Itr implements Iterator { + final Object[] array; // Array of all elements + int cursor; // index of next element to return; + int lastRet; // index of last element, or -1 if no such + + Itr(Object[] array) { + lastRet = -1; + this.array = array; + } + + public boolean hasNext() { + return cursor < array.length; + } + + public E next() { + if (cursor >= array.length) + throw new NoSuchElementException(); + lastRet = cursor; + return (E)array[cursor++]; + } + + public void remove() { + if (lastRet < 0) + throw new IllegalStateException(); + removeEQ(array[lastRet]); + lastRet = -1; + } + } + + /** + * Saves the state to a stream (that is, serializes it). For + * compatibility with previous version of this class, + * elements are first copied to a java.util.PriorityQueue, + * which is then serialized. + */ + private void writeObject(java.io.ObjectOutputStream s) + throws java.io.IOException { + lock.lock(); + try { + int n = size; // avoid zero capacity argument + q = new PriorityQueue(n == 0 ? 1 : n, comparator); + q.addAll(this); + s.defaultWriteObject(); + } finally { + q = null; + lock.unlock(); + } + } + + /** + * Reconstitutes the {@code PriorityBlockingQueue} instance from a stream + * (that is, deserializes it). + * + * @param s the stream + */ + private void readObject(java.io.ObjectInputStream s) + throws java.io.IOException, ClassNotFoundException { + try { + s.defaultReadObject(); + this.queue = new Object[q.size()]; + comparator = q.comparator(); + addAll(q); + } finally { + q = null; + } + } + + // Unsafe mechanics + private static final sun.misc.Unsafe UNSAFE; + private static final long allocationSpinLockOffset; + static { + try { + UNSAFE = sun.misc.Unsafe.getUnsafe(); + Class k = PriorityBlockingQueue.class; + allocationSpinLockOffset = UNSAFE.objectFieldOffset + (k.getDeclaredField("allocationSpinLock")); + } catch (Exception e) { + throw new Error(e); + } + } +} diff -r e1953d8b8338 -r c8af252ea9eb rt/emul/compact/src/main/java/java/util/concurrent/RecursiveAction.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/RecursiveAction.java Sat Mar 19 10:48:29 2016 +0100 @@ -0,0 +1,181 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +package java.util.concurrent; + +/** + * A recursive resultless {@link ForkJoinTask}. This class + * establishes conventions to parameterize resultless actions as + * {@code Void} {@code ForkJoinTask}s. Because {@code null} is the + * only valid value of type {@code Void}, methods such as join always + * return {@code null} upon completion. + * + *

Sample Usages. Here is a sketch of a ForkJoin sort that + * sorts a given {@code long[]} array: + * + *

 {@code
+ * class SortTask extends RecursiveAction {
+ *   final long[] array; final int lo; final int hi;
+ *   SortTask(long[] array, int lo, int hi) {
+ *     this.array = array; this.lo = lo; this.hi = hi;
+ *   }
+ *   protected void compute() {
+ *     if (hi - lo < THRESHOLD)
+ *       sequentiallySort(array, lo, hi);
+ *     else {
+ *       int mid = (lo + hi) >>> 1;
+ *       invokeAll(new SortTask(array, lo, mid),
+ *                 new SortTask(array, mid, hi));
+ *       merge(array, lo, hi);
+ *     }
+ *   }
+ * }}
+ * + * You could then sort {@code anArray} by creating {@code new + * SortTask(anArray, 0, anArray.length-1) } and invoking it in a + * ForkJoinPool. As a more concrete simple example, the following + * task increments each element of an array: + *
 {@code
+ * class IncrementTask extends RecursiveAction {
+ *   final long[] array; final int lo; final int hi;
+ *   IncrementTask(long[] array, int lo, int hi) {
+ *     this.array = array; this.lo = lo; this.hi = hi;
+ *   }
+ *   protected void compute() {
+ *     if (hi - lo < THRESHOLD) {
+ *       for (int i = lo; i < hi; ++i)
+ *         array[i]++;
+ *     }
+ *     else {
+ *       int mid = (lo + hi) >>> 1;
+ *       invokeAll(new IncrementTask(array, lo, mid),
+ *                 new IncrementTask(array, mid, hi));
+ *     }
+ *   }
+ * }}
+ * + *

The following example illustrates some refinements and idioms + * that may lead to better performance: RecursiveActions need not be + * fully recursive, so long as they maintain the basic + * divide-and-conquer approach. Here is a class that sums the squares + * of each element of a double array, by subdividing out only the + * right-hand-sides of repeated divisions by two, and keeping track of + * them with a chain of {@code next} references. It uses a dynamic + * threshold based on method {@code getSurplusQueuedTaskCount}, but + * counterbalances potential excess partitioning by directly + * performing leaf actions on unstolen tasks rather than further + * subdividing. + * + *

 {@code
+ * double sumOfSquares(ForkJoinPool pool, double[] array) {
+ *   int n = array.length;
+ *   Applyer a = new Applyer(array, 0, n, null);
+ *   pool.invoke(a);
+ *   return a.result;
+ * }
+ *
+ * class Applyer extends RecursiveAction {
+ *   final double[] array;
+ *   final int lo, hi;
+ *   double result;
+ *   Applyer next; // keeps track of right-hand-side tasks
+ *   Applyer(double[] array, int lo, int hi, Applyer next) {
+ *     this.array = array; this.lo = lo; this.hi = hi;
+ *     this.next = next;
+ *   }
+ *
+ *   double atLeaf(int l, int h) {
+ *     double sum = 0;
+ *     for (int i = l; i < h; ++i) // perform leftmost base step
+ *       sum += array[i] * array[i];
+ *     return sum;
+ *   }
+ *
+ *   protected void compute() {
+ *     int l = lo;
+ *     int h = hi;
+ *     Applyer right = null;
+ *     while (h - l > 1 && getSurplusQueuedTaskCount() <= 3) {
+ *        int mid = (l + h) >>> 1;
+ *        right = new Applyer(array, mid, h, right);
+ *        right.fork();
+ *        h = mid;
+ *     }
+ *     double sum = atLeaf(l, h);
+ *     while (right != null) {
+ *        if (right.tryUnfork()) // directly calculate if not stolen
+ *          sum += right.atLeaf(right.lo, right.hi);
+ *       else {
+ *          right.join();
+ *          sum += right.result;
+ *        }
+ *        right = right.next;
+ *      }
+ *     result = sum;
+ *   }
+ * }}
+ * + * @since 1.7 + * @author Doug Lea + */ +public abstract class RecursiveAction extends ForkJoinTask { + private static final long serialVersionUID = 5232453952276485070L; + + /** + * The main computation performed by this task. + */ + protected abstract void compute(); + + /** + * Always returns {@code null}. + * + * @return {@code null} always + */ + public final Void getRawResult() { return null; } + + /** + * Requires null completion value. + */ + protected final void setRawResult(Void mustBeNull) { } + + /** + * Implements execution conventions for RecursiveActions. + */ + protected final boolean exec() { + compute(); + return true; + } + +} diff -r e1953d8b8338 -r c8af252ea9eb rt/emul/compact/src/main/java/java/util/concurrent/RecursiveTask.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/RecursiveTask.java Sat Mar 19 10:48:29 2016 +0100 @@ -0,0 +1,97 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +package java.util.concurrent; + +/** + * A recursive result-bearing {@link ForkJoinTask}. + * + *

For a classic example, here is a task computing Fibonacci numbers: + * + *

 {@code
+ * class Fibonacci extends RecursiveTask {
+ *   final int n;
+ *   Fibonacci(int n) { this.n = n; }
+ *   Integer compute() {
+ *     if (n <= 1)
+ *        return n;
+ *     Fibonacci f1 = new Fibonacci(n - 1);
+ *     f1.fork();
+ *     Fibonacci f2 = new Fibonacci(n - 2);
+ *     return f2.compute() + f1.join();
+ *   }
+ * }}
+ * + * However, besides being a dumb way to compute Fibonacci functions + * (there is a simple fast linear algorithm that you'd use in + * practice), this is likely to perform poorly because the smallest + * subtasks are too small to be worthwhile splitting up. Instead, as + * is the case for nearly all fork/join applications, you'd pick some + * minimum granularity size (for example 10 here) for which you always + * sequentially solve rather than subdividing. + * + * @since 1.7 + * @author Doug Lea + */ +public abstract class RecursiveTask extends ForkJoinTask { + private static final long serialVersionUID = 5232453952276485270L; + + /** + * The result of the computation. + */ + V result; + + /** + * The main computation performed by this task. + */ + protected abstract V compute(); + + public final V getRawResult() { + return result; + } + + protected final void setRawResult(V value) { + result = value; + } + + /** + * Implements execution conventions for RecursiveTask. + */ + protected final boolean exec() { + result = compute(); + return true; + } + +} diff -r e1953d8b8338 -r c8af252ea9eb rt/emul/compact/src/main/java/java/util/concurrent/RejectedExecutionException.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/RejectedExecutionException.java Sat Mar 19 10:48:29 2016 +0100 @@ -0,0 +1,91 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +package java.util.concurrent; + +/** + * Exception thrown by an {@link Executor} when a task cannot be + * accepted for execution. + * + * @since 1.5 + * @author Doug Lea + */ +public class RejectedExecutionException extends RuntimeException { + private static final long serialVersionUID = -375805702767069545L; + + /** + * Constructs a RejectedExecutionException with no detail message. + * The cause is not initialized, and may subsequently be + * initialized by a call to {@link #initCause(Throwable) initCause}. + */ + public RejectedExecutionException() { } + + /** + * Constructs a RejectedExecutionException with the + * specified detail message. The cause is not initialized, and may + * subsequently be initialized by a call to {@link + * #initCause(Throwable) initCause}. + * + * @param message the detail message + */ + public RejectedExecutionException(String message) { + super(message); + } + + /** + * Constructs a RejectedExecutionException with the + * specified detail message and cause. + * + * @param message the detail message + * @param cause the cause (which is saved for later retrieval by the + * {@link #getCause()} method) + */ + public RejectedExecutionException(String message, Throwable cause) { + super(message, cause); + } + + /** + * Constructs a RejectedExecutionException with the + * specified cause. The detail message is set to:
 (cause ==
+     * null ? null : cause.toString())
(which typically contains + * the class and detail message of cause). + * + * @param cause the cause (which is saved for later retrieval by the + * {@link #getCause()} method) + */ + public RejectedExecutionException(Throwable cause) { + super(cause); + } +} diff -r e1953d8b8338 -r c8af252ea9eb rt/emul/compact/src/main/java/java/util/concurrent/RejectedExecutionHandler.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/RejectedExecutionHandler.java Sat Mar 19 10:48:29 2016 +0100 @@ -0,0 +1,62 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +package java.util.concurrent; + +/** + * A handler for tasks that cannot be executed by a {@link ThreadPoolExecutor}. + * + * @since 1.5 + * @author Doug Lea + */ +public interface RejectedExecutionHandler { + + /** + * Method that may be invoked by a {@link ThreadPoolExecutor} when + * {@link ThreadPoolExecutor#execute execute} cannot accept a + * task. This may occur when no more threads or queue slots are + * available because their bounds would be exceeded, or upon + * shutdown of the Executor. + * + *

In the absence of other alternatives, the method may throw + * an unchecked {@link RejectedExecutionException}, which will be + * propagated to the caller of {@code execute}. + * + * @param r the runnable task requested to be executed + * @param executor the executor attempting to execute this task + * @throws RejectedExecutionException if there is no remedy + */ + void rejectedExecution(Runnable r, ThreadPoolExecutor executor); +} diff -r e1953d8b8338 -r c8af252ea9eb rt/emul/compact/src/main/java/java/util/concurrent/RunnableFuture.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/RunnableFuture.java Sat Mar 19 10:48:29 2016 +0100 @@ -0,0 +1,54 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +package java.util.concurrent; + +/** + * A {@link Future} that is {@link Runnable}. Successful execution of + * the run method causes completion of the Future + * and allows access to its results. + * @see FutureTask + * @see Executor + * @since 1.6 + * @author Doug Lea + * @param The result type returned by this Future's get method + */ +public interface RunnableFuture extends Runnable, Future { + /** + * Sets this Future to the result of its computation + * unless it has been cancelled. + */ + void run(); +} diff -r e1953d8b8338 -r c8af252ea9eb rt/emul/compact/src/main/java/java/util/concurrent/RunnableScheduledFuture.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/RunnableScheduledFuture.java Sat Mar 19 10:48:29 2016 +0100 @@ -0,0 +1,58 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +package java.util.concurrent; + +/** + * A {@link ScheduledFuture} that is {@link Runnable}. Successful + * execution of the run method causes completion of the + * Future and allows access to its results. + * @see FutureTask + * @see Executor + * @since 1.6 + * @author Doug Lea + * @param The result type returned by this Future's get method + */ +public interface RunnableScheduledFuture extends RunnableFuture, ScheduledFuture { + + /** + * Returns true if this is a periodic task. A periodic task may + * re-run according to some schedule. A non-periodic task can be + * run only once. + * + * @return true if this task is periodic + */ + boolean isPeriodic(); +} diff -r e1953d8b8338 -r c8af252ea9eb rt/emul/compact/src/main/java/java/util/concurrent/ScheduledExecutorService.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/ScheduledExecutorService.java Sat Mar 19 10:48:29 2016 +0100 @@ -0,0 +1,187 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +package java.util.concurrent; +import java.util.concurrent.atomic.*; +import java.util.*; + +/** + * An {@link ExecutorService} that can schedule commands to run after a given + * delay, or to execute periodically. + * + *

The schedule methods create tasks with various delays + * and return a task object that can be used to cancel or check + * execution. The scheduleAtFixedRate and + * scheduleWithFixedDelay methods create and execute tasks + * that run periodically until cancelled. + * + *

Commands submitted using the {@link Executor#execute} and + * {@link ExecutorService} submit methods are scheduled with + * a requested delay of zero. Zero and negative delays (but not + * periods) are also allowed in schedule methods, and are + * treated as requests for immediate execution. + * + *

All schedule methods accept relative delays and + * periods as arguments, not absolute times or dates. It is a simple + * matter to transform an absolute time represented as a {@link + * java.util.Date} to the required form. For example, to schedule at + * a certain future date, you can use: schedule(task, + * date.getTime() - System.currentTimeMillis(), + * TimeUnit.MILLISECONDS). Beware however that expiration of a + * relative delay need not coincide with the current Date at + * which the task is enabled due to network time synchronization + * protocols, clock drift, or other factors. + * + * The {@link Executors} class provides convenient factory methods for + * the ScheduledExecutorService implementations provided in this package. + * + *

Usage Example

+ * + * Here is a class with a method that sets up a ScheduledExecutorService + * to beep every ten seconds for an hour: + * + *
 {@code
+ * import static java.util.concurrent.TimeUnit.*;
+ * class BeeperControl {
+ *   private final ScheduledExecutorService scheduler =
+ *     Executors.newScheduledThreadPool(1);
+ *
+ *   public void beepForAnHour() {
+ *     final Runnable beeper = new Runnable() {
+ *       public void run() { System.out.println("beep"); }
+ *     };
+ *     final ScheduledFuture beeperHandle =
+ *       scheduler.scheduleAtFixedRate(beeper, 10, 10, SECONDS);
+ *     scheduler.schedule(new Runnable() {
+ *       public void run() { beeperHandle.cancel(true); }
+ *     }, 60 * 60, SECONDS);
+ *   }
+ * }}
+ * + * @since 1.5 + * @author Doug Lea + */ +public interface ScheduledExecutorService extends ExecutorService { + + /** + * Creates and executes a one-shot action that becomes enabled + * after the given delay. + * + * @param command the task to execute + * @param delay the time from now to delay execution + * @param unit the time unit of the delay parameter + * @return a ScheduledFuture representing pending completion of + * the task and whose get() method will return + * null upon completion + * @throws RejectedExecutionException if the task cannot be + * scheduled for execution + * @throws NullPointerException if command is null + */ + public ScheduledFuture schedule(Runnable command, + long delay, TimeUnit unit); + + /** + * Creates and executes a ScheduledFuture that becomes enabled after the + * given delay. + * + * @param callable the function to execute + * @param delay the time from now to delay execution + * @param unit the time unit of the delay parameter + * @return a ScheduledFuture that can be used to extract result or cancel + * @throws RejectedExecutionException if the task cannot be + * scheduled for execution + * @throws NullPointerException if callable is null + */ + public ScheduledFuture schedule(Callable callable, + long delay, TimeUnit unit); + + /** + * Creates and executes a periodic action that becomes enabled first + * after the given initial delay, and subsequently with the given + * period; that is executions will commence after + * initialDelay then initialDelay+period, then + * initialDelay + 2 * period, and so on. + * If any execution of the task + * encounters an exception, subsequent executions are suppressed. + * Otherwise, the task will only terminate via cancellation or + * termination of the executor. If any execution of this task + * takes longer than its period, then subsequent executions + * may start late, but will not concurrently execute. + * + * @param command the task to execute + * @param initialDelay the time to delay first execution + * @param period the period between successive executions + * @param unit the time unit of the initialDelay and period parameters + * @return a ScheduledFuture representing pending completion of + * the task, and whose get() method will throw an + * exception upon cancellation + * @throws RejectedExecutionException if the task cannot be + * scheduled for execution + * @throws NullPointerException if command is null + * @throws IllegalArgumentException if period less than or equal to zero + */ + public ScheduledFuture scheduleAtFixedRate(Runnable command, + long initialDelay, + long period, + TimeUnit unit); + + /** + * Creates and executes a periodic action that becomes enabled first + * after the given initial delay, and subsequently with the + * given delay between the termination of one execution and the + * commencement of the next. If any execution of the task + * encounters an exception, subsequent executions are suppressed. + * Otherwise, the task will only terminate via cancellation or + * termination of the executor. + * + * @param command the task to execute + * @param initialDelay the time to delay first execution + * @param delay the delay between the termination of one + * execution and the commencement of the next + * @param unit the time unit of the initialDelay and delay parameters + * @return a ScheduledFuture representing pending completion of + * the task, and whose get() method will throw an + * exception upon cancellation + * @throws RejectedExecutionException if the task cannot be + * scheduled for execution + * @throws NullPointerException if command is null + * @throws IllegalArgumentException if delay less than or equal to zero + */ + public ScheduledFuture scheduleWithFixedDelay(Runnable command, + long initialDelay, + long delay, + TimeUnit unit); + +} diff -r e1953d8b8338 -r c8af252ea9eb rt/emul/compact/src/main/java/java/util/concurrent/ScheduledFuture.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/ScheduledFuture.java Sat Mar 19 10:48:29 2016 +0100 @@ -0,0 +1,48 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +package java.util.concurrent; + +/** + * A delayed result-bearing action that can be cancelled. + * Usually a scheduled future is the result of scheduling + * a task with a {@link ScheduledExecutorService}. + * + * @since 1.5 + * @author Doug Lea + * @param The result type returned by this Future + */ +public interface ScheduledFuture extends Delayed, Future { +} diff -r e1953d8b8338 -r c8af252ea9eb rt/emul/compact/src/main/java/java/util/concurrent/ScheduledThreadPoolExecutor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/ScheduledThreadPoolExecutor.java Sat Mar 19 10:48:29 2016 +0100 @@ -0,0 +1,1277 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +package java.util.concurrent; +import java.util.concurrent.atomic.*; +import java.util.concurrent.locks.*; +import java.util.*; + +/** + * A {@link ThreadPoolExecutor} that can additionally schedule + * commands to run after a given delay, or to execute + * periodically. This class is preferable to {@link java.util.Timer} + * when multiple worker threads are needed, or when the additional + * flexibility or capabilities of {@link ThreadPoolExecutor} (which + * this class extends) are required. + * + *

Delayed tasks execute no sooner than they are enabled, but + * without any real-time guarantees about when, after they are + * enabled, they will commence. Tasks scheduled for exactly the same + * execution time are enabled in first-in-first-out (FIFO) order of + * submission. + * + *

When a submitted task is cancelled before it is run, execution + * is suppressed. By default, such a cancelled task is not + * automatically removed from the work queue until its delay + * elapses. While this enables further inspection and monitoring, it + * may also cause unbounded retention of cancelled tasks. To avoid + * this, set {@link #setRemoveOnCancelPolicy} to {@code true}, which + * causes tasks to be immediately removed from the work queue at + * time of cancellation. + * + *

Successive executions of a task scheduled via + * {@code scheduleAtFixedRate} or + * {@code scheduleWithFixedDelay} do not overlap. While different + * executions may be performed by different threads, the effects of + * prior executions happen-before + * those of subsequent ones. + * + *

While this class inherits from {@link ThreadPoolExecutor}, a few + * of the inherited tuning methods are not useful for it. In + * particular, because it acts as a fixed-sized pool using + * {@code corePoolSize} threads and an unbounded queue, adjustments + * to {@code maximumPoolSize} have no useful effect. Additionally, it + * is almost never a good idea to set {@code corePoolSize} to zero or + * use {@code allowCoreThreadTimeOut} because this may leave the pool + * without threads to handle tasks once they become eligible to run. + * + *

Extension notes: This class overrides the + * {@link ThreadPoolExecutor#execute execute} and + * {@link AbstractExecutorService#submit(Runnable) submit} + * methods to generate internal {@link ScheduledFuture} objects to + * control per-task delays and scheduling. To preserve + * functionality, any further overrides of these methods in + * subclasses must invoke superclass versions, which effectively + * disables additional task customization. However, this class + * provides alternative protected extension method + * {@code decorateTask} (one version each for {@code Runnable} and + * {@code Callable}) that can be used to customize the concrete task + * types used to execute commands entered via {@code execute}, + * {@code submit}, {@code schedule}, {@code scheduleAtFixedRate}, + * and {@code scheduleWithFixedDelay}. By default, a + * {@code ScheduledThreadPoolExecutor} uses a task type extending + * {@link FutureTask}. However, this may be modified or replaced using + * subclasses of the form: + * + *

 {@code
+ * public class CustomScheduledExecutor extends ScheduledThreadPoolExecutor {
+ *
+ *   static class CustomTask implements RunnableScheduledFuture { ... }
+ *
+ *   protected  RunnableScheduledFuture decorateTask(
+ *                Runnable r, RunnableScheduledFuture task) {
+ *       return new CustomTask(r, task);
+ *   }
+ *
+ *   protected  RunnableScheduledFuture decorateTask(
+ *                Callable c, RunnableScheduledFuture task) {
+ *       return new CustomTask(c, task);
+ *   }
+ *   // ... add constructors, etc.
+ * }}
+ * + * @since 1.5 + * @author Doug Lea + */ +public class ScheduledThreadPoolExecutor + extends ThreadPoolExecutor + implements ScheduledExecutorService { + + /* + * This class specializes ThreadPoolExecutor implementation by + * + * 1. Using a custom task type, ScheduledFutureTask for + * tasks, even those that don't require scheduling (i.e., + * those submitted using ExecutorService execute, not + * ScheduledExecutorService methods) which are treated as + * delayed tasks with a delay of zero. + * + * 2. Using a custom queue (DelayedWorkQueue), a variant of + * unbounded DelayQueue. The lack of capacity constraint and + * the fact that corePoolSize and maximumPoolSize are + * effectively identical simplifies some execution mechanics + * (see delayedExecute) compared to ThreadPoolExecutor. + * + * 3. Supporting optional run-after-shutdown parameters, which + * leads to overrides of shutdown methods to remove and cancel + * tasks that should NOT be run after shutdown, as well as + * different recheck logic when task (re)submission overlaps + * with a shutdown. + * + * 4. Task decoration methods to allow interception and + * instrumentation, which are needed because subclasses cannot + * otherwise override submit methods to get this effect. These + * don't have any impact on pool control logic though. + */ + + /** + * False if should cancel/suppress periodic tasks on shutdown. + */ + private volatile boolean continueExistingPeriodicTasksAfterShutdown; + + /** + * False if should cancel non-periodic tasks on shutdown. + */ + private volatile boolean executeExistingDelayedTasksAfterShutdown = true; + + /** + * True if ScheduledFutureTask.cancel should remove from queue + */ + private volatile boolean removeOnCancel = false; + + /** + * Sequence number to break scheduling ties, and in turn to + * guarantee FIFO order among tied entries. + */ + private static final AtomicLong sequencer = new AtomicLong(0); + + /** + * Returns current nanosecond time. + */ + final long now() { + return System.nanoTime(); + } + + private class ScheduledFutureTask + extends FutureTask implements RunnableScheduledFuture { + + /** Sequence number to break ties FIFO */ + private final long sequenceNumber; + + /** The time the task is enabled to execute in nanoTime units */ + private long time; + + /** + * Period in nanoseconds for repeating tasks. A positive + * value indicates fixed-rate execution. A negative value + * indicates fixed-delay execution. A value of 0 indicates a + * non-repeating task. + */ + private final long period; + + /** The actual task to be re-enqueued by reExecutePeriodic */ + RunnableScheduledFuture outerTask = this; + + /** + * Index into delay queue, to support faster cancellation. + */ + int heapIndex; + + /** + * Creates a one-shot action with given nanoTime-based trigger time. + */ + ScheduledFutureTask(Runnable r, V result, long ns) { + super(r, result); + this.time = ns; + this.period = 0; + this.sequenceNumber = sequencer.getAndIncrement(); + } + + /** + * Creates a periodic action with given nano time and period. + */ + ScheduledFutureTask(Runnable r, V result, long ns, long period) { + super(r, result); + this.time = ns; + this.period = period; + this.sequenceNumber = sequencer.getAndIncrement(); + } + + /** + * Creates a one-shot action with given nanoTime-based trigger. + */ + ScheduledFutureTask(Callable callable, long ns) { + super(callable); + this.time = ns; + this.period = 0; + this.sequenceNumber = sequencer.getAndIncrement(); + } + + public long getDelay(TimeUnit unit) { + return unit.convert(time - now(), TimeUnit.NANOSECONDS); + } + + public int compareTo(Delayed other) { + if (other == this) // compare zero ONLY if same object + return 0; + if (other instanceof ScheduledFutureTask) { + ScheduledFutureTask x = (ScheduledFutureTask)other; + long diff = time - x.time; + if (diff < 0) + return -1; + else if (diff > 0) + return 1; + else if (sequenceNumber < x.sequenceNumber) + return -1; + else + return 1; + } + long d = (getDelay(TimeUnit.NANOSECONDS) - + other.getDelay(TimeUnit.NANOSECONDS)); + return (d == 0) ? 0 : ((d < 0) ? -1 : 1); + } + + /** + * Returns true if this is a periodic (not a one-shot) action. + * + * @return true if periodic + */ + public boolean isPeriodic() { + return period != 0; + } + + /** + * Sets the next time to run for a periodic task. + */ + private void setNextRunTime() { + long p = period; + if (p > 0) + time += p; + else + time = triggerTime(-p); + } + + public boolean cancel(boolean mayInterruptIfRunning) { + boolean cancelled = super.cancel(mayInterruptIfRunning); + if (cancelled && removeOnCancel && heapIndex >= 0) + remove(this); + return cancelled; + } + + /** + * Overrides FutureTask version so as to reset/requeue if periodic. + */ + public void run() { + boolean periodic = isPeriodic(); + if (!canRunInCurrentRunState(periodic)) + cancel(false); + else if (!periodic) + ScheduledFutureTask.super.run(); + else if (ScheduledFutureTask.super.runAndReset()) { + setNextRunTime(); + reExecutePeriodic(outerTask); + } + } + } + + /** + * Returns true if can run a task given current run state + * and run-after-shutdown parameters. + * + * @param periodic true if this task periodic, false if delayed + */ + boolean canRunInCurrentRunState(boolean periodic) { + return isRunningOrShutdown(periodic ? + continueExistingPeriodicTasksAfterShutdown : + executeExistingDelayedTasksAfterShutdown); + } + + /** + * Main execution method for delayed or periodic tasks. If pool + * is shut down, rejects the task. Otherwise adds task to queue + * and starts a thread, if necessary, to run it. (We cannot + * prestart the thread to run the task because the task (probably) + * shouldn't be run yet,) If the pool is shut down while the task + * is being added, cancel and remove it if required by state and + * run-after-shutdown parameters. + * + * @param task the task + */ + private void delayedExecute(RunnableScheduledFuture task) { + if (isShutdown()) + reject(task); + else { + super.getQueue().add(task); + if (isShutdown() && + !canRunInCurrentRunState(task.isPeriodic()) && + remove(task)) + task.cancel(false); + else + prestartCoreThread(); + } + } + + /** + * Requeues a periodic task unless current run state precludes it. + * Same idea as delayedExecute except drops task rather than rejecting. + * + * @param task the task + */ + void reExecutePeriodic(RunnableScheduledFuture task) { + if (canRunInCurrentRunState(true)) { + super.getQueue().add(task); + if (!canRunInCurrentRunState(true) && remove(task)) + task.cancel(false); + else + prestartCoreThread(); + } + } + + /** + * Cancels and clears the queue of all tasks that should not be run + * due to shutdown policy. Invoked within super.shutdown. + */ + @Override void onShutdown() { + BlockingQueue q = super.getQueue(); + boolean keepDelayed = + getExecuteExistingDelayedTasksAfterShutdownPolicy(); + boolean keepPeriodic = + getContinueExistingPeriodicTasksAfterShutdownPolicy(); + if (!keepDelayed && !keepPeriodic) { + for (Object e : q.toArray()) + if (e instanceof RunnableScheduledFuture) + ((RunnableScheduledFuture) e).cancel(false); + q.clear(); + } + else { + // Traverse snapshot to avoid iterator exceptions + for (Object e : q.toArray()) { + if (e instanceof RunnableScheduledFuture) { + RunnableScheduledFuture t = + (RunnableScheduledFuture)e; + if ((t.isPeriodic() ? !keepPeriodic : !keepDelayed) || + t.isCancelled()) { // also remove if already cancelled + if (q.remove(t)) + t.cancel(false); + } + } + } + } + tryTerminate(); + } + + /** + * Modifies or replaces the task used to execute a runnable. + * This method can be used to override the concrete + * class used for managing internal tasks. + * The default implementation simply returns the given task. + * + * @param runnable the submitted Runnable + * @param task the task created to execute the runnable + * @return a task that can execute the runnable + * @since 1.6 + */ + protected RunnableScheduledFuture decorateTask( + Runnable runnable, RunnableScheduledFuture task) { + return task; + } + + /** + * Modifies or replaces the task used to execute a callable. + * This method can be used to override the concrete + * class used for managing internal tasks. + * The default implementation simply returns the given task. + * + * @param callable the submitted Callable + * @param task the task created to execute the callable + * @return a task that can execute the callable + * @since 1.6 + */ + protected RunnableScheduledFuture decorateTask( + Callable callable, RunnableScheduledFuture task) { + return task; + } + + /** + * Creates a new {@code ScheduledThreadPoolExecutor} with the + * given core pool size. + * + * @param corePoolSize the number of threads to keep in the pool, even + * if they are idle, unless {@code allowCoreThreadTimeOut} is set + * @throws IllegalArgumentException if {@code corePoolSize < 0} + */ + public ScheduledThreadPoolExecutor(int corePoolSize) { + super(corePoolSize, Integer.MAX_VALUE, 0, TimeUnit.NANOSECONDS, + new DelayedWorkQueue()); + } + + /** + * Creates a new {@code ScheduledThreadPoolExecutor} with the + * given initial parameters. + * + * @param corePoolSize the number of threads to keep in the pool, even + * if they are idle, unless {@code allowCoreThreadTimeOut} is set + * @param threadFactory the factory to use when the executor + * creates a new thread + * @throws IllegalArgumentException if {@code corePoolSize < 0} + * @throws NullPointerException if {@code threadFactory} is null + */ + public ScheduledThreadPoolExecutor(int corePoolSize, + ThreadFactory threadFactory) { + super(corePoolSize, Integer.MAX_VALUE, 0, TimeUnit.NANOSECONDS, + new DelayedWorkQueue(), threadFactory); + } + + /** + * Creates a new ScheduledThreadPoolExecutor with the given + * initial parameters. + * + * @param corePoolSize the number of threads to keep in the pool, even + * if they are idle, unless {@code allowCoreThreadTimeOut} is set + * @param handler the handler to use when execution is blocked + * because the thread bounds and queue capacities are reached + * @throws IllegalArgumentException if {@code corePoolSize < 0} + * @throws NullPointerException if {@code handler} is null + */ + public ScheduledThreadPoolExecutor(int corePoolSize, + RejectedExecutionHandler handler) { + super(corePoolSize, Integer.MAX_VALUE, 0, TimeUnit.NANOSECONDS, + new DelayedWorkQueue(), handler); + } + + /** + * Creates a new ScheduledThreadPoolExecutor with the given + * initial parameters. + * + * @param corePoolSize the number of threads to keep in the pool, even + * if they are idle, unless {@code allowCoreThreadTimeOut} is set + * @param threadFactory the factory to use when the executor + * creates a new thread + * @param handler the handler to use when execution is blocked + * because the thread bounds and queue capacities are reached + * @throws IllegalArgumentException if {@code corePoolSize < 0} + * @throws NullPointerException if {@code threadFactory} or + * {@code handler} is null + */ + public ScheduledThreadPoolExecutor(int corePoolSize, + ThreadFactory threadFactory, + RejectedExecutionHandler handler) { + super(corePoolSize, Integer.MAX_VALUE, 0, TimeUnit.NANOSECONDS, + new DelayedWorkQueue(), threadFactory, handler); + } + + /** + * Returns the trigger time of a delayed action. + */ + private long triggerTime(long delay, TimeUnit unit) { + return triggerTime(unit.toNanos((delay < 0) ? 0 : delay)); + } + + /** + * Returns the trigger time of a delayed action. + */ + long triggerTime(long delay) { + return now() + + ((delay < (Long.MAX_VALUE >> 1)) ? delay : overflowFree(delay)); + } + + /** + * Constrains the values of all delays in the queue to be within + * Long.MAX_VALUE of each other, to avoid overflow in compareTo. + * This may occur if a task is eligible to be dequeued, but has + * not yet been, while some other task is added with a delay of + * Long.MAX_VALUE. + */ + private long overflowFree(long delay) { + Delayed head = (Delayed) super.getQueue().peek(); + if (head != null) { + long headDelay = head.getDelay(TimeUnit.NANOSECONDS); + if (headDelay < 0 && (delay - headDelay < 0)) + delay = Long.MAX_VALUE + headDelay; + } + return delay; + } + + /** + * @throws RejectedExecutionException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + */ + public ScheduledFuture schedule(Runnable command, + long delay, + TimeUnit unit) { + if (command == null || unit == null) + throw new NullPointerException(); + RunnableScheduledFuture t = decorateTask(command, + new ScheduledFutureTask(command, null, + triggerTime(delay, unit))); + delayedExecute(t); + return t; + } + + /** + * @throws RejectedExecutionException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + */ + public ScheduledFuture schedule(Callable callable, + long delay, + TimeUnit unit) { + if (callable == null || unit == null) + throw new NullPointerException(); + RunnableScheduledFuture t = decorateTask(callable, + new ScheduledFutureTask(callable, + triggerTime(delay, unit))); + delayedExecute(t); + return t; + } + + /** + * @throws RejectedExecutionException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + * @throws IllegalArgumentException {@inheritDoc} + */ + public ScheduledFuture scheduleAtFixedRate(Runnable command, + long initialDelay, + long period, + TimeUnit unit) { + if (command == null || unit == null) + throw new NullPointerException(); + if (period <= 0) + throw new IllegalArgumentException(); + ScheduledFutureTask sft = + new ScheduledFutureTask(command, + null, + triggerTime(initialDelay, unit), + unit.toNanos(period)); + RunnableScheduledFuture t = decorateTask(command, sft); + sft.outerTask = t; + delayedExecute(t); + return t; + } + + /** + * @throws RejectedExecutionException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + * @throws IllegalArgumentException {@inheritDoc} + */ + public ScheduledFuture scheduleWithFixedDelay(Runnable command, + long initialDelay, + long delay, + TimeUnit unit) { + if (command == null || unit == null) + throw new NullPointerException(); + if (delay <= 0) + throw new IllegalArgumentException(); + ScheduledFutureTask sft = + new ScheduledFutureTask(command, + null, + triggerTime(initialDelay, unit), + unit.toNanos(-delay)); + RunnableScheduledFuture t = decorateTask(command, sft); + sft.outerTask = t; + delayedExecute(t); + return t; + } + + /** + * Executes {@code command} with zero required delay. + * This has effect equivalent to + * {@link #schedule(Runnable,long,TimeUnit) schedule(command, 0, anyUnit)}. + * Note that inspections of the queue and of the list returned by + * {@code shutdownNow} will access the zero-delayed + * {@link ScheduledFuture}, not the {@code command} itself. + * + *

A consequence of the use of {@code ScheduledFuture} objects is + * that {@link ThreadPoolExecutor#afterExecute afterExecute} is always + * called with a null second {@code Throwable} argument, even if the + * {@code command} terminated abruptly. Instead, the {@code Throwable} + * thrown by such a task can be obtained via {@link Future#get}. + * + * @throws RejectedExecutionException at discretion of + * {@code RejectedExecutionHandler}, if the task + * cannot be accepted for execution because the + * executor has been shut down + * @throws NullPointerException {@inheritDoc} + */ + public void execute(Runnable command) { + schedule(command, 0, TimeUnit.NANOSECONDS); + } + + // Override AbstractExecutorService methods + + /** + * @throws RejectedExecutionException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + */ + public Future submit(Runnable task) { + return schedule(task, 0, TimeUnit.NANOSECONDS); + } + + /** + * @throws RejectedExecutionException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + */ + public Future submit(Runnable task, T result) { + return schedule(Executors.callable(task, result), + 0, TimeUnit.NANOSECONDS); + } + + /** + * @throws RejectedExecutionException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + */ + public Future submit(Callable task) { + return schedule(task, 0, TimeUnit.NANOSECONDS); + } + + /** + * Sets the policy on whether to continue executing existing + * periodic tasks even when this executor has been {@code shutdown}. + * In this case, these tasks will only terminate upon + * {@code shutdownNow} or after setting the policy to + * {@code false} when already shutdown. + * This value is by default {@code false}. + * + * @param value if {@code true}, continue after shutdown, else don't. + * @see #getContinueExistingPeriodicTasksAfterShutdownPolicy + */ + public void setContinueExistingPeriodicTasksAfterShutdownPolicy(boolean value) { + continueExistingPeriodicTasksAfterShutdown = value; + if (!value && isShutdown()) + onShutdown(); + } + + /** + * Gets the policy on whether to continue executing existing + * periodic tasks even when this executor has been {@code shutdown}. + * In this case, these tasks will only terminate upon + * {@code shutdownNow} or after setting the policy to + * {@code false} when already shutdown. + * This value is by default {@code false}. + * + * @return {@code true} if will continue after shutdown + * @see #setContinueExistingPeriodicTasksAfterShutdownPolicy + */ + public boolean getContinueExistingPeriodicTasksAfterShutdownPolicy() { + return continueExistingPeriodicTasksAfterShutdown; + } + + /** + * Sets the policy on whether to execute existing delayed + * tasks even when this executor has been {@code shutdown}. + * In this case, these tasks will only terminate upon + * {@code shutdownNow}, or after setting the policy to + * {@code false} when already shutdown. + * This value is by default {@code true}. + * + * @param value if {@code true}, execute after shutdown, else don't. + * @see #getExecuteExistingDelayedTasksAfterShutdownPolicy + */ + public void setExecuteExistingDelayedTasksAfterShutdownPolicy(boolean value) { + executeExistingDelayedTasksAfterShutdown = value; + if (!value && isShutdown()) + onShutdown(); + } + + /** + * Gets the policy on whether to execute existing delayed + * tasks even when this executor has been {@code shutdown}. + * In this case, these tasks will only terminate upon + * {@code shutdownNow}, or after setting the policy to + * {@code false} when already shutdown. + * This value is by default {@code true}. + * + * @return {@code true} if will execute after shutdown + * @see #setExecuteExistingDelayedTasksAfterShutdownPolicy + */ + public boolean getExecuteExistingDelayedTasksAfterShutdownPolicy() { + return executeExistingDelayedTasksAfterShutdown; + } + + /** + * Sets the policy on whether cancelled tasks should be immediately + * removed from the work queue at time of cancellation. This value is + * by default {@code false}. + * + * @param value if {@code true}, remove on cancellation, else don't + * @see #getRemoveOnCancelPolicy + * @since 1.7 + */ + public void setRemoveOnCancelPolicy(boolean value) { + removeOnCancel = value; + } + + /** + * Gets the policy on whether cancelled tasks should be immediately + * removed from the work queue at time of cancellation. This value is + * by default {@code false}. + * + * @return {@code true} if cancelled tasks are immediately removed + * from the queue + * @see #setRemoveOnCancelPolicy + * @since 1.7 + */ + public boolean getRemoveOnCancelPolicy() { + return removeOnCancel; + } + + /** + * Initiates an orderly shutdown in which previously submitted + * tasks are executed, but no new tasks will be accepted. + * Invocation has no additional effect if already shut down. + * + *

This method does not wait for previously submitted tasks to + * complete execution. Use {@link #awaitTermination awaitTermination} + * to do that. + * + *

If the {@code ExecuteExistingDelayedTasksAfterShutdownPolicy} + * has been set {@code false}, existing delayed tasks whose delays + * have not yet elapsed are cancelled. And unless the {@code + * ContinueExistingPeriodicTasksAfterShutdownPolicy} has been set + * {@code true}, future executions of existing periodic tasks will + * be cancelled. + * + * @throws SecurityException {@inheritDoc} + */ + public void shutdown() { + super.shutdown(); + } + + /** + * Attempts to stop all actively executing tasks, halts the + * processing of waiting tasks, and returns a list of the tasks + * that were awaiting execution. + * + *

This method does not wait for actively executing tasks to + * terminate. Use {@link #awaitTermination awaitTermination} to + * do that. + * + *

There are no guarantees beyond best-effort attempts to stop + * processing actively executing tasks. This implementation + * cancels tasks via {@link Thread#interrupt}, so any task that + * fails to respond to interrupts may never terminate. + * + * @return list of tasks that never commenced execution. + * Each element of this list is a {@link ScheduledFuture}, + * including those tasks submitted using {@code execute}, + * which are for scheduling purposes used as the basis of a + * zero-delay {@code ScheduledFuture}. + * @throws SecurityException {@inheritDoc} + */ + public List shutdownNow() { + return super.shutdownNow(); + } + + /** + * Returns the task queue used by this executor. Each element of + * this queue is a {@link ScheduledFuture}, including those + * tasks submitted using {@code execute} which are for scheduling + * purposes used as the basis of a zero-delay + * {@code ScheduledFuture}. Iteration over this queue is + * not guaranteed to traverse tasks in the order in + * which they will execute. + * + * @return the task queue + */ + public BlockingQueue getQueue() { + return super.getQueue(); + } + + /** + * Specialized delay queue. To mesh with TPE declarations, this + * class must be declared as a BlockingQueue even though + * it can only hold RunnableScheduledFutures. + */ + static class DelayedWorkQueue extends AbstractQueue + implements BlockingQueue { + + /* + * A DelayedWorkQueue is based on a heap-based data structure + * like those in DelayQueue and PriorityQueue, except that + * every ScheduledFutureTask also records its index into the + * heap array. This eliminates the need to find a task upon + * cancellation, greatly speeding up removal (down from O(n) + * to O(log n)), and reducing garbage retention that would + * otherwise occur by waiting for the element to rise to top + * before clearing. But because the queue may also hold + * RunnableScheduledFutures that are not ScheduledFutureTasks, + * we are not guaranteed to have such indices available, in + * which case we fall back to linear search. (We expect that + * most tasks will not be decorated, and that the faster cases + * will be much more common.) + * + * All heap operations must record index changes -- mainly + * within siftUp and siftDown. Upon removal, a task's + * heapIndex is set to -1. Note that ScheduledFutureTasks can + * appear at most once in the queue (this need not be true for + * other kinds of tasks or work queues), so are uniquely + * identified by heapIndex. + */ + + private static final int INITIAL_CAPACITY = 16; + private RunnableScheduledFuture[] queue = + new RunnableScheduledFuture[INITIAL_CAPACITY]; + private final ReentrantLock lock = new ReentrantLock(); + private int size = 0; + + /** + * Thread designated to wait for the task at the head of the + * queue. This variant of the Leader-Follower pattern + * (http://www.cs.wustl.edu/~schmidt/POSA/POSA2/) serves to + * minimize unnecessary timed waiting. When a thread becomes + * the leader, it waits only for the next delay to elapse, but + * other threads await indefinitely. The leader thread must + * signal some other thread before returning from take() or + * poll(...), unless some other thread becomes leader in the + * interim. Whenever the head of the queue is replaced with a + * task with an earlier expiration time, the leader field is + * invalidated by being reset to null, and some waiting + * thread, but not necessarily the current leader, is + * signalled. So waiting threads must be prepared to acquire + * and lose leadership while waiting. + */ + private Thread leader = null; + + /** + * Condition signalled when a newer task becomes available at the + * head of the queue or a new thread may need to become leader. + */ + private final Condition available = lock.newCondition(); + + /** + * Set f's heapIndex if it is a ScheduledFutureTask. + */ + private void setIndex(RunnableScheduledFuture f, int idx) { + if (f instanceof ScheduledFutureTask) + ((ScheduledFutureTask)f).heapIndex = idx; + } + + /** + * Sift element added at bottom up to its heap-ordered spot. + * Call only when holding lock. + */ + private void siftUp(int k, RunnableScheduledFuture key) { + while (k > 0) { + int parent = (k - 1) >>> 1; + RunnableScheduledFuture e = queue[parent]; + if (key.compareTo(e) >= 0) + break; + queue[k] = e; + setIndex(e, k); + k = parent; + } + queue[k] = key; + setIndex(key, k); + } + + /** + * Sift element added at top down to its heap-ordered spot. + * Call only when holding lock. + */ + private void siftDown(int k, RunnableScheduledFuture key) { + int half = size >>> 1; + while (k < half) { + int child = (k << 1) + 1; + RunnableScheduledFuture c = queue[child]; + int right = child + 1; + if (right < size && c.compareTo(queue[right]) > 0) + c = queue[child = right]; + if (key.compareTo(c) <= 0) + break; + queue[k] = c; + setIndex(c, k); + k = child; + } + queue[k] = key; + setIndex(key, k); + } + + /** + * Resize the heap array. Call only when holding lock. + */ + private void grow() { + int oldCapacity = queue.length; + int newCapacity = oldCapacity + (oldCapacity >> 1); // grow 50% + if (newCapacity < 0) // overflow + newCapacity = Integer.MAX_VALUE; + queue = Arrays.copyOf(queue, newCapacity); + } + + /** + * Find index of given object, or -1 if absent + */ + private int indexOf(Object x) { + if (x != null) { + if (x instanceof ScheduledFutureTask) { + int i = ((ScheduledFutureTask) x).heapIndex; + // Sanity check; x could conceivably be a + // ScheduledFutureTask from some other pool. + if (i >= 0 && i < size && queue[i] == x) + return i; + } else { + for (int i = 0; i < size; i++) + if (x.equals(queue[i])) + return i; + } + } + return -1; + } + + public boolean contains(Object x) { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + return indexOf(x) != -1; + } finally { + lock.unlock(); + } + } + + public boolean remove(Object x) { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + int i = indexOf(x); + if (i < 0) + return false; + + setIndex(queue[i], -1); + int s = --size; + RunnableScheduledFuture replacement = queue[s]; + queue[s] = null; + if (s != i) { + siftDown(i, replacement); + if (queue[i] == replacement) + siftUp(i, replacement); + } + return true; + } finally { + lock.unlock(); + } + } + + public int size() { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + return size; + } finally { + lock.unlock(); + } + } + + public boolean isEmpty() { + return size() == 0; + } + + public int remainingCapacity() { + return Integer.MAX_VALUE; + } + + public RunnableScheduledFuture peek() { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + return queue[0]; + } finally { + lock.unlock(); + } + } + + public boolean offer(Runnable x) { + if (x == null) + throw new NullPointerException(); + RunnableScheduledFuture e = (RunnableScheduledFuture)x; + final ReentrantLock lock = this.lock; + lock.lock(); + try { + int i = size; + if (i >= queue.length) + grow(); + size = i + 1; + if (i == 0) { + queue[0] = e; + setIndex(e, 0); + } else { + siftUp(i, e); + } + if (queue[0] == e) { + leader = null; + available.signal(); + } + } finally { + lock.unlock(); + } + return true; + } + + public void put(Runnable e) { + offer(e); + } + + public boolean add(Runnable e) { + return offer(e); + } + + public boolean offer(Runnable e, long timeout, TimeUnit unit) { + return offer(e); + } + + /** + * Performs common bookkeeping for poll and take: Replaces + * first element with last and sifts it down. Call only when + * holding lock. + * @param f the task to remove and return + */ + private RunnableScheduledFuture finishPoll(RunnableScheduledFuture f) { + int s = --size; + RunnableScheduledFuture x = queue[s]; + queue[s] = null; + if (s != 0) + siftDown(0, x); + setIndex(f, -1); + return f; + } + + public RunnableScheduledFuture poll() { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + RunnableScheduledFuture first = queue[0]; + if (first == null || first.getDelay(TimeUnit.NANOSECONDS) > 0) + return null; + else + return finishPoll(first); + } finally { + lock.unlock(); + } + } + + public RunnableScheduledFuture take() throws InterruptedException { + final ReentrantLock lock = this.lock; + lock.lockInterruptibly(); + try { + for (;;) { + RunnableScheduledFuture first = queue[0]; + if (first == null) + available.await(); + else { + long delay = first.getDelay(TimeUnit.NANOSECONDS); + if (delay <= 0) + return finishPoll(first); + else if (leader != null) + available.await(); + else { + Thread thisThread = Thread.currentThread(); + leader = thisThread; + try { + available.awaitNanos(delay); + } finally { + if (leader == thisThread) + leader = null; + } + } + } + } + } finally { + if (leader == null && queue[0] != null) + available.signal(); + lock.unlock(); + } + } + + public RunnableScheduledFuture poll(long timeout, TimeUnit unit) + throws InterruptedException { + long nanos = unit.toNanos(timeout); + final ReentrantLock lock = this.lock; + lock.lockInterruptibly(); + try { + for (;;) { + RunnableScheduledFuture first = queue[0]; + if (first == null) { + if (nanos <= 0) + return null; + else + nanos = available.awaitNanos(nanos); + } else { + long delay = first.getDelay(TimeUnit.NANOSECONDS); + if (delay <= 0) + return finishPoll(first); + if (nanos <= 0) + return null; + if (nanos < delay || leader != null) + nanos = available.awaitNanos(nanos); + else { + Thread thisThread = Thread.currentThread(); + leader = thisThread; + try { + long timeLeft = available.awaitNanos(delay); + nanos -= delay - timeLeft; + } finally { + if (leader == thisThread) + leader = null; + } + } + } + } + } finally { + if (leader == null && queue[0] != null) + available.signal(); + lock.unlock(); + } + } + + public void clear() { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + for (int i = 0; i < size; i++) { + RunnableScheduledFuture t = queue[i]; + if (t != null) { + queue[i] = null; + setIndex(t, -1); + } + } + size = 0; + } finally { + lock.unlock(); + } + } + + /** + * Return and remove first element only if it is expired. + * Used only by drainTo. Call only when holding lock. + */ + private RunnableScheduledFuture pollExpired() { + RunnableScheduledFuture first = queue[0]; + if (first == null || first.getDelay(TimeUnit.NANOSECONDS) > 0) + return null; + return finishPoll(first); + } + + public int drainTo(Collection c) { + if (c == null) + throw new NullPointerException(); + if (c == this) + throw new IllegalArgumentException(); + final ReentrantLock lock = this.lock; + lock.lock(); + try { + RunnableScheduledFuture first; + int n = 0; + while ((first = pollExpired()) != null) { + c.add(first); + ++n; + } + return n; + } finally { + lock.unlock(); + } + } + + public int drainTo(Collection c, int maxElements) { + if (c == null) + throw new NullPointerException(); + if (c == this) + throw new IllegalArgumentException(); + if (maxElements <= 0) + return 0; + final ReentrantLock lock = this.lock; + lock.lock(); + try { + RunnableScheduledFuture first; + int n = 0; + while (n < maxElements && (first = pollExpired()) != null) { + c.add(first); + ++n; + } + return n; + } finally { + lock.unlock(); + } + } + + public Object[] toArray() { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + return Arrays.copyOf(queue, size, Object[].class); + } finally { + lock.unlock(); + } + } + + @SuppressWarnings("unchecked") + public T[] toArray(T[] a) { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + if (a.length < size) + return (T[]) Arrays.copyOf(queue, size, a.getClass()); + System.arraycopy(queue, 0, a, 0, size); + if (a.length > size) + a[size] = null; + return a; + } finally { + lock.unlock(); + } + } + + public Iterator iterator() { + return new Itr(Arrays.copyOf(queue, size)); + } + + /** + * Snapshot iterator that works off copy of underlying q array. + */ + private class Itr implements Iterator { + final RunnableScheduledFuture[] array; + int cursor = 0; // index of next element to return + int lastRet = -1; // index of last element, or -1 if no such + + Itr(RunnableScheduledFuture[] array) { + this.array = array; + } + + public boolean hasNext() { + return cursor < array.length; + } + + public Runnable next() { + if (cursor >= array.length) + throw new NoSuchElementException(); + lastRet = cursor; + return array[cursor++]; + } + + public void remove() { + if (lastRet < 0) + throw new IllegalStateException(); + DelayedWorkQueue.this.remove(array[lastRet]); + lastRet = -1; + } + } + } +} diff -r e1953d8b8338 -r c8af252ea9eb rt/emul/compact/src/main/java/java/util/concurrent/Semaphore.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/Semaphore.java Sat Mar 19 10:48:29 2016 +0100 @@ -0,0 +1,713 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +package java.util.concurrent; +import java.util.*; +import java.util.concurrent.locks.*; +import java.util.concurrent.atomic.*; + +/** + * A counting semaphore. Conceptually, a semaphore maintains a set of + * permits. Each {@link #acquire} blocks if necessary until a permit is + * available, and then takes it. Each {@link #release} adds a permit, + * potentially releasing a blocking acquirer. + * However, no actual permit objects are used; the {@code Semaphore} just + * keeps a count of the number available and acts accordingly. + * + *

Semaphores are often used to restrict the number of threads than can + * access some (physical or logical) resource. For example, here is + * a class that uses a semaphore to control access to a pool of items: + *

+ * class Pool {
+ *   private static final int MAX_AVAILABLE = 100;
+ *   private final Semaphore available = new Semaphore(MAX_AVAILABLE, true);
+ *
+ *   public Object getItem() throws InterruptedException {
+ *     available.acquire();
+ *     return getNextAvailableItem();
+ *   }
+ *
+ *   public void putItem(Object x) {
+ *     if (markAsUnused(x))
+ *       available.release();
+ *   }
+ *
+ *   // Not a particularly efficient data structure; just for demo
+ *
+ *   protected Object[] items = ... whatever kinds of items being managed
+ *   protected boolean[] used = new boolean[MAX_AVAILABLE];
+ *
+ *   protected synchronized Object getNextAvailableItem() {
+ *     for (int i = 0; i < MAX_AVAILABLE; ++i) {
+ *       if (!used[i]) {
+ *          used[i] = true;
+ *          return items[i];
+ *       }
+ *     }
+ *     return null; // not reached
+ *   }
+ *
+ *   protected synchronized boolean markAsUnused(Object item) {
+ *     for (int i = 0; i < MAX_AVAILABLE; ++i) {
+ *       if (item == items[i]) {
+ *          if (used[i]) {
+ *            used[i] = false;
+ *            return true;
+ *          } else
+ *            return false;
+ *       }
+ *     }
+ *     return false;
+ *   }
+ *
+ * }
+ * 
+ * + *

Before obtaining an item each thread must acquire a permit from + * the semaphore, guaranteeing that an item is available for use. When + * the thread has finished with the item it is returned back to the + * pool and a permit is returned to the semaphore, allowing another + * thread to acquire that item. Note that no synchronization lock is + * held when {@link #acquire} is called as that would prevent an item + * from being returned to the pool. The semaphore encapsulates the + * synchronization needed to restrict access to the pool, separately + * from any synchronization needed to maintain the consistency of the + * pool itself. + * + *

A semaphore initialized to one, and which is used such that it + * only has at most one permit available, can serve as a mutual + * exclusion lock. This is more commonly known as a binary + * semaphore, because it only has two states: one permit + * available, or zero permits available. When used in this way, the + * binary semaphore has the property (unlike many {@link Lock} + * implementations), that the "lock" can be released by a + * thread other than the owner (as semaphores have no notion of + * ownership). This can be useful in some specialized contexts, such + * as deadlock recovery. + * + *

The constructor for this class optionally accepts a + * fairness parameter. When set false, this class makes no + * guarantees about the order in which threads acquire permits. In + * particular, barging is permitted, that is, a thread + * invoking {@link #acquire} can be allocated a permit ahead of a + * thread that has been waiting - logically the new thread places itself at + * the head of the queue of waiting threads. When fairness is set true, the + * semaphore guarantees that threads invoking any of the {@link + * #acquire() acquire} methods are selected to obtain permits in the order in + * which their invocation of those methods was processed + * (first-in-first-out; FIFO). Note that FIFO ordering necessarily + * applies to specific internal points of execution within these + * methods. So, it is possible for one thread to invoke + * {@code acquire} before another, but reach the ordering point after + * the other, and similarly upon return from the method. + * Also note that the untimed {@link #tryAcquire() tryAcquire} methods do not + * honor the fairness setting, but will take any permits that are + * available. + * + *

Generally, semaphores used to control resource access should be + * initialized as fair, to ensure that no thread is starved out from + * accessing a resource. When using semaphores for other kinds of + * synchronization control, the throughput advantages of non-fair + * ordering often outweigh fairness considerations. + * + *

This class also provides convenience methods to {@link + * #acquire(int) acquire} and {@link #release(int) release} multiple + * permits at a time. Beware of the increased risk of indefinite + * postponement when these methods are used without fairness set true. + * + *

Memory consistency effects: Actions in a thread prior to calling + * a "release" method such as {@code release()} + * happen-before + * actions following a successful "acquire" method such as {@code acquire()} + * in another thread. + * + * @since 1.5 + * @author Doug Lea + * + */ + +public class Semaphore implements java.io.Serializable { + private static final long serialVersionUID = -3222578661600680210L; + /** All mechanics via AbstractQueuedSynchronizer subclass */ + private final Sync sync; + + /** + * Synchronization implementation for semaphore. Uses AQS state + * to represent permits. Subclassed into fair and nonfair + * versions. + */ + abstract static class Sync extends AbstractQueuedSynchronizer { + private static final long serialVersionUID = 1192457210091910933L; + + Sync(int permits) { + setState(permits); + } + + final int getPermits() { + return getState(); + } + + final int nonfairTryAcquireShared(int acquires) { + for (;;) { + int available = getState(); + int remaining = available - acquires; + if (remaining < 0 || + compareAndSetState(available, remaining)) + return remaining; + } + } + + protected final boolean tryReleaseShared(int releases) { + for (;;) { + int current = getState(); + int next = current + releases; + if (next < current) // overflow + throw new Error("Maximum permit count exceeded"); + if (compareAndSetState(current, next)) + return true; + } + } + + final void reducePermits(int reductions) { + for (;;) { + int current = getState(); + int next = current - reductions; + if (next > current) // underflow + throw new Error("Permit count underflow"); + if (compareAndSetState(current, next)) + return; + } + } + + final int drainPermits() { + for (;;) { + int current = getState(); + if (current == 0 || compareAndSetState(current, 0)) + return current; + } + } + } + + /** + * NonFair version + */ + static final class NonfairSync extends Sync { + private static final long serialVersionUID = -2694183684443567898L; + + NonfairSync(int permits) { + super(permits); + } + + protected int tryAcquireShared(int acquires) { + return nonfairTryAcquireShared(acquires); + } + } + + /** + * Fair version + */ + static final class FairSync extends Sync { + private static final long serialVersionUID = 2014338818796000944L; + + FairSync(int permits) { + super(permits); + } + + protected int tryAcquireShared(int acquires) { + for (;;) { + if (hasQueuedPredecessors()) + return -1; + int available = getState(); + int remaining = available - acquires; + if (remaining < 0 || + compareAndSetState(available, remaining)) + return remaining; + } + } + } + + /** + * Creates a {@code Semaphore} with the given number of + * permits and nonfair fairness setting. + * + * @param permits the initial number of permits available. + * This value may be negative, in which case releases + * must occur before any acquires will be granted. + */ + public Semaphore(int permits) { + sync = new NonfairSync(permits); + } + + /** + * Creates a {@code Semaphore} with the given number of + * permits and the given fairness setting. + * + * @param permits the initial number of permits available. + * This value may be negative, in which case releases + * must occur before any acquires will be granted. + * @param fair {@code true} if this semaphore will guarantee + * first-in first-out granting of permits under contention, + * else {@code false} + */ + public Semaphore(int permits, boolean fair) { + sync = fair ? new FairSync(permits) : new NonfairSync(permits); + } + + /** + * Acquires a permit from this semaphore, blocking until one is + * available, or the thread is {@linkplain Thread#interrupt interrupted}. + * + *

Acquires a permit, if one is available and returns immediately, + * reducing the number of available permits by one. + * + *

If no permit is available then the current thread becomes + * disabled for thread scheduling purposes and lies dormant until + * one of two things happens: + *

    + *
  • Some other thread invokes the {@link #release} method for this + * semaphore and the current thread is next to be assigned a permit; or + *
  • Some other thread {@linkplain Thread#interrupt interrupts} + * the current thread. + *
+ * + *

If the current thread: + *

    + *
  • has its interrupted status set on entry to this method; or + *
  • is {@linkplain Thread#interrupt interrupted} while waiting + * for a permit, + *
+ * then {@link InterruptedException} is thrown and the current thread's + * interrupted status is cleared. + * + * @throws InterruptedException if the current thread is interrupted + */ + public void acquire() throws InterruptedException { + sync.acquireSharedInterruptibly(1); + } + + /** + * Acquires a permit from this semaphore, blocking until one is + * available. + * + *

Acquires a permit, if one is available and returns immediately, + * reducing the number of available permits by one. + * + *

If no permit is available then the current thread becomes + * disabled for thread scheduling purposes and lies dormant until + * some other thread invokes the {@link #release} method for this + * semaphore and the current thread is next to be assigned a permit. + * + *

If the current thread is {@linkplain Thread#interrupt interrupted} + * while waiting for a permit then it will continue to wait, but the + * time at which the thread is assigned a permit may change compared to + * the time it would have received the permit had no interruption + * occurred. When the thread does return from this method its interrupt + * status will be set. + */ + public void acquireUninterruptibly() { + sync.acquireShared(1); + } + + /** + * Acquires a permit from this semaphore, only if one is available at the + * time of invocation. + * + *

Acquires a permit, if one is available and returns immediately, + * with the value {@code true}, + * reducing the number of available permits by one. + * + *

If no permit is available then this method will return + * immediately with the value {@code false}. + * + *

Even when this semaphore has been set to use a + * fair ordering policy, a call to {@code tryAcquire()} will + * immediately acquire a permit if one is available, whether or not + * other threads are currently waiting. + * This "barging" behavior can be useful in certain + * circumstances, even though it breaks fairness. If you want to honor + * the fairness setting, then use + * {@link #tryAcquire(long, TimeUnit) tryAcquire(0, TimeUnit.SECONDS) } + * which is almost equivalent (it also detects interruption). + * + * @return {@code true} if a permit was acquired and {@code false} + * otherwise + */ + public boolean tryAcquire() { + return sync.nonfairTryAcquireShared(1) >= 0; + } + + /** + * Acquires a permit from this semaphore, if one becomes available + * within the given waiting time and the current thread has not + * been {@linkplain Thread#interrupt interrupted}. + * + *

Acquires a permit, if one is available and returns immediately, + * with the value {@code true}, + * reducing the number of available permits by one. + * + *

If no permit is available then the current thread becomes + * disabled for thread scheduling purposes and lies dormant until + * one of three things happens: + *

    + *
  • Some other thread invokes the {@link #release} method for this + * semaphore and the current thread is next to be assigned a permit; or + *
  • Some other thread {@linkplain Thread#interrupt interrupts} + * the current thread; or + *
  • The specified waiting time elapses. + *
+ * + *

If a permit is acquired then the value {@code true} is returned. + * + *

If the current thread: + *

    + *
  • has its interrupted status set on entry to this method; or + *
  • is {@linkplain Thread#interrupt interrupted} while waiting + * to acquire a permit, + *
+ * then {@link InterruptedException} is thrown and the current thread's + * interrupted status is cleared. + * + *

If the specified waiting time elapses then the value {@code false} + * is returned. If the time is less than or equal to zero, the method + * will not wait at all. + * + * @param timeout the maximum time to wait for a permit + * @param unit the time unit of the {@code timeout} argument + * @return {@code true} if a permit was acquired and {@code false} + * if the waiting time elapsed before a permit was acquired + * @throws InterruptedException if the current thread is interrupted + */ + public boolean tryAcquire(long timeout, TimeUnit unit) + throws InterruptedException { + return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout)); + } + + /** + * Releases a permit, returning it to the semaphore. + * + *

Releases a permit, increasing the number of available permits by + * one. If any threads are trying to acquire a permit, then one is + * selected and given the permit that was just released. That thread + * is (re)enabled for thread scheduling purposes. + * + *

There is no requirement that a thread that releases a permit must + * have acquired that permit by calling {@link #acquire}. + * Correct usage of a semaphore is established by programming convention + * in the application. + */ + public void release() { + sync.releaseShared(1); + } + + /** + * Acquires the given number of permits from this semaphore, + * blocking until all are available, + * or the thread is {@linkplain Thread#interrupt interrupted}. + * + *

Acquires the given number of permits, if they are available, + * and returns immediately, reducing the number of available permits + * by the given amount. + * + *

If insufficient permits are available then the current thread becomes + * disabled for thread scheduling purposes and lies dormant until + * one of two things happens: + *

    + *
  • Some other thread invokes one of the {@link #release() release} + * methods for this semaphore, the current thread is next to be assigned + * permits and the number of available permits satisfies this request; or + *
  • Some other thread {@linkplain Thread#interrupt interrupts} + * the current thread. + *
+ * + *

If the current thread: + *

    + *
  • has its interrupted status set on entry to this method; or + *
  • is {@linkplain Thread#interrupt interrupted} while waiting + * for a permit, + *
+ * then {@link InterruptedException} is thrown and the current thread's + * interrupted status is cleared. + * Any permits that were to be assigned to this thread are instead + * assigned to other threads trying to acquire permits, as if + * permits had been made available by a call to {@link #release()}. + * + * @param permits the number of permits to acquire + * @throws InterruptedException if the current thread is interrupted + * @throws IllegalArgumentException if {@code permits} is negative + */ + public void acquire(int permits) throws InterruptedException { + if (permits < 0) throw new IllegalArgumentException(); + sync.acquireSharedInterruptibly(permits); + } + + /** + * Acquires the given number of permits from this semaphore, + * blocking until all are available. + * + *

Acquires the given number of permits, if they are available, + * and returns immediately, reducing the number of available permits + * by the given amount. + * + *

If insufficient permits are available then the current thread becomes + * disabled for thread scheduling purposes and lies dormant until + * some other thread invokes one of the {@link #release() release} + * methods for this semaphore, the current thread is next to be assigned + * permits and the number of available permits satisfies this request. + * + *

If the current thread is {@linkplain Thread#interrupt interrupted} + * while waiting for permits then it will continue to wait and its + * position in the queue is not affected. When the thread does return + * from this method its interrupt status will be set. + * + * @param permits the number of permits to acquire + * @throws IllegalArgumentException if {@code permits} is negative + * + */ + public void acquireUninterruptibly(int permits) { + if (permits < 0) throw new IllegalArgumentException(); + sync.acquireShared(permits); + } + + /** + * Acquires the given number of permits from this semaphore, only + * if all are available at the time of invocation. + * + *

Acquires the given number of permits, if they are available, and + * returns immediately, with the value {@code true}, + * reducing the number of available permits by the given amount. + * + *

If insufficient permits are available then this method will return + * immediately with the value {@code false} and the number of available + * permits is unchanged. + * + *

Even when this semaphore has been set to use a fair ordering + * policy, a call to {@code tryAcquire} will + * immediately acquire a permit if one is available, whether or + * not other threads are currently waiting. This + * "barging" behavior can be useful in certain + * circumstances, even though it breaks fairness. If you want to + * honor the fairness setting, then use {@link #tryAcquire(int, + * long, TimeUnit) tryAcquire(permits, 0, TimeUnit.SECONDS) } + * which is almost equivalent (it also detects interruption). + * + * @param permits the number of permits to acquire + * @return {@code true} if the permits were acquired and + * {@code false} otherwise + * @throws IllegalArgumentException if {@code permits} is negative + */ + public boolean tryAcquire(int permits) { + if (permits < 0) throw new IllegalArgumentException(); + return sync.nonfairTryAcquireShared(permits) >= 0; + } + + /** + * Acquires the given number of permits from this semaphore, if all + * become available within the given waiting time and the current + * thread has not been {@linkplain Thread#interrupt interrupted}. + * + *

Acquires the given number of permits, if they are available and + * returns immediately, with the value {@code true}, + * reducing the number of available permits by the given amount. + * + *

If insufficient permits are available then + * the current thread becomes disabled for thread scheduling + * purposes and lies dormant until one of three things happens: + *

    + *
  • Some other thread invokes one of the {@link #release() release} + * methods for this semaphore, the current thread is next to be assigned + * permits and the number of available permits satisfies this request; or + *
  • Some other thread {@linkplain Thread#interrupt interrupts} + * the current thread; or + *
  • The specified waiting time elapses. + *
+ * + *

If the permits are acquired then the value {@code true} is returned. + * + *

If the current thread: + *

    + *
  • has its interrupted status set on entry to this method; or + *
  • is {@linkplain Thread#interrupt interrupted} while waiting + * to acquire the permits, + *
+ * then {@link InterruptedException} is thrown and the current thread's + * interrupted status is cleared. + * Any permits that were to be assigned to this thread, are instead + * assigned to other threads trying to acquire permits, as if + * the permits had been made available by a call to {@link #release()}. + * + *

If the specified waiting time elapses then the value {@code false} + * is returned. If the time is less than or equal to zero, the method + * will not wait at all. Any permits that were to be assigned to this + * thread, are instead assigned to other threads trying to acquire + * permits, as if the permits had been made available by a call to + * {@link #release()}. + * + * @param permits the number of permits to acquire + * @param timeout the maximum time to wait for the permits + * @param unit the time unit of the {@code timeout} argument + * @return {@code true} if all permits were acquired and {@code false} + * if the waiting time elapsed before all permits were acquired + * @throws InterruptedException if the current thread is interrupted + * @throws IllegalArgumentException if {@code permits} is negative + */ + public boolean tryAcquire(int permits, long timeout, TimeUnit unit) + throws InterruptedException { + if (permits < 0) throw new IllegalArgumentException(); + return sync.tryAcquireSharedNanos(permits, unit.toNanos(timeout)); + } + + /** + * Releases the given number of permits, returning them to the semaphore. + * + *

Releases the given number of permits, increasing the number of + * available permits by that amount. + * If any threads are trying to acquire permits, then one + * is selected and given the permits that were just released. + * If the number of available permits satisfies that thread's request + * then that thread is (re)enabled for thread scheduling purposes; + * otherwise the thread will wait until sufficient permits are available. + * If there are still permits available + * after this thread's request has been satisfied, then those permits + * are assigned in turn to other threads trying to acquire permits. + * + *

There is no requirement that a thread that releases a permit must + * have acquired that permit by calling {@link Semaphore#acquire acquire}. + * Correct usage of a semaphore is established by programming convention + * in the application. + * + * @param permits the number of permits to release + * @throws IllegalArgumentException if {@code permits} is negative + */ + public void release(int permits) { + if (permits < 0) throw new IllegalArgumentException(); + sync.releaseShared(permits); + } + + /** + * Returns the current number of permits available in this semaphore. + * + *

This method is typically used for debugging and testing purposes. + * + * @return the number of permits available in this semaphore + */ + public int availablePermits() { + return sync.getPermits(); + } + + /** + * Acquires and returns all permits that are immediately available. + * + * @return the number of permits acquired + */ + public int drainPermits() { + return sync.drainPermits(); + } + + /** + * Shrinks the number of available permits by the indicated + * reduction. This method can be useful in subclasses that use + * semaphores to track resources that become unavailable. This + * method differs from {@code acquire} in that it does not block + * waiting for permits to become available. + * + * @param reduction the number of permits to remove + * @throws IllegalArgumentException if {@code reduction} is negative + */ + protected void reducePermits(int reduction) { + if (reduction < 0) throw new IllegalArgumentException(); + sync.reducePermits(reduction); + } + + /** + * Returns {@code true} if this semaphore has fairness set true. + * + * @return {@code true} if this semaphore has fairness set true + */ + public boolean isFair() { + return sync instanceof FairSync; + } + + /** + * Queries whether any threads are waiting to acquire. Note that + * because cancellations may occur at any time, a {@code true} + * return does not guarantee that any other thread will ever + * acquire. This method is designed primarily for use in + * monitoring of the system state. + * + * @return {@code true} if there may be other threads waiting to + * acquire the lock + */ + public final boolean hasQueuedThreads() { + return sync.hasQueuedThreads(); + } + + /** + * Returns an estimate of the number of threads waiting to acquire. + * The value is only an estimate because the number of threads may + * change dynamically while this method traverses internal data + * structures. This method is designed for use in monitoring of the + * system state, not for synchronization control. + * + * @return the estimated number of threads waiting for this lock + */ + public final int getQueueLength() { + return sync.getQueueLength(); + } + + /** + * Returns a collection containing threads that may be waiting to acquire. + * Because the actual set of threads may change dynamically while + * constructing this result, the returned collection is only a best-effort + * estimate. The elements of the returned collection are in no particular + * order. This method is designed to facilitate construction of + * subclasses that provide more extensive monitoring facilities. + * + * @return the collection of threads + */ + protected Collection getQueuedThreads() { + return sync.getQueuedThreads(); + } + + /** + * Returns a string identifying this semaphore, as well as its state. + * The state, in brackets, includes the String {@code "Permits ="} + * followed by the number of permits. + * + * @return a string identifying this semaphore, as well as its state + */ + public String toString() { + return super.toString() + "[Permits = " + sync.getPermits() + "]"; + } +} diff -r e1953d8b8338 -r c8af252ea9eb rt/emul/compact/src/main/java/java/util/concurrent/SynchronousQueue.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/SynchronousQueue.java Sat Mar 19 10:48:29 2016 +0100 @@ -0,0 +1,1196 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea, Bill Scherer, and Michael Scott with + * assistance from members of JCP JSR-166 Expert Group and released to + * the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +package java.util.concurrent; +import java.util.concurrent.locks.*; +import java.util.concurrent.atomic.*; +import java.util.*; + +/** + * A {@linkplain BlockingQueue blocking queue} in which each insert + * operation must wait for a corresponding remove operation by another + * thread, and vice versa. A synchronous queue does not have any + * internal capacity, not even a capacity of one. You cannot + * peek at a synchronous queue because an element is only + * present when you try to remove it; you cannot insert an element + * (using any method) unless another thread is trying to remove it; + * you cannot iterate as there is nothing to iterate. The + * head of the queue is the element that the first queued + * inserting thread is trying to add to the queue; if there is no such + * queued thread then no element is available for removal and + * poll() will return null. For purposes of other + * Collection methods (for example contains), a + * SynchronousQueue acts as an empty collection. This queue + * does not permit null elements. + * + *

Synchronous queues are similar to rendezvous channels used in + * CSP and Ada. They are well suited for handoff designs, in which an + * object running in one thread must sync up with an object running + * in another thread in order to hand it some information, event, or + * task. + * + *

This class supports an optional fairness policy for ordering + * waiting producer and consumer threads. By default, this ordering + * is not guaranteed. However, a queue constructed with fairness set + * to true grants threads access in FIFO order. + * + *

This class and its iterator implement all of the + * optional methods of the {@link Collection} and {@link + * Iterator} interfaces. + * + *

This class is a member of the + * + * Java Collections Framework. + * + * @since 1.5 + * @author Doug Lea and Bill Scherer and Michael Scott + * @param the type of elements held in this collection + */ +public class SynchronousQueue extends AbstractQueue + implements BlockingQueue, java.io.Serializable { + private static final long serialVersionUID = -3223113410248163686L; + + /* + * This class implements extensions of the dual stack and dual + * queue algorithms described in "Nonblocking Concurrent Objects + * with Condition Synchronization", by W. N. Scherer III and + * M. L. Scott. 18th Annual Conf. on Distributed Computing, + * Oct. 2004 (see also + * http://www.cs.rochester.edu/u/scott/synchronization/pseudocode/duals.html). + * The (Lifo) stack is used for non-fair mode, and the (Fifo) + * queue for fair mode. The performance of the two is generally + * similar. Fifo usually supports higher throughput under + * contention but Lifo maintains higher thread locality in common + * applications. + * + * A dual queue (and similarly stack) is one that at any given + * time either holds "data" -- items provided by put operations, + * or "requests" -- slots representing take operations, or is + * empty. A call to "fulfill" (i.e., a call requesting an item + * from a queue holding data or vice versa) dequeues a + * complementary node. The most interesting feature of these + * queues is that any operation can figure out which mode the + * queue is in, and act accordingly without needing locks. + * + * Both the queue and stack extend abstract class Transferer + * defining the single method transfer that does a put or a + * take. These are unified into a single method because in dual + * data structures, the put and take operations are symmetrical, + * so nearly all code can be combined. The resulting transfer + * methods are on the long side, but are easier to follow than + * they would be if broken up into nearly-duplicated parts. + * + * The queue and stack data structures share many conceptual + * similarities but very few concrete details. For simplicity, + * they are kept distinct so that they can later evolve + * separately. + * + * The algorithms here differ from the versions in the above paper + * in extending them for use in synchronous queues, as well as + * dealing with cancellation. The main differences include: + * + * 1. The original algorithms used bit-marked pointers, but + * the ones here use mode bits in nodes, leading to a number + * of further adaptations. + * 2. SynchronousQueues must block threads waiting to become + * fulfilled. + * 3. Support for cancellation via timeout and interrupts, + * including cleaning out cancelled nodes/threads + * from lists to avoid garbage retention and memory depletion. + * + * Blocking is mainly accomplished using LockSupport park/unpark, + * except that nodes that appear to be the next ones to become + * fulfilled first spin a bit (on multiprocessors only). On very + * busy synchronous queues, spinning can dramatically improve + * throughput. And on less busy ones, the amount of spinning is + * small enough not to be noticeable. + * + * Cleaning is done in different ways in queues vs stacks. For + * queues, we can almost always remove a node immediately in O(1) + * time (modulo retries for consistency checks) when it is + * cancelled. But if it may be pinned as the current tail, it must + * wait until some subsequent cancellation. For stacks, we need a + * potentially O(n) traversal to be sure that we can remove the + * node, but this can run concurrently with other threads + * accessing the stack. + * + * While garbage collection takes care of most node reclamation + * issues that otherwise complicate nonblocking algorithms, care + * is taken to "forget" references to data, other nodes, and + * threads that might be held on to long-term by blocked + * threads. In cases where setting to null would otherwise + * conflict with main algorithms, this is done by changing a + * node's link to now point to the node itself. This doesn't arise + * much for Stack nodes (because blocked threads do not hang on to + * old head pointers), but references in Queue nodes must be + * aggressively forgotten to avoid reachability of everything any + * node has ever referred to since arrival. + */ + + /** + * Shared internal API for dual stacks and queues. + */ + abstract static class Transferer { + /** + * Performs a put or take. + * + * @param e if non-null, the item to be handed to a consumer; + * if null, requests that transfer return an item + * offered by producer. + * @param timed if this operation should timeout + * @param nanos the timeout, in nanoseconds + * @return if non-null, the item provided or received; if null, + * the operation failed due to timeout or interrupt -- + * the caller can distinguish which of these occurred + * by checking Thread.interrupted. + */ + abstract Object transfer(Object e, boolean timed, long nanos); + } + + /** The number of CPUs, for spin control */ + static final int NCPUS = Runtime.getRuntime().availableProcessors(); + + /** + * The number of times to spin before blocking in timed waits. + * The value is empirically derived -- it works well across a + * variety of processors and OSes. Empirically, the best value + * seems not to vary with number of CPUs (beyond 2) so is just + * a constant. + */ + static final int maxTimedSpins = (NCPUS < 2) ? 0 : 32; + + /** + * The number of times to spin before blocking in untimed waits. + * This is greater than timed value because untimed waits spin + * faster since they don't need to check times on each spin. + */ + static final int maxUntimedSpins = maxTimedSpins * 16; + + /** + * The number of nanoseconds for which it is faster to spin + * rather than to use timed park. A rough estimate suffices. + */ + static final long spinForTimeoutThreshold = 1000L; + + /** Dual stack */ + static final class TransferStack extends Transferer { + /* + * This extends Scherer-Scott dual stack algorithm, differing, + * among other ways, by using "covering" nodes rather than + * bit-marked pointers: Fulfilling operations push on marker + * nodes (with FULFILLING bit set in mode) to reserve a spot + * to match a waiting node. + */ + + /* Modes for SNodes, ORed together in node fields */ + /** Node represents an unfulfilled consumer */ + static final int REQUEST = 0; + /** Node represents an unfulfilled producer */ + static final int DATA = 1; + /** Node is fulfilling another unfulfilled DATA or REQUEST */ + static final int FULFILLING = 2; + + /** Return true if m has fulfilling bit set */ + static boolean isFulfilling(int m) { return (m & FULFILLING) != 0; } + + /** Node class for TransferStacks. */ + static final class SNode { + volatile SNode next; // next node in stack + volatile SNode match; // the node matched to this + volatile Thread waiter; // to control park/unpark + Object item; // data; or null for REQUESTs + int mode; + // Note: item and mode fields don't need to be volatile + // since they are always written before, and read after, + // other volatile/atomic operations. + + SNode(Object item) { + this.item = item; + } + + boolean casNext(SNode cmp, SNode val) { + return cmp == next && + UNSAFE.compareAndSwapObject(this, nextOffset, cmp, val); + } + + /** + * Tries to match node s to this node, if so, waking up thread. + * Fulfillers call tryMatch to identify their waiters. + * Waiters block until they have been matched. + * + * @param s the node to match + * @return true if successfully matched to s + */ + boolean tryMatch(SNode s) { + if (match == null && + UNSAFE.compareAndSwapObject(this, matchOffset, null, s)) { + Thread w = waiter; + if (w != null) { // waiters need at most one unpark + waiter = null; + LockSupport.unpark(w); + } + return true; + } + return match == s; + } + + /** + * Tries to cancel a wait by matching node to itself. + */ + void tryCancel() { + UNSAFE.compareAndSwapObject(this, matchOffset, null, this); + } + + boolean isCancelled() { + return match == this; + } + + // Unsafe mechanics + private static final sun.misc.Unsafe UNSAFE; + private static final long matchOffset; + private static final long nextOffset; + + static { + try { + UNSAFE = sun.misc.Unsafe.getUnsafe(); + Class k = SNode.class; + matchOffset = UNSAFE.objectFieldOffset + (k.getDeclaredField("match")); + nextOffset = UNSAFE.objectFieldOffset + (k.getDeclaredField("next")); + } catch (Exception e) { + throw new Error(e); + } + } + } + + /** The head (top) of the stack */ + volatile SNode head; + + boolean casHead(SNode h, SNode nh) { + return h == head && + UNSAFE.compareAndSwapObject(this, headOffset, h, nh); + } + + /** + * Creates or resets fields of a node. Called only from transfer + * where the node to push on stack is lazily created and + * reused when possible to help reduce intervals between reads + * and CASes of head and to avoid surges of garbage when CASes + * to push nodes fail due to contention. + */ + static SNode snode(SNode s, Object e, SNode next, int mode) { + if (s == null) s = new SNode(e); + s.mode = mode; + s.next = next; + return s; + } + + /** + * Puts or takes an item. + */ + Object transfer(Object e, boolean timed, long nanos) { + /* + * Basic algorithm is to loop trying one of three actions: + * + * 1. If apparently empty or already containing nodes of same + * mode, try to push node on stack and wait for a match, + * returning it, or null if cancelled. + * + * 2. If apparently containing node of complementary mode, + * try to push a fulfilling node on to stack, match + * with corresponding waiting node, pop both from + * stack, and return matched item. The matching or + * unlinking might not actually be necessary because of + * other threads performing action 3: + * + * 3. If top of stack already holds another fulfilling node, + * help it out by doing its match and/or pop + * operations, and then continue. The code for helping + * is essentially the same as for fulfilling, except + * that it doesn't return the item. + */ + + SNode s = null; // constructed/reused as needed + int mode = (e == null) ? REQUEST : DATA; + + for (;;) { + SNode h = head; + if (h == null || h.mode == mode) { // empty or same-mode + if (timed && nanos <= 0) { // can't wait + if (h != null && h.isCancelled()) + casHead(h, h.next); // pop cancelled node + else + return null; + } else if (casHead(h, s = snode(s, e, h, mode))) { + SNode m = awaitFulfill(s, timed, nanos); + if (m == s) { // wait was cancelled + clean(s); + return null; + } + if ((h = head) != null && h.next == s) + casHead(h, s.next); // help s's fulfiller + return (mode == REQUEST) ? m.item : s.item; + } + } else if (!isFulfilling(h.mode)) { // try to fulfill + if (h.isCancelled()) // already cancelled + casHead(h, h.next); // pop and retry + else if (casHead(h, s=snode(s, e, h, FULFILLING|mode))) { + for (;;) { // loop until matched or waiters disappear + SNode m = s.next; // m is s's match + if (m == null) { // all waiters are gone + casHead(s, null); // pop fulfill node + s = null; // use new node next time + break; // restart main loop + } + SNode mn = m.next; + if (m.tryMatch(s)) { + casHead(s, mn); // pop both s and m + return (mode == REQUEST) ? m.item : s.item; + } else // lost match + s.casNext(m, mn); // help unlink + } + } + } else { // help a fulfiller + SNode m = h.next; // m is h's match + if (m == null) // waiter is gone + casHead(h, null); // pop fulfilling node + else { + SNode mn = m.next; + if (m.tryMatch(h)) // help match + casHead(h, mn); // pop both h and m + else // lost match + h.casNext(m, mn); // help unlink + } + } + } + } + + /** + * Spins/blocks until node s is matched by a fulfill operation. + * + * @param s the waiting node + * @param timed true if timed wait + * @param nanos timeout value + * @return matched node, or s if cancelled + */ + SNode awaitFulfill(SNode s, boolean timed, long nanos) { + /* + * When a node/thread is about to block, it sets its waiter + * field and then rechecks state at least one more time + * before actually parking, thus covering race vs + * fulfiller noticing that waiter is non-null so should be + * woken. + * + * When invoked by nodes that appear at the point of call + * to be at the head of the stack, calls to park are + * preceded by spins to avoid blocking when producers and + * consumers are arriving very close in time. This can + * happen enough to bother only on multiprocessors. + * + * The order of checks for returning out of main loop + * reflects fact that interrupts have precedence over + * normal returns, which have precedence over + * timeouts. (So, on timeout, one last check for match is + * done before giving up.) Except that calls from untimed + * SynchronousQueue.{poll/offer} don't check interrupts + * and don't wait at all, so are trapped in transfer + * method rather than calling awaitFulfill. + */ + long lastTime = timed ? System.nanoTime() : 0; + Thread w = Thread.currentThread(); + SNode h = head; + int spins = (shouldSpin(s) ? + (timed ? maxTimedSpins : maxUntimedSpins) : 0); + for (;;) { + if (w.isInterrupted()) + s.tryCancel(); + SNode m = s.match; + if (m != null) + return m; + if (timed) { + long now = System.nanoTime(); + nanos -= now - lastTime; + lastTime = now; + if (nanos <= 0) { + s.tryCancel(); + continue; + } + } + if (spins > 0) + spins = shouldSpin(s) ? (spins-1) : 0; + else if (s.waiter == null) + s.waiter = w; // establish waiter so can park next iter + else if (!timed) + LockSupport.park(this); + else if (nanos > spinForTimeoutThreshold) + LockSupport.parkNanos(this, nanos); + } + } + + /** + * Returns true if node s is at head or there is an active + * fulfiller. + */ + boolean shouldSpin(SNode s) { + SNode h = head; + return (h == s || h == null || isFulfilling(h.mode)); + } + + /** + * Unlinks s from the stack. + */ + void clean(SNode s) { + s.item = null; // forget item + s.waiter = null; // forget thread + + /* + * At worst we may need to traverse entire stack to unlink + * s. If there are multiple concurrent calls to clean, we + * might not see s if another thread has already removed + * it. But we can stop when we see any node known to + * follow s. We use s.next unless it too is cancelled, in + * which case we try the node one past. We don't check any + * further because we don't want to doubly traverse just to + * find sentinel. + */ + + SNode past = s.next; + if (past != null && past.isCancelled()) + past = past.next; + + // Absorb cancelled nodes at head + SNode p; + while ((p = head) != null && p != past && p.isCancelled()) + casHead(p, p.next); + + // Unsplice embedded nodes + while (p != null && p != past) { + SNode n = p.next; + if (n != null && n.isCancelled()) + p.casNext(n, n.next); + else + p = n; + } + } + + // Unsafe mechanics + private static final sun.misc.Unsafe UNSAFE; + private static final long headOffset; + static { + try { + UNSAFE = sun.misc.Unsafe.getUnsafe(); + Class k = TransferStack.class; + headOffset = UNSAFE.objectFieldOffset + (k.getDeclaredField("head")); + } catch (Exception e) { + throw new Error(e); + } + } + } + + /** Dual Queue */ + static final class TransferQueue extends Transferer { + /* + * This extends Scherer-Scott dual queue algorithm, differing, + * among other ways, by using modes within nodes rather than + * marked pointers. The algorithm is a little simpler than + * that for stacks because fulfillers do not need explicit + * nodes, and matching is done by CAS'ing QNode.item field + * from non-null to null (for put) or vice versa (for take). + */ + + /** Node class for TransferQueue. */ + static final class QNode { + volatile QNode next; // next node in queue + volatile Object item; // CAS'ed to or from null + volatile Thread waiter; // to control park/unpark + final boolean isData; + + QNode(Object item, boolean isData) { + this.item = item; + this.isData = isData; + } + + boolean casNext(QNode cmp, QNode val) { + return next == cmp && + UNSAFE.compareAndSwapObject(this, nextOffset, cmp, val); + } + + boolean casItem(Object cmp, Object val) { + return item == cmp && + UNSAFE.compareAndSwapObject(this, itemOffset, cmp, val); + } + + /** + * Tries to cancel by CAS'ing ref to this as item. + */ + void tryCancel(Object cmp) { + UNSAFE.compareAndSwapObject(this, itemOffset, cmp, this); + } + + boolean isCancelled() { + return item == this; + } + + /** + * Returns true if this node is known to be off the queue + * because its next pointer has been forgotten due to + * an advanceHead operation. + */ + boolean isOffList() { + return next == this; + } + + // Unsafe mechanics + private static final sun.misc.Unsafe UNSAFE; + private static final long itemOffset; + private static final long nextOffset; + + static { + try { + UNSAFE = sun.misc.Unsafe.getUnsafe(); + Class k = QNode.class; + itemOffset = UNSAFE.objectFieldOffset + (k.getDeclaredField("item")); + nextOffset = UNSAFE.objectFieldOffset + (k.getDeclaredField("next")); + } catch (Exception e) { + throw new Error(e); + } + } + } + + /** Head of queue */ + transient volatile QNode head; + /** Tail of queue */ + transient volatile QNode tail; + /** + * Reference to a cancelled node that might not yet have been + * unlinked from queue because it was the last inserted node + * when it cancelled. + */ + transient volatile QNode cleanMe; + + TransferQueue() { + QNode h = new QNode(null, false); // initialize to dummy node. + head = h; + tail = h; + } + + /** + * Tries to cas nh as new head; if successful, unlink + * old head's next node to avoid garbage retention. + */ + void advanceHead(QNode h, QNode nh) { + if (h == head && + UNSAFE.compareAndSwapObject(this, headOffset, h, nh)) + h.next = h; // forget old next + } + + /** + * Tries to cas nt as new tail. + */ + void advanceTail(QNode t, QNode nt) { + if (tail == t) + UNSAFE.compareAndSwapObject(this, tailOffset, t, nt); + } + + /** + * Tries to CAS cleanMe slot. + */ + boolean casCleanMe(QNode cmp, QNode val) { + return cleanMe == cmp && + UNSAFE.compareAndSwapObject(this, cleanMeOffset, cmp, val); + } + + /** + * Puts or takes an item. + */ + Object transfer(Object e, boolean timed, long nanos) { + /* Basic algorithm is to loop trying to take either of + * two actions: + * + * 1. If queue apparently empty or holding same-mode nodes, + * try to add node to queue of waiters, wait to be + * fulfilled (or cancelled) and return matching item. + * + * 2. If queue apparently contains waiting items, and this + * call is of complementary mode, try to fulfill by CAS'ing + * item field of waiting node and dequeuing it, and then + * returning matching item. + * + * In each case, along the way, check for and try to help + * advance head and tail on behalf of other stalled/slow + * threads. + * + * The loop starts off with a null check guarding against + * seeing uninitialized head or tail values. This never + * happens in current SynchronousQueue, but could if + * callers held non-volatile/final ref to the + * transferer. The check is here anyway because it places + * null checks at top of loop, which is usually faster + * than having them implicitly interspersed. + */ + + QNode s = null; // constructed/reused as needed + boolean isData = (e != null); + + for (;;) { + QNode t = tail; + QNode h = head; + if (t == null || h == null) // saw uninitialized value + continue; // spin + + if (h == t || t.isData == isData) { // empty or same-mode + QNode tn = t.next; + if (t != tail) // inconsistent read + continue; + if (tn != null) { // lagging tail + advanceTail(t, tn); + continue; + } + if (timed && nanos <= 0) // can't wait + return null; + if (s == null) + s = new QNode(e, isData); + if (!t.casNext(null, s)) // failed to link in + continue; + + advanceTail(t, s); // swing tail and wait + Object x = awaitFulfill(s, e, timed, nanos); + if (x == s) { // wait was cancelled + clean(t, s); + return null; + } + + if (!s.isOffList()) { // not already unlinked + advanceHead(t, s); // unlink if head + if (x != null) // and forget fields + s.item = s; + s.waiter = null; + } + return (x != null) ? x : e; + + } else { // complementary-mode + QNode m = h.next; // node to fulfill + if (t != tail || m == null || h != head) + continue; // inconsistent read + + Object x = m.item; + if (isData == (x != null) || // m already fulfilled + x == m || // m cancelled + !m.casItem(x, e)) { // lost CAS + advanceHead(h, m); // dequeue and retry + continue; + } + + advanceHead(h, m); // successfully fulfilled + LockSupport.unpark(m.waiter); + return (x != null) ? x : e; + } + } + } + + /** + * Spins/blocks until node s is fulfilled. + * + * @param s the waiting node + * @param e the comparison value for checking match + * @param timed true if timed wait + * @param nanos timeout value + * @return matched item, or s if cancelled + */ + Object awaitFulfill(QNode s, Object e, boolean timed, long nanos) { + /* Same idea as TransferStack.awaitFulfill */ + long lastTime = timed ? System.nanoTime() : 0; + Thread w = Thread.currentThread(); + int spins = ((head.next == s) ? + (timed ? maxTimedSpins : maxUntimedSpins) : 0); + for (;;) { + if (w.isInterrupted()) + s.tryCancel(e); + Object x = s.item; + if (x != e) + return x; + if (timed) { + long now = System.nanoTime(); + nanos -= now - lastTime; + lastTime = now; + if (nanos <= 0) { + s.tryCancel(e); + continue; + } + } + if (spins > 0) + --spins; + else if (s.waiter == null) + s.waiter = w; + else if (!timed) + LockSupport.park(this); + else if (nanos > spinForTimeoutThreshold) + LockSupport.parkNanos(this, nanos); + } + } + + /** + * Gets rid of cancelled node s with original predecessor pred. + */ + void clean(QNode pred, QNode s) { + s.waiter = null; // forget thread + /* + * At any given time, exactly one node on list cannot be + * deleted -- the last inserted node. To accommodate this, + * if we cannot delete s, we save its predecessor as + * "cleanMe", deleting the previously saved version + * first. At least one of node s or the node previously + * saved can always be deleted, so this always terminates. + */ + while (pred.next == s) { // Return early if already unlinked + QNode h = head; + QNode hn = h.next; // Absorb cancelled first node as head + if (hn != null && hn.isCancelled()) { + advanceHead(h, hn); + continue; + } + QNode t = tail; // Ensure consistent read for tail + if (t == h) + return; + QNode tn = t.next; + if (t != tail) + continue; + if (tn != null) { + advanceTail(t, tn); + continue; + } + if (s != t) { // If not tail, try to unsplice + QNode sn = s.next; + if (sn == s || pred.casNext(s, sn)) + return; + } + QNode dp = cleanMe; + if (dp != null) { // Try unlinking previous cancelled node + QNode d = dp.next; + QNode dn; + if (d == null || // d is gone or + d == dp || // d is off list or + !d.isCancelled() || // d not cancelled or + (d != t && // d not tail and + (dn = d.next) != null && // has successor + dn != d && // that is on list + dp.casNext(d, dn))) // d unspliced + casCleanMe(dp, null); + if (dp == pred) + return; // s is already saved node + } else if (casCleanMe(null, pred)) + return; // Postpone cleaning s + } + } + + private static final sun.misc.Unsafe UNSAFE; + private static final long headOffset; + private static final long tailOffset; + private static final long cleanMeOffset; + static { + try { + UNSAFE = sun.misc.Unsafe.getUnsafe(); + Class k = TransferQueue.class; + headOffset = UNSAFE.objectFieldOffset + (k.getDeclaredField("head")); + tailOffset = UNSAFE.objectFieldOffset + (k.getDeclaredField("tail")); + cleanMeOffset = UNSAFE.objectFieldOffset + (k.getDeclaredField("cleanMe")); + } catch (Exception e) { + throw new Error(e); + } + } + } + + /** + * The transferer. Set only in constructor, but cannot be declared + * as final without further complicating serialization. Since + * this is accessed only at most once per public method, there + * isn't a noticeable performance penalty for using volatile + * instead of final here. + */ + private transient volatile Transferer transferer; + + /** + * Creates a SynchronousQueue with nonfair access policy. + */ + public SynchronousQueue() { + this(false); + } + + /** + * Creates a SynchronousQueue with the specified fairness policy. + * + * @param fair if true, waiting threads contend in FIFO order for + * access; otherwise the order is unspecified. + */ + public SynchronousQueue(boolean fair) { + transferer = fair ? new TransferQueue() : new TransferStack(); + } + + /** + * Adds the specified element to this queue, waiting if necessary for + * another thread to receive it. + * + * @throws InterruptedException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + */ + public void put(E o) throws InterruptedException { + if (o == null) throw new NullPointerException(); + if (transferer.transfer(o, false, 0) == null) { + Thread.interrupted(); + throw new InterruptedException(); + } + } + + /** + * Inserts the specified element into this queue, waiting if necessary + * up to the specified wait time for another thread to receive it. + * + * @return true if successful, or false if the + * specified waiting time elapses before a consumer appears. + * @throws InterruptedException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + */ + public boolean offer(E o, long timeout, TimeUnit unit) + throws InterruptedException { + if (o == null) throw new NullPointerException(); + if (transferer.transfer(o, true, unit.toNanos(timeout)) != null) + return true; + if (!Thread.interrupted()) + return false; + throw new InterruptedException(); + } + + /** + * Inserts the specified element into this queue, if another thread is + * waiting to receive it. + * + * @param e the element to add + * @return true if the element was added to this queue, else + * false + * @throws NullPointerException if the specified element is null + */ + public boolean offer(E e) { + if (e == null) throw new NullPointerException(); + return transferer.transfer(e, true, 0) != null; + } + + /** + * Retrieves and removes the head of this queue, waiting if necessary + * for another thread to insert it. + * + * @return the head of this queue + * @throws InterruptedException {@inheritDoc} + */ + public E take() throws InterruptedException { + Object e = transferer.transfer(null, false, 0); + if (e != null) + return (E)e; + Thread.interrupted(); + throw new InterruptedException(); + } + + /** + * Retrieves and removes the head of this queue, waiting + * if necessary up to the specified wait time, for another thread + * to insert it. + * + * @return the head of this queue, or null if the + * specified waiting time elapses before an element is present. + * @throws InterruptedException {@inheritDoc} + */ + public E poll(long timeout, TimeUnit unit) throws InterruptedException { + Object e = transferer.transfer(null, true, unit.toNanos(timeout)); + if (e != null || !Thread.interrupted()) + return (E)e; + throw new InterruptedException(); + } + + /** + * Retrieves and removes the head of this queue, if another thread + * is currently making an element available. + * + * @return the head of this queue, or null if no + * element is available. + */ + public E poll() { + return (E)transferer.transfer(null, true, 0); + } + + /** + * Always returns true. + * A SynchronousQueue has no internal capacity. + * + * @return true + */ + public boolean isEmpty() { + return true; + } + + /** + * Always returns zero. + * A SynchronousQueue has no internal capacity. + * + * @return zero. + */ + public int size() { + return 0; + } + + /** + * Always returns zero. + * A SynchronousQueue has no internal capacity. + * + * @return zero. + */ + public int remainingCapacity() { + return 0; + } + + /** + * Does nothing. + * A SynchronousQueue has no internal capacity. + */ + public void clear() { + } + + /** + * Always returns false. + * A SynchronousQueue has no internal capacity. + * + * @param o the element + * @return false + */ + public boolean contains(Object o) { + return false; + } + + /** + * Always returns false. + * A SynchronousQueue has no internal capacity. + * + * @param o the element to remove + * @return false + */ + public boolean remove(Object o) { + return false; + } + + /** + * Returns false unless the given collection is empty. + * A SynchronousQueue has no internal capacity. + * + * @param c the collection + * @return false unless given collection is empty + */ + public boolean containsAll(Collection c) { + return c.isEmpty(); + } + + /** + * Always returns false. + * A SynchronousQueue has no internal capacity. + * + * @param c the collection + * @return false + */ + public boolean removeAll(Collection c) { + return false; + } + + /** + * Always returns false. + * A SynchronousQueue has no internal capacity. + * + * @param c the collection + * @return false + */ + public boolean retainAll(Collection c) { + return false; + } + + /** + * Always returns null. + * A SynchronousQueue does not return elements + * unless actively waited on. + * + * @return null + */ + public E peek() { + return null; + } + + /** + * Returns an empty iterator in which hasNext always returns + * false. + * + * @return an empty iterator + */ + public Iterator iterator() { + return Collections.emptyIterator(); + } + + /** + * Returns a zero-length array. + * @return a zero-length array + */ + public Object[] toArray() { + return new Object[0]; + } + + /** + * Sets the zeroeth element of the specified array to null + * (if the array has non-zero length) and returns it. + * + * @param a the array + * @return the specified array + * @throws NullPointerException if the specified array is null + */ + public T[] toArray(T[] a) { + if (a.length > 0) + a[0] = null; + return a; + } + + /** + * @throws UnsupportedOperationException {@inheritDoc} + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + * @throws IllegalArgumentException {@inheritDoc} + */ + public int drainTo(Collection c) { + if (c == null) + throw new NullPointerException(); + if (c == this) + throw new IllegalArgumentException(); + int n = 0; + E e; + while ( (e = poll()) != null) { + c.add(e); + ++n; + } + return n; + } + + /** + * @throws UnsupportedOperationException {@inheritDoc} + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + * @throws IllegalArgumentException {@inheritDoc} + */ + public int drainTo(Collection c, int maxElements) { + if (c == null) + throw new NullPointerException(); + if (c == this) + throw new IllegalArgumentException(); + int n = 0; + E e; + while (n < maxElements && (e = poll()) != null) { + c.add(e); + ++n; + } + return n; + } + + /* + * To cope with serialization strategy in the 1.5 version of + * SynchronousQueue, we declare some unused classes and fields + * that exist solely to enable serializability across versions. + * These fields are never used, so are initialized only if this + * object is ever serialized or deserialized. + */ + + static class WaitQueue implements java.io.Serializable { } + static class LifoWaitQueue extends WaitQueue { + private static final long serialVersionUID = -3633113410248163686L; + } + static class FifoWaitQueue extends WaitQueue { + private static final long serialVersionUID = -3623113410248163686L; + } + private ReentrantLock qlock; + private WaitQueue waitingProducers; + private WaitQueue waitingConsumers; + + /** + * Save the state to a stream (that is, serialize it). + * + * @param s the stream + */ + private void writeObject(java.io.ObjectOutputStream s) + throws java.io.IOException { + boolean fair = transferer instanceof TransferQueue; + if (fair) { + qlock = new ReentrantLock(true); + waitingProducers = new FifoWaitQueue(); + waitingConsumers = new FifoWaitQueue(); + } + else { + qlock = new ReentrantLock(); + waitingProducers = new LifoWaitQueue(); + waitingConsumers = new LifoWaitQueue(); + } + s.defaultWriteObject(); + } + + private void readObject(final java.io.ObjectInputStream s) + throws java.io.IOException, ClassNotFoundException { + s.defaultReadObject(); + if (waitingProducers instanceof FifoWaitQueue) + transferer = new TransferQueue(); + else + transferer = new TransferStack(); + } + + // Unsafe mechanics + static long objectFieldOffset(sun.misc.Unsafe UNSAFE, + String field, Class klazz) { + try { + return UNSAFE.objectFieldOffset(klazz.getDeclaredField(field)); + } catch (NoSuchFieldException e) { + // Convert Exception to corresponding Error + NoSuchFieldError error = new NoSuchFieldError(field); + error.initCause(e); + throw error; + } + } + +} diff -r e1953d8b8338 -r c8af252ea9eb rt/emul/compact/src/main/java/java/util/concurrent/ThreadFactory.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/ThreadFactory.java Sat Mar 19 10:48:29 2016 +0100 @@ -0,0 +1,70 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +package java.util.concurrent; + +/** + * An object that creates new threads on demand. Using thread factories + * removes hardwiring of calls to {@link Thread#Thread(Runnable) new Thread}, + * enabling applications to use special thread subclasses, priorities, etc. + * + *

+ * The simplest implementation of this interface is just: + *

+ * class SimpleThreadFactory implements ThreadFactory {
+ *   public Thread newThread(Runnable r) {
+ *     return new Thread(r);
+ *   }
+ * }
+ * 
+ * + * The {@link Executors#defaultThreadFactory} method provides a more + * useful simple implementation, that sets the created thread context + * to known values before returning it. + * @since 1.5 + * @author Doug Lea + */ +public interface ThreadFactory { + + /** + * Constructs a new {@code Thread}. Implementations may also initialize + * priority, name, daemon status, {@code ThreadGroup}, etc. + * + * @param r a runnable to be executed by new thread instance + * @return constructed thread, or {@code null} if the request to + * create a thread is rejected + */ + Thread newThread(Runnable r); +} diff -r e1953d8b8338 -r c8af252ea9eb rt/emul/compact/src/main/java/java/util/concurrent/ThreadLocalRandom.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/ThreadLocalRandom.java Sat Mar 19 10:48:29 2016 +0100 @@ -0,0 +1,226 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +package java.util.concurrent; + +import java.util.Random; + +/** + * A random number generator isolated to the current thread. Like the + * global {@link java.util.Random} generator used by the {@link + * java.lang.Math} class, a {@code ThreadLocalRandom} is initialized + * with an internally generated seed that may not otherwise be + * modified. When applicable, use of {@code ThreadLocalRandom} rather + * than shared {@code Random} objects in concurrent programs will + * typically encounter much less overhead and contention. Use of + * {@code ThreadLocalRandom} is particularly appropriate when multiple + * tasks (for example, each a {@link ForkJoinTask}) use random numbers + * in parallel in thread pools. + * + *

Usages of this class should typically be of the form: + * {@code ThreadLocalRandom.current().nextX(...)} (where + * {@code X} is {@code Int}, {@code Long}, etc). + * When all usages are of this form, it is never possible to + * accidently share a {@code ThreadLocalRandom} across multiple threads. + * + *

This class also provides additional commonly used bounded random + * generation methods. + * + * @since 1.7 + * @author Doug Lea + */ +public class ThreadLocalRandom extends Random { + // same constants as Random, but must be redeclared because private + private static final long multiplier = 0x5DEECE66DL; + private static final long addend = 0xBL; + private static final long mask = (1L << 48) - 1; + + /** + * The random seed. We can't use super.seed. + */ + private long rnd; + + /** + * Initialization flag to permit calls to setSeed to succeed only + * while executing the Random constructor. We can't allow others + * since it would cause setting seed in one part of a program to + * unintentionally impact other usages by the thread. + */ + boolean initialized; + + // Padding to help avoid memory contention among seed updates in + // different TLRs in the common case that they are located near + // each other. + private long pad0, pad1, pad2, pad3, pad4, pad5, pad6, pad7; + + /** + * The actual ThreadLocal + */ + private static final ThreadLocal localRandom = + new ThreadLocal() { + protected ThreadLocalRandom initialValue() { + return new ThreadLocalRandom(); + } + }; + + + /** + * Constructor called only by localRandom.initialValue. + */ + ThreadLocalRandom() { + super(); + initialized = true; + } + + /** + * Returns the current thread's {@code ThreadLocalRandom}. + * + * @return the current thread's {@code ThreadLocalRandom} + */ + public static ThreadLocalRandom current() { + return localRandom.get(); + } + + /** + * Throws {@code UnsupportedOperationException}. Setting seeds in + * this generator is not supported. + * + * @throws UnsupportedOperationException always + */ + public void setSeed(long seed) { + if (initialized) + throw new UnsupportedOperationException(); + rnd = (seed ^ multiplier) & mask; + } + + protected int next(int bits) { + rnd = (rnd * multiplier + addend) & mask; + return (int) (rnd >>> (48-bits)); + } + + /** + * Returns a pseudorandom, uniformly distributed value between the + * given least value (inclusive) and bound (exclusive). + * + * @param least the least value returned + * @param bound the upper bound (exclusive) + * @throws IllegalArgumentException if least greater than or equal + * to bound + * @return the next value + */ + public int nextInt(int least, int bound) { + if (least >= bound) + throw new IllegalArgumentException(); + return nextInt(bound - least) + least; + } + + /** + * Returns a pseudorandom, uniformly distributed value + * between 0 (inclusive) and the specified value (exclusive). + * + * @param n the bound on the random number to be returned. Must be + * positive. + * @return the next value + * @throws IllegalArgumentException if n is not positive + */ + public long nextLong(long n) { + if (n <= 0) + throw new IllegalArgumentException("n must be positive"); + // Divide n by two until small enough for nextInt. On each + // iteration (at most 31 of them but usually much less), + // randomly choose both whether to include high bit in result + // (offset) and whether to continue with the lower vs upper + // half (which makes a difference only if odd). + long offset = 0; + while (n >= Integer.MAX_VALUE) { + int bits = next(2); + long half = n >>> 1; + long nextn = ((bits & 2) == 0) ? half : n - half; + if ((bits & 1) == 0) + offset += n - nextn; + n = nextn; + } + return offset + nextInt((int) n); + } + + /** + * Returns a pseudorandom, uniformly distributed value between the + * given least value (inclusive) and bound (exclusive). + * + * @param least the least value returned + * @param bound the upper bound (exclusive) + * @return the next value + * @throws IllegalArgumentException if least greater than or equal + * to bound + */ + public long nextLong(long least, long bound) { + if (least >= bound) + throw new IllegalArgumentException(); + return nextLong(bound - least) + least; + } + + /** + * Returns a pseudorandom, uniformly distributed {@code double} value + * between 0 (inclusive) and the specified value (exclusive). + * + * @param n the bound on the random number to be returned. Must be + * positive. + * @return the next value + * @throws IllegalArgumentException if n is not positive + */ + public double nextDouble(double n) { + if (n <= 0) + throw new IllegalArgumentException("n must be positive"); + return nextDouble() * n; + } + + /** + * Returns a pseudorandom, uniformly distributed value between the + * given least value (inclusive) and bound (exclusive). + * + * @param least the least value returned + * @param bound the upper bound (exclusive) + * @return the next value + * @throws IllegalArgumentException if least greater than or equal + * to bound + */ + public double nextDouble(double least, double bound) { + if (least >= bound) + throw new IllegalArgumentException(); + return nextDouble() * (bound - least) + least; + } + + private static final long serialVersionUID = -5851777807851030925L; +} diff -r e1953d8b8338 -r c8af252ea9eb rt/emul/compact/src/main/java/java/util/concurrent/ThreadPoolExecutor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/ThreadPoolExecutor.java Sat Mar 19 10:48:29 2016 +0100 @@ -0,0 +1,2054 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +package java.util.concurrent; +import java.util.concurrent.locks.*; +import java.util.concurrent.atomic.*; +import java.util.*; + +/** + * An {@link ExecutorService} that executes each submitted task using + * one of possibly several pooled threads, normally configured + * using {@link Executors} factory methods. + * + *

Thread pools address two different problems: they usually + * provide improved performance when executing large numbers of + * asynchronous tasks, due to reduced per-task invocation overhead, + * and they provide a means of bounding and managing the resources, + * including threads, consumed when executing a collection of tasks. + * Each {@code ThreadPoolExecutor} also maintains some basic + * statistics, such as the number of completed tasks. + * + *

To be useful across a wide range of contexts, this class + * provides many adjustable parameters and extensibility + * hooks. However, programmers are urged to use the more convenient + * {@link Executors} factory methods {@link + * Executors#newCachedThreadPool} (unbounded thread pool, with + * automatic thread reclamation), {@link Executors#newFixedThreadPool} + * (fixed size thread pool) and {@link + * Executors#newSingleThreadExecutor} (single background thread), that + * preconfigure settings for the most common usage + * scenarios. Otherwise, use the following guide when manually + * configuring and tuning this class: + * + *

+ * + *
Core and maximum pool sizes
+ * + *
A {@code ThreadPoolExecutor} will automatically adjust the + * pool size (see {@link #getPoolSize}) + * according to the bounds set by + * corePoolSize (see {@link #getCorePoolSize}) and + * maximumPoolSize (see {@link #getMaximumPoolSize}). + * + * When a new task is submitted in method {@link #execute}, and fewer + * than corePoolSize threads are running, a new thread is created to + * handle the request, even if other worker threads are idle. If + * there are more than corePoolSize but less than maximumPoolSize + * threads running, a new thread will be created only if the queue is + * full. By setting corePoolSize and maximumPoolSize the same, you + * create a fixed-size thread pool. By setting maximumPoolSize to an + * essentially unbounded value such as {@code Integer.MAX_VALUE}, you + * allow the pool to accommodate an arbitrary number of concurrent + * tasks. Most typically, core and maximum pool sizes are set only + * upon construction, but they may also be changed dynamically using + * {@link #setCorePoolSize} and {@link #setMaximumPoolSize}.
+ * + *
On-demand construction
+ * + *
By default, even core threads are initially created and + * started only when new tasks arrive, but this can be overridden + * dynamically using method {@link #prestartCoreThread} or {@link + * #prestartAllCoreThreads}. You probably want to prestart threads if + * you construct the pool with a non-empty queue.
+ * + *
Creating new threads
+ * + *
New threads are created using a {@link ThreadFactory}. If not + * otherwise specified, a {@link Executors#defaultThreadFactory} is + * used, that creates threads to all be in the same {@link + * ThreadGroup} and with the same {@code NORM_PRIORITY} priority and + * non-daemon status. By supplying a different ThreadFactory, you can + * alter the thread's name, thread group, priority, daemon status, + * etc. If a {@code ThreadFactory} fails to create a thread when asked + * by returning null from {@code newThread}, the executor will + * continue, but might not be able to execute any tasks. Threads + * should possess the "modifyThread" {@code RuntimePermission}. If + * worker threads or other threads using the pool do not possess this + * permission, service may be degraded: configuration changes may not + * take effect in a timely manner, and a shutdown pool may remain in a + * state in which termination is possible but not completed.
+ * + *
Keep-alive times
+ * + *
If the pool currently has more than corePoolSize threads, + * excess threads will be terminated if they have been idle for more + * than the keepAliveTime (see {@link #getKeepAliveTime}). This + * provides a means of reducing resource consumption when the pool is + * not being actively used. If the pool becomes more active later, new + * threads will be constructed. This parameter can also be changed + * dynamically using method {@link #setKeepAliveTime}. Using a value + * of {@code Long.MAX_VALUE} {@link TimeUnit#NANOSECONDS} effectively + * disables idle threads from ever terminating prior to shut down. By + * default, the keep-alive policy applies only when there are more + * than corePoolSizeThreads. But method {@link + * #allowCoreThreadTimeOut(boolean)} can be used to apply this + * time-out policy to core threads as well, so long as the + * keepAliveTime value is non-zero.
+ * + *
Queuing
+ * + *
Any {@link BlockingQueue} may be used to transfer and hold + * submitted tasks. The use of this queue interacts with pool sizing: + * + *
    + * + *
  • If fewer than corePoolSize threads are running, the Executor + * always prefers adding a new thread + * rather than queuing.
  • + * + *
  • If corePoolSize or more threads are running, the Executor + * always prefers queuing a request rather than adding a new + * thread.
  • + * + *
  • If a request cannot be queued, a new thread is created unless + * this would exceed maximumPoolSize, in which case, the task will be + * rejected.
  • + * + *
+ * + * There are three general strategies for queuing: + *
    + * + *
  1. Direct handoffs. A good default choice for a work + * queue is a {@link SynchronousQueue} that hands off tasks to threads + * without otherwise holding them. Here, an attempt to queue a task + * will fail if no threads are immediately available to run it, so a + * new thread will be constructed. This policy avoids lockups when + * handling sets of requests that might have internal dependencies. + * Direct handoffs generally require unbounded maximumPoolSizes to + * avoid rejection of new submitted tasks. This in turn admits the + * possibility of unbounded thread growth when commands continue to + * arrive on average faster than they can be processed.
  2. + * + *
  3. Unbounded queues. Using an unbounded queue (for + * example a {@link LinkedBlockingQueue} without a predefined + * capacity) will cause new tasks to wait in the queue when all + * corePoolSize threads are busy. Thus, no more than corePoolSize + * threads will ever be created. (And the value of the maximumPoolSize + * therefore doesn't have any effect.) This may be appropriate when + * each task is completely independent of others, so tasks cannot + * affect each others execution; for example, in a web page server. + * While this style of queuing can be useful in smoothing out + * transient bursts of requests, it admits the possibility of + * unbounded work queue growth when commands continue to arrive on + * average faster than they can be processed.
  4. + * + *
  5. Bounded queues. A bounded queue (for example, an + * {@link ArrayBlockingQueue}) helps prevent resource exhaustion when + * used with finite maximumPoolSizes, but can be more difficult to + * tune and control. Queue sizes and maximum pool sizes may be traded + * off for each other: Using large queues and small pools minimizes + * CPU usage, OS resources, and context-switching overhead, but can + * lead to artificially low throughput. If tasks frequently block (for + * example if they are I/O bound), a system may be able to schedule + * time for more threads than you otherwise allow. Use of small queues + * generally requires larger pool sizes, which keeps CPUs busier but + * may encounter unacceptable scheduling overhead, which also + * decreases throughput.
  6. + * + *
+ * + *
+ * + *
Rejected tasks
+ * + *
New tasks submitted in method {@link #execute} will be + * rejected when the Executor has been shut down, and also + * when the Executor uses finite bounds for both maximum threads and + * work queue capacity, and is saturated. In either case, the {@code + * execute} method invokes the {@link + * RejectedExecutionHandler#rejectedExecution} method of its {@link + * RejectedExecutionHandler}. Four predefined handler policies are + * provided: + * + *
    + * + *
  1. In the default {@link ThreadPoolExecutor.AbortPolicy}, the + * handler throws a runtime {@link RejectedExecutionException} upon + * rejection.
  2. + * + *
  3. In {@link ThreadPoolExecutor.CallerRunsPolicy}, the thread + * that invokes {@code execute} itself runs the task. This provides a + * simple feedback control mechanism that will slow down the rate that + * new tasks are submitted.
  4. + * + *
  5. In {@link ThreadPoolExecutor.DiscardPolicy}, a task that + * cannot be executed is simply dropped.
  6. + * + *
  7. In {@link ThreadPoolExecutor.DiscardOldestPolicy}, if the + * executor is not shut down, the task at the head of the work queue + * is dropped, and then execution is retried (which can fail again, + * causing this to be repeated.)
  8. + * + *
+ * + * It is possible to define and use other kinds of {@link + * RejectedExecutionHandler} classes. Doing so requires some care + * especially when policies are designed to work only under particular + * capacity or queuing policies.
+ * + *
Hook methods
+ * + *
This class provides {@code protected} overridable {@link + * #beforeExecute} and {@link #afterExecute} methods that are called + * before and after execution of each task. These can be used to + * manipulate the execution environment; for example, reinitializing + * ThreadLocals, gathering statistics, or adding log + * entries. Additionally, method {@link #terminated} can be overridden + * to perform any special processing that needs to be done once the + * Executor has fully terminated. + * + *

If hook or callback methods throw exceptions, internal worker + * threads may in turn fail and abruptly terminate.

+ * + *
Queue maintenance
+ * + *
Method {@link #getQueue} allows access to the work queue for + * purposes of monitoring and debugging. Use of this method for any + * other purpose is strongly discouraged. Two supplied methods, + * {@link #remove} and {@link #purge} are available to assist in + * storage reclamation when large numbers of queued tasks become + * cancelled.
+ * + *
Finalization
+ * + *
A pool that is no longer referenced in a program AND + * has no remaining threads will be {@code shutdown} automatically. If + * you would like to ensure that unreferenced pools are reclaimed even + * if users forget to call {@link #shutdown}, then you must arrange + * that unused threads eventually die, by setting appropriate + * keep-alive times, using a lower bound of zero core threads and/or + * setting {@link #allowCoreThreadTimeOut(boolean)}.
+ * + *
+ * + *

Extension example. Most extensions of this class + * override one or more of the protected hook methods. For example, + * here is a subclass that adds a simple pause/resume feature: + * + *

 {@code
+ * class PausableThreadPoolExecutor extends ThreadPoolExecutor {
+ *   private boolean isPaused;
+ *   private ReentrantLock pauseLock = new ReentrantLock();
+ *   private Condition unpaused = pauseLock.newCondition();
+ *
+ *   public PausableThreadPoolExecutor(...) { super(...); }
+ *
+ *   protected void beforeExecute(Thread t, Runnable r) {
+ *     super.beforeExecute(t, r);
+ *     pauseLock.lock();
+ *     try {
+ *       while (isPaused) unpaused.await();
+ *     } catch (InterruptedException ie) {
+ *       t.interrupt();
+ *     } finally {
+ *       pauseLock.unlock();
+ *     }
+ *   }
+ *
+ *   public void pause() {
+ *     pauseLock.lock();
+ *     try {
+ *       isPaused = true;
+ *     } finally {
+ *       pauseLock.unlock();
+ *     }
+ *   }
+ *
+ *   public void resume() {
+ *     pauseLock.lock();
+ *     try {
+ *       isPaused = false;
+ *       unpaused.signalAll();
+ *     } finally {
+ *       pauseLock.unlock();
+ *     }
+ *   }
+ * }}
+ * + * @since 1.5 + * @author Doug Lea + */ +public class ThreadPoolExecutor extends AbstractExecutorService { + /** + * The main pool control state, ctl, is an atomic integer packing + * two conceptual fields + * workerCount, indicating the effective number of threads + * runState, indicating whether running, shutting down etc + * + * In order to pack them into one int, we limit workerCount to + * (2^29)-1 (about 500 million) threads rather than (2^31)-1 (2 + * billion) otherwise representable. If this is ever an issue in + * the future, the variable can be changed to be an AtomicLong, + * and the shift/mask constants below adjusted. But until the need + * arises, this code is a bit faster and simpler using an int. + * + * The workerCount is the number of workers that have been + * permitted to start and not permitted to stop. The value may be + * transiently different from the actual number of live threads, + * for example when a ThreadFactory fails to create a thread when + * asked, and when exiting threads are still performing + * bookkeeping before terminating. The user-visible pool size is + * reported as the current size of the workers set. + * + * The runState provides the main lifecyle control, taking on values: + * + * RUNNING: Accept new tasks and process queued tasks + * SHUTDOWN: Don't accept new tasks, but process queued tasks + * STOP: Don't accept new tasks, don't process queued tasks, + * and interrupt in-progress tasks + * TIDYING: All tasks have terminated, workerCount is zero, + * the thread transitioning to state TIDYING + * will run the terminated() hook method + * TERMINATED: terminated() has completed + * + * The numerical order among these values matters, to allow + * ordered comparisons. The runState monotonically increases over + * time, but need not hit each state. The transitions are: + * + * RUNNING -> SHUTDOWN + * On invocation of shutdown(), perhaps implicitly in finalize() + * (RUNNING or SHUTDOWN) -> STOP + * On invocation of shutdownNow() + * SHUTDOWN -> TIDYING + * When both queue and pool are empty + * STOP -> TIDYING + * When pool is empty + * TIDYING -> TERMINATED + * When the terminated() hook method has completed + * + * Threads waiting in awaitTermination() will return when the + * state reaches TERMINATED. + * + * Detecting the transition from SHUTDOWN to TIDYING is less + * straightforward than you'd like because the queue may become + * empty after non-empty and vice versa during SHUTDOWN state, but + * we can only terminate if, after seeing that it is empty, we see + * that workerCount is 0 (which sometimes entails a recheck -- see + * below). + */ + private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0)); + private static final int COUNT_BITS = Integer.SIZE - 3; + private static final int CAPACITY = (1 << COUNT_BITS) - 1; + + // runState is stored in the high-order bits + private static final int RUNNING = -1 << COUNT_BITS; + private static final int SHUTDOWN = 0 << COUNT_BITS; + private static final int STOP = 1 << COUNT_BITS; + private static final int TIDYING = 2 << COUNT_BITS; + private static final int TERMINATED = 3 << COUNT_BITS; + + // Packing and unpacking ctl + private static int runStateOf(int c) { return c & ~CAPACITY; } + private static int workerCountOf(int c) { return c & CAPACITY; } + private static int ctlOf(int rs, int wc) { return rs | wc; } + + /* + * Bit field accessors that don't require unpacking ctl. + * These depend on the bit layout and on workerCount being never negative. + */ + + private static boolean runStateLessThan(int c, int s) { + return c < s; + } + + private static boolean runStateAtLeast(int c, int s) { + return c >= s; + } + + private static boolean isRunning(int c) { + return c < SHUTDOWN; + } + + /** + * Attempt to CAS-increment the workerCount field of ctl. + */ + private boolean compareAndIncrementWorkerCount(int expect) { + return ctl.compareAndSet(expect, expect + 1); + } + + /** + * Attempt to CAS-decrement the workerCount field of ctl. + */ + private boolean compareAndDecrementWorkerCount(int expect) { + return ctl.compareAndSet(expect, expect - 1); + } + + /** + * Decrements the workerCount field of ctl. This is called only on + * abrupt termination of a thread (see processWorkerExit). Other + * decrements are performed within getTask. + */ + private void decrementWorkerCount() { + do {} while (! compareAndDecrementWorkerCount(ctl.get())); + } + + /** + * The queue used for holding tasks and handing off to worker + * threads. We do not require that workQueue.poll() returning + * null necessarily means that workQueue.isEmpty(), so rely + * solely on isEmpty to see if the queue is empty (which we must + * do for example when deciding whether to transition from + * SHUTDOWN to TIDYING). This accommodates special-purpose + * queues such as DelayQueues for which poll() is allowed to + * return null even if it may later return non-null when delays + * expire. + */ + private final BlockingQueue workQueue; + + /** + * Lock held on access to workers set and related bookkeeping. + * While we could use a concurrent set of some sort, it turns out + * to be generally preferable to use a lock. Among the reasons is + * that this serializes interruptIdleWorkers, which avoids + * unnecessary interrupt storms, especially during shutdown. + * Otherwise exiting threads would concurrently interrupt those + * that have not yet interrupted. It also simplifies some of the + * associated statistics bookkeeping of largestPoolSize etc. We + * also hold mainLock on shutdown and shutdownNow, for the sake of + * ensuring workers set is stable while separately checking + * permission to interrupt and actually interrupting. + */ + private final ReentrantLock mainLock = new ReentrantLock(); + + /** + * Set containing all worker threads in pool. Accessed only when + * holding mainLock. + */ + private final HashSet workers = new HashSet(); + + /** + * Wait condition to support awaitTermination + */ + private final Condition termination = mainLock.newCondition(); + + /** + * Tracks largest attained pool size. Accessed only under + * mainLock. + */ + private int largestPoolSize; + + /** + * Counter for completed tasks. Updated only on termination of + * worker threads. Accessed only under mainLock. + */ + private long completedTaskCount; + + /* + * All user control parameters are declared as volatiles so that + * ongoing actions are based on freshest values, but without need + * for locking, since no internal invariants depend on them + * changing synchronously with respect to other actions. + */ + + /** + * Factory for new threads. All threads are created using this + * factory (via method addWorker). All callers must be prepared + * for addWorker to fail, which may reflect a system or user's + * policy limiting the number of threads. Even though it is not + * treated as an error, failure to create threads may result in + * new tasks being rejected or existing ones remaining stuck in + * the queue. On the other hand, no special precautions exist to + * handle OutOfMemoryErrors that might be thrown while trying to + * create threads, since there is generally no recourse from + * within this class. + */ + private volatile ThreadFactory threadFactory; + + /** + * Handler called when saturated or shutdown in execute. + */ + private volatile RejectedExecutionHandler handler; + + /** + * Timeout in nanoseconds for idle threads waiting for work. + * Threads use this timeout when there are more than corePoolSize + * present or if allowCoreThreadTimeOut. Otherwise they wait + * forever for new work. + */ + private volatile long keepAliveTime; + + /** + * If false (default), core threads stay alive even when idle. + * If true, core threads use keepAliveTime to time out waiting + * for work. + */ + private volatile boolean allowCoreThreadTimeOut; + + /** + * Core pool size is the minimum number of workers to keep alive + * (and not allow to time out etc) unless allowCoreThreadTimeOut + * is set, in which case the minimum is zero. + */ + private volatile int corePoolSize; + + /** + * Maximum pool size. Note that the actual maximum is internally + * bounded by CAPACITY. + */ + private volatile int maximumPoolSize; + + /** + * The default rejected execution handler + */ + private static final RejectedExecutionHandler defaultHandler = + new AbortPolicy(); + + /** + * Permission required for callers of shutdown and shutdownNow. + * We additionally require (see checkShutdownAccess) that callers + * have permission to actually interrupt threads in the worker set + * (as governed by Thread.interrupt, which relies on + * ThreadGroup.checkAccess, which in turn relies on + * SecurityManager.checkAccess). Shutdowns are attempted only if + * these checks pass. + * + * All actual invocations of Thread.interrupt (see + * interruptIdleWorkers and interruptWorkers) ignore + * SecurityExceptions, meaning that the attempted interrupts + * silently fail. In the case of shutdown, they should not fail + * unless the SecurityManager has inconsistent policies, sometimes + * allowing access to a thread and sometimes not. In such cases, + * failure to actually interrupt threads may disable or delay full + * termination. Other uses of interruptIdleWorkers are advisory, + * and failure to actually interrupt will merely delay response to + * configuration changes so is not handled exceptionally. + */ + private static final RuntimePermission shutdownPerm = + new RuntimePermission("modifyThread"); + + /** + * Class Worker mainly maintains interrupt control state for + * threads running tasks, along with other minor bookkeeping. + * This class opportunistically extends AbstractQueuedSynchronizer + * to simplify acquiring and releasing a lock surrounding each + * task execution. This protects against interrupts that are + * intended to wake up a worker thread waiting for a task from + * instead interrupting a task being run. We implement a simple + * non-reentrant mutual exclusion lock rather than use ReentrantLock + * because we do not want worker tasks to be able to reacquire the + * lock when they invoke pool control methods like setCorePoolSize. + */ + private final class Worker + extends AbstractQueuedSynchronizer + implements Runnable + { + /** + * This class will never be serialized, but we provide a + * serialVersionUID to suppress a javac warning. + */ + private static final long serialVersionUID = 6138294804551838833L; + + /** Thread this worker is running in. Null if factory fails. */ + final Thread thread; + /** Initial task to run. Possibly null. */ + Runnable firstTask; + /** Per-thread task counter */ + volatile long completedTasks; + + /** + * Creates with given first task and thread from ThreadFactory. + * @param firstTask the first task (null if none) + */ + Worker(Runnable firstTask) { + this.firstTask = firstTask; + this.thread = getThreadFactory().newThread(this); + } + + /** Delegates main run loop to outer runWorker */ + public void run() { + runWorker(this); + } + + // Lock methods + // + // The value 0 represents the unlocked state. + // The value 1 represents the locked state. + + protected boolean isHeldExclusively() { + return getState() == 1; + } + + protected boolean tryAcquire(int unused) { + if (compareAndSetState(0, 1)) { + setExclusiveOwnerThread(Thread.currentThread()); + return true; + } + return false; + } + + protected boolean tryRelease(int unused) { + setExclusiveOwnerThread(null); + setState(0); + return true; + } + + public void lock() { acquire(1); } + public boolean tryLock() { return tryAcquire(1); } + public void unlock() { release(1); } + public boolean isLocked() { return isHeldExclusively(); } + } + + /* + * Methods for setting control state + */ + + /** + * Transitions runState to given target, or leaves it alone if + * already at least the given target. + * + * @param targetState the desired state, either SHUTDOWN or STOP + * (but not TIDYING or TERMINATED -- use tryTerminate for that) + */ + private void advanceRunState(int targetState) { + for (;;) { + int c = ctl.get(); + if (runStateAtLeast(c, targetState) || + ctl.compareAndSet(c, ctlOf(targetState, workerCountOf(c)))) + break; + } + } + + /** + * Transitions to TERMINATED state if either (SHUTDOWN and pool + * and queue empty) or (STOP and pool empty). If otherwise + * eligible to terminate but workerCount is nonzero, interrupts an + * idle worker to ensure that shutdown signals propagate. This + * method must be called following any action that might make + * termination possible -- reducing worker count or removing tasks + * from the queue during shutdown. The method is non-private to + * allow access from ScheduledThreadPoolExecutor. + */ + final void tryTerminate() { + for (;;) { + int c = ctl.get(); + if (isRunning(c) || + runStateAtLeast(c, TIDYING) || + (runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty())) + return; + if (workerCountOf(c) != 0) { // Eligible to terminate + interruptIdleWorkers(ONLY_ONE); + return; + } + + final ReentrantLock mainLock = this.mainLock; + mainLock.lock(); + try { + if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) { + try { + terminated(); + } finally { + ctl.set(ctlOf(TERMINATED, 0)); + termination.signalAll(); + } + return; + } + } finally { + mainLock.unlock(); + } + // else retry on failed CAS + } + } + + /* + * Methods for controlling interrupts to worker threads. + */ + + /** + * If there is a security manager, makes sure caller has + * permission to shut down threads in general (see shutdownPerm). + * If this passes, additionally makes sure the caller is allowed + * to interrupt each worker thread. This might not be true even if + * first check passed, if the SecurityManager treats some threads + * specially. + */ + private void checkShutdownAccess() { + SecurityManager security = System.getSecurityManager(); + if (security != null) { + security.checkPermission(shutdownPerm); + final ReentrantLock mainLock = this.mainLock; + mainLock.lock(); + try { + for (Worker w : workers) + security.checkAccess(w.thread); + } finally { + mainLock.unlock(); + } + } + } + + /** + * Interrupts all threads, even if active. Ignores SecurityExceptions + * (in which case some threads may remain uninterrupted). + */ + private void interruptWorkers() { + final ReentrantLock mainLock = this.mainLock; + mainLock.lock(); + try { + for (Worker w : workers) { + try { + w.thread.interrupt(); + } catch (SecurityException ignore) { + } + } + } finally { + mainLock.unlock(); + } + } + + /** + * Interrupts threads that might be waiting for tasks (as + * indicated by not being locked) so they can check for + * termination or configuration changes. Ignores + * SecurityExceptions (in which case some threads may remain + * uninterrupted). + * + * @param onlyOne If true, interrupt at most one worker. This is + * called only from tryTerminate when termination is otherwise + * enabled but there are still other workers. In this case, at + * most one waiting worker is interrupted to propagate shutdown + * signals in case all threads are currently waiting. + * Interrupting any arbitrary thread ensures that newly arriving + * workers since shutdown began will also eventually exit. + * To guarantee eventual termination, it suffices to always + * interrupt only one idle worker, but shutdown() interrupts all + * idle workers so that redundant workers exit promptly, not + * waiting for a straggler task to finish. + */ + private void interruptIdleWorkers(boolean onlyOne) { + final ReentrantLock mainLock = this.mainLock; + mainLock.lock(); + try { + for (Worker w : workers) { + Thread t = w.thread; + if (!t.isInterrupted() && w.tryLock()) { + try { + t.interrupt(); + } catch (SecurityException ignore) { + } finally { + w.unlock(); + } + } + if (onlyOne) + break; + } + } finally { + mainLock.unlock(); + } + } + + /** + * Common form of interruptIdleWorkers, to avoid having to + * remember what the boolean argument means. + */ + private void interruptIdleWorkers() { + interruptIdleWorkers(false); + } + + private static final boolean ONLY_ONE = true; + + /** + * Ensures that unless the pool is stopping, the current thread + * does not have its interrupt set. This requires a double-check + * of state in case the interrupt was cleared concurrently with a + * shutdownNow -- if so, the interrupt is re-enabled. + */ + private void clearInterruptsForTaskRun() { + if (runStateLessThan(ctl.get(), STOP) && + Thread.interrupted() && + runStateAtLeast(ctl.get(), STOP)) + Thread.currentThread().interrupt(); + } + + /* + * Misc utilities, most of which are also exported to + * ScheduledThreadPoolExecutor + */ + + /** + * Invokes the rejected execution handler for the given command. + * Package-protected for use by ScheduledThreadPoolExecutor. + */ + final void reject(Runnable command) { + handler.rejectedExecution(command, this); + } + + /** + * Performs any further cleanup following run state transition on + * invocation of shutdown. A no-op here, but used by + * ScheduledThreadPoolExecutor to cancel delayed tasks. + */ + void onShutdown() { + } + + /** + * State check needed by ScheduledThreadPoolExecutor to + * enable running tasks during shutdown. + * + * @param shutdownOK true if should return true if SHUTDOWN + */ + final boolean isRunningOrShutdown(boolean shutdownOK) { + int rs = runStateOf(ctl.get()); + return rs == RUNNING || (rs == SHUTDOWN && shutdownOK); + } + + /** + * Drains the task queue into a new list, normally using + * drainTo. But if the queue is a DelayQueue or any other kind of + * queue for which poll or drainTo may fail to remove some + * elements, it deletes them one by one. + */ + private List drainQueue() { + BlockingQueue q = workQueue; + List taskList = new ArrayList(); + q.drainTo(taskList); + if (!q.isEmpty()) { + for (Runnable r : q.toArray(new Runnable[0])) { + if (q.remove(r)) + taskList.add(r); + } + } + return taskList; + } + + /* + * Methods for creating, running and cleaning up after workers + */ + + /** + * Checks if a new worker can be added with respect to current + * pool state and the given bound (either core or maximum). If so, + * the worker count is adjusted accordingly, and, if possible, a + * new worker is created and started running firstTask as its + * first task. This method returns false if the pool is stopped or + * eligible to shut down. It also returns false if the thread + * factory fails to create a thread when asked, which requires a + * backout of workerCount, and a recheck for termination, in case + * the existence of this worker was holding up termination. + * + * @param firstTask the task the new thread should run first (or + * null if none). Workers are created with an initial first task + * (in method execute()) to bypass queuing when there are fewer + * than corePoolSize threads (in which case we always start one), + * or when the queue is full (in which case we must bypass queue). + * Initially idle threads are usually created via + * prestartCoreThread or to replace other dying workers. + * + * @param core if true use corePoolSize as bound, else + * maximumPoolSize. (A boolean indicator is used here rather than a + * value to ensure reads of fresh values after checking other pool + * state). + * @return true if successful + */ + private boolean addWorker(Runnable firstTask, boolean core) { + retry: + for (;;) { + int c = ctl.get(); + int rs = runStateOf(c); + + // Check if queue empty only if necessary. + if (rs >= SHUTDOWN && + ! (rs == SHUTDOWN && + firstTask == null && + ! workQueue.isEmpty())) + return false; + + for (;;) { + int wc = workerCountOf(c); + if (wc >= CAPACITY || + wc >= (core ? corePoolSize : maximumPoolSize)) + return false; + if (compareAndIncrementWorkerCount(c)) + break retry; + c = ctl.get(); // Re-read ctl + if (runStateOf(c) != rs) + continue retry; + // else CAS failed due to workerCount change; retry inner loop + } + } + + Worker w = new Worker(firstTask); + Thread t = w.thread; + + final ReentrantLock mainLock = this.mainLock; + mainLock.lock(); + try { + // Recheck while holding lock. + // Back out on ThreadFactory failure or if + // shut down before lock acquired. + int c = ctl.get(); + int rs = runStateOf(c); + + if (t == null || + (rs >= SHUTDOWN && + ! (rs == SHUTDOWN && + firstTask == null))) { + decrementWorkerCount(); + tryTerminate(); + return false; + } + + workers.add(w); + + int s = workers.size(); + if (s > largestPoolSize) + largestPoolSize = s; + } finally { + mainLock.unlock(); + } + + t.start(); + // It is possible (but unlikely) for a thread to have been + // added to workers, but not yet started, during transition to + // STOP, which could result in a rare missed interrupt, + // because Thread.interrupt is not guaranteed to have any effect + // on a non-yet-started Thread (see Thread#interrupt). + if (runStateOf(ctl.get()) == STOP && ! t.isInterrupted()) + t.interrupt(); + + return true; + } + + /** + * Performs cleanup and bookkeeping for a dying worker. Called + * only from worker threads. Unless completedAbruptly is set, + * assumes that workerCount has already been adjusted to account + * for exit. This method removes thread from worker set, and + * possibly terminates the pool or replaces the worker if either + * it exited due to user task exception or if fewer than + * corePoolSize workers are running or queue is non-empty but + * there are no workers. + * + * @param w the worker + * @param completedAbruptly if the worker died due to user exception + */ + private void processWorkerExit(Worker w, boolean completedAbruptly) { + if (completedAbruptly) // If abrupt, then workerCount wasn't adjusted + decrementWorkerCount(); + + final ReentrantLock mainLock = this.mainLock; + mainLock.lock(); + try { + completedTaskCount += w.completedTasks; + workers.remove(w); + } finally { + mainLock.unlock(); + } + + tryTerminate(); + + int c = ctl.get(); + if (runStateLessThan(c, STOP)) { + if (!completedAbruptly) { + int min = allowCoreThreadTimeOut ? 0 : corePoolSize; + if (min == 0 && ! workQueue.isEmpty()) + min = 1; + if (workerCountOf(c) >= min) + return; // replacement not needed + } + addWorker(null, false); + } + } + + /** + * Performs blocking or timed wait for a task, depending on + * current configuration settings, or returns null if this worker + * must exit because of any of: + * 1. There are more than maximumPoolSize workers (due to + * a call to setMaximumPoolSize). + * 2. The pool is stopped. + * 3. The pool is shutdown and the queue is empty. + * 4. This worker timed out waiting for a task, and timed-out + * workers are subject to termination (that is, + * {@code allowCoreThreadTimeOut || workerCount > corePoolSize}) + * both before and after the timed wait. + * + * @return task, or null if the worker must exit, in which case + * workerCount is decremented + */ + private Runnable getTask() { + boolean timedOut = false; // Did the last poll() time out? + + retry: + for (;;) { + int c = ctl.get(); + int rs = runStateOf(c); + + // Check if queue empty only if necessary. + if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) { + decrementWorkerCount(); + return null; + } + + boolean timed; // Are workers subject to culling? + + for (;;) { + int wc = workerCountOf(c); + timed = allowCoreThreadTimeOut || wc > corePoolSize; + + if (wc <= maximumPoolSize && ! (timedOut && timed)) + break; + if (compareAndDecrementWorkerCount(c)) + return null; + c = ctl.get(); // Re-read ctl + if (runStateOf(c) != rs) + continue retry; + // else CAS failed due to workerCount change; retry inner loop + } + + try { + Runnable r = timed ? + workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) : + workQueue.take(); + if (r != null) + return r; + timedOut = true; + } catch (InterruptedException retry) { + timedOut = false; + } + } + } + + /** + * Main worker run loop. Repeatedly gets tasks from queue and + * executes them, while coping with a number of issues: + * + * 1. We may start out with an initial task, in which case we + * don't need to get the first one. Otherwise, as long as pool is + * running, we get tasks from getTask. If it returns null then the + * worker exits due to changed pool state or configuration + * parameters. Other exits result from exception throws in + * external code, in which case completedAbruptly holds, which + * usually leads processWorkerExit to replace this thread. + * + * 2. Before running any task, the lock is acquired to prevent + * other pool interrupts while the task is executing, and + * clearInterruptsForTaskRun called to ensure that unless pool is + * stopping, this thread does not have its interrupt set. + * + * 3. Each task run is preceded by a call to beforeExecute, which + * might throw an exception, in which case we cause thread to die + * (breaking loop with completedAbruptly true) without processing + * the task. + * + * 4. Assuming beforeExecute completes normally, we run the task, + * gathering any of its thrown exceptions to send to + * afterExecute. We separately handle RuntimeException, Error + * (both of which the specs guarantee that we trap) and arbitrary + * Throwables. Because we cannot rethrow Throwables within + * Runnable.run, we wrap them within Errors on the way out (to the + * thread's UncaughtExceptionHandler). Any thrown exception also + * conservatively causes thread to die. + * + * 5. After task.run completes, we call afterExecute, which may + * also throw an exception, which will also cause thread to + * die. According to JLS Sec 14.20, this exception is the one that + * will be in effect even if task.run throws. + * + * The net effect of the exception mechanics is that afterExecute + * and the thread's UncaughtExceptionHandler have as accurate + * information as we can provide about any problems encountered by + * user code. + * + * @param w the worker + */ + final void runWorker(Worker w) { + Runnable task = w.firstTask; + w.firstTask = null; + boolean completedAbruptly = true; + try { + while (task != null || (task = getTask()) != null) { + w.lock(); + clearInterruptsForTaskRun(); + try { + beforeExecute(w.thread, task); + Throwable thrown = null; + try { + task.run(); + } catch (RuntimeException x) { + thrown = x; throw x; + } catch (Error x) { + thrown = x; throw x; + } catch (Throwable x) { + thrown = x; throw new Error(x); + } finally { + afterExecute(task, thrown); + } + } finally { + task = null; + w.completedTasks++; + w.unlock(); + } + } + completedAbruptly = false; + } finally { + processWorkerExit(w, completedAbruptly); + } + } + + // Public constructors and methods + + /** + * Creates a new {@code ThreadPoolExecutor} with the given initial + * parameters and default thread factory and rejected execution handler. + * It may be more convenient to use one of the {@link Executors} factory + * methods instead of this general purpose constructor. + * + * @param corePoolSize the number of threads to keep in the pool, even + * if they are idle, unless {@code allowCoreThreadTimeOut} is set + * @param maximumPoolSize the maximum number of threads to allow in the + * pool + * @param keepAliveTime when the number of threads is greater than + * the core, this is the maximum time that excess idle threads + * will wait for new tasks before terminating. + * @param unit the time unit for the {@code keepAliveTime} argument + * @param workQueue the queue to use for holding tasks before they are + * executed. This queue will hold only the {@code Runnable} + * tasks submitted by the {@code execute} method. + * @throws IllegalArgumentException if one of the following holds:
+ * {@code corePoolSize < 0}
+ * {@code keepAliveTime < 0}
+ * {@code maximumPoolSize <= 0}
+ * {@code maximumPoolSize < corePoolSize} + * @throws NullPointerException if {@code workQueue} is null + */ + public ThreadPoolExecutor(int corePoolSize, + int maximumPoolSize, + long keepAliveTime, + TimeUnit unit, + BlockingQueue workQueue) { + this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, + Executors.defaultThreadFactory(), defaultHandler); + } + + /** + * Creates a new {@code ThreadPoolExecutor} with the given initial + * parameters and default rejected execution handler. + * + * @param corePoolSize the number of threads to keep in the pool, even + * if they are idle, unless {@code allowCoreThreadTimeOut} is set + * @param maximumPoolSize the maximum number of threads to allow in the + * pool + * @param keepAliveTime when the number of threads is greater than + * the core, this is the maximum time that excess idle threads + * will wait for new tasks before terminating. + * @param unit the time unit for the {@code keepAliveTime} argument + * @param workQueue the queue to use for holding tasks before they are + * executed. This queue will hold only the {@code Runnable} + * tasks submitted by the {@code execute} method. + * @param threadFactory the factory to use when the executor + * creates a new thread + * @throws IllegalArgumentException if one of the following holds:
+ * {@code corePoolSize < 0}
+ * {@code keepAliveTime < 0}
+ * {@code maximumPoolSize <= 0}
+ * {@code maximumPoolSize < corePoolSize} + * @throws NullPointerException if {@code workQueue} + * or {@code threadFactory} is null + */ + public ThreadPoolExecutor(int corePoolSize, + int maximumPoolSize, + long keepAliveTime, + TimeUnit unit, + BlockingQueue workQueue, + ThreadFactory threadFactory) { + this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, + threadFactory, defaultHandler); + } + + /** + * Creates a new {@code ThreadPoolExecutor} with the given initial + * parameters and default thread factory. + * + * @param corePoolSize the number of threads to keep in the pool, even + * if they are idle, unless {@code allowCoreThreadTimeOut} is set + * @param maximumPoolSize the maximum number of threads to allow in the + * pool + * @param keepAliveTime when the number of threads is greater than + * the core, this is the maximum time that excess idle threads + * will wait for new tasks before terminating. + * @param unit the time unit for the {@code keepAliveTime} argument + * @param workQueue the queue to use for holding tasks before they are + * executed. This queue will hold only the {@code Runnable} + * tasks submitted by the {@code execute} method. + * @param handler the handler to use when execution is blocked + * because the thread bounds and queue capacities are reached + * @throws IllegalArgumentException if one of the following holds:
+ * {@code corePoolSize < 0}
+ * {@code keepAliveTime < 0}
+ * {@code maximumPoolSize <= 0}
+ * {@code maximumPoolSize < corePoolSize} + * @throws NullPointerException if {@code workQueue} + * or {@code handler} is null + */ + public ThreadPoolExecutor(int corePoolSize, + int maximumPoolSize, + long keepAliveTime, + TimeUnit unit, + BlockingQueue workQueue, + RejectedExecutionHandler handler) { + this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, + Executors.defaultThreadFactory(), handler); + } + + /** + * Creates a new {@code ThreadPoolExecutor} with the given initial + * parameters. + * + * @param corePoolSize the number of threads to keep in the pool, even + * if they are idle, unless {@code allowCoreThreadTimeOut} is set + * @param maximumPoolSize the maximum number of threads to allow in the + * pool + * @param keepAliveTime when the number of threads is greater than + * the core, this is the maximum time that excess idle threads + * will wait for new tasks before terminating. + * @param unit the time unit for the {@code keepAliveTime} argument + * @param workQueue the queue to use for holding tasks before they are + * executed. This queue will hold only the {@code Runnable} + * tasks submitted by the {@code execute} method. + * @param threadFactory the factory to use when the executor + * creates a new thread + * @param handler the handler to use when execution is blocked + * because the thread bounds and queue capacities are reached + * @throws IllegalArgumentException if one of the following holds:
+ * {@code corePoolSize < 0}
+ * {@code keepAliveTime < 0}
+ * {@code maximumPoolSize <= 0}
+ * {@code maximumPoolSize < corePoolSize} + * @throws NullPointerException if {@code workQueue} + * or {@code threadFactory} or {@code handler} is null + */ + public ThreadPoolExecutor(int corePoolSize, + int maximumPoolSize, + long keepAliveTime, + TimeUnit unit, + BlockingQueue workQueue, + ThreadFactory threadFactory, + RejectedExecutionHandler handler) { + if (corePoolSize < 0 || + maximumPoolSize <= 0 || + maximumPoolSize < corePoolSize || + keepAliveTime < 0) + throw new IllegalArgumentException(); + if (workQueue == null || threadFactory == null || handler == null) + throw new NullPointerException(); + this.corePoolSize = corePoolSize; + this.maximumPoolSize = maximumPoolSize; + this.workQueue = workQueue; + this.keepAliveTime = unit.toNanos(keepAliveTime); + this.threadFactory = threadFactory; + this.handler = handler; + } + + /** + * Executes the given task sometime in the future. The task + * may execute in a new thread or in an existing pooled thread. + * + * If the task cannot be submitted for execution, either because this + * executor has been shutdown or because its capacity has been reached, + * the task is handled by the current {@code RejectedExecutionHandler}. + * + * @param command the task to execute + * @throws RejectedExecutionException at discretion of + * {@code RejectedExecutionHandler}, if the task + * cannot be accepted for execution + * @throws NullPointerException if {@code command} is null + */ + public void execute(Runnable command) { + if (command == null) + throw new NullPointerException(); + /* + * Proceed in 3 steps: + * + * 1. If fewer than corePoolSize threads are running, try to + * start a new thread with the given command as its first + * task. The call to addWorker atomically checks runState and + * workerCount, and so prevents false alarms that would add + * threads when it shouldn't, by returning false. + * + * 2. If a task can be successfully queued, then we still need + * to double-check whether we should have added a thread + * (because existing ones died since last checking) or that + * the pool shut down since entry into this method. So we + * recheck state and if necessary roll back the enqueuing if + * stopped, or start a new thread if there are none. + * + * 3. If we cannot queue task, then we try to add a new + * thread. If it fails, we know we are shut down or saturated + * and so reject the task. + */ + int c = ctl.get(); + if (workerCountOf(c) < corePoolSize) { + if (addWorker(command, true)) + return; + c = ctl.get(); + } + if (isRunning(c) && workQueue.offer(command)) { + int recheck = ctl.get(); + if (! isRunning(recheck) && remove(command)) + reject(command); + else if (workerCountOf(recheck) == 0) + addWorker(null, false); + } + else if (!addWorker(command, false)) + reject(command); + } + + /** + * Initiates an orderly shutdown in which previously submitted + * tasks are executed, but no new tasks will be accepted. + * Invocation has no additional effect if already shut down. + * + *

This method does not wait for previously submitted tasks to + * complete execution. Use {@link #awaitTermination awaitTermination} + * to do that. + * + * @throws SecurityException {@inheritDoc} + */ + public void shutdown() { + final ReentrantLock mainLock = this.mainLock; + mainLock.lock(); + try { + checkShutdownAccess(); + advanceRunState(SHUTDOWN); + interruptIdleWorkers(); + onShutdown(); // hook for ScheduledThreadPoolExecutor + } finally { + mainLock.unlock(); + } + tryTerminate(); + } + + /** + * Attempts to stop all actively executing tasks, halts the + * processing of waiting tasks, and returns a list of the tasks + * that were awaiting execution. These tasks are drained (removed) + * from the task queue upon return from this method. + * + *

This method does not wait for actively executing tasks to + * terminate. Use {@link #awaitTermination awaitTermination} to + * do that. + * + *

There are no guarantees beyond best-effort attempts to stop + * processing actively executing tasks. This implementation + * cancels tasks via {@link Thread#interrupt}, so any task that + * fails to respond to interrupts may never terminate. + * + * @throws SecurityException {@inheritDoc} + */ + public List shutdownNow() { + List tasks; + final ReentrantLock mainLock = this.mainLock; + mainLock.lock(); + try { + checkShutdownAccess(); + advanceRunState(STOP); + interruptWorkers(); + tasks = drainQueue(); + } finally { + mainLock.unlock(); + } + tryTerminate(); + return tasks; + } + + public boolean isShutdown() { + return ! isRunning(ctl.get()); + } + + /** + * Returns true if this executor is in the process of terminating + * after {@link #shutdown} or {@link #shutdownNow} but has not + * completely terminated. This method may be useful for + * debugging. A return of {@code true} reported a sufficient + * period after shutdown may indicate that submitted tasks have + * ignored or suppressed interruption, causing this executor not + * to properly terminate. + * + * @return true if terminating but not yet terminated + */ + public boolean isTerminating() { + int c = ctl.get(); + return ! isRunning(c) && runStateLessThan(c, TERMINATED); + } + + public boolean isTerminated() { + return runStateAtLeast(ctl.get(), TERMINATED); + } + + public boolean awaitTermination(long timeout, TimeUnit unit) + throws InterruptedException { + long nanos = unit.toNanos(timeout); + final ReentrantLock mainLock = this.mainLock; + mainLock.lock(); + try { + for (;;) { + if (runStateAtLeast(ctl.get(), TERMINATED)) + return true; + if (nanos <= 0) + return false; + nanos = termination.awaitNanos(nanos); + } + } finally { + mainLock.unlock(); + } + } + + /** + * Invokes {@code shutdown} when this executor is no longer + * referenced and it has no threads. + */ + protected void finalize() { + shutdown(); + } + + /** + * Sets the thread factory used to create new threads. + * + * @param threadFactory the new thread factory + * @throws NullPointerException if threadFactory is null + * @see #getThreadFactory + */ + public void setThreadFactory(ThreadFactory threadFactory) { + if (threadFactory == null) + throw new NullPointerException(); + this.threadFactory = threadFactory; + } + + /** + * Returns the thread factory used to create new threads. + * + * @return the current thread factory + * @see #setThreadFactory + */ + public ThreadFactory getThreadFactory() { + return threadFactory; + } + + /** + * Sets a new handler for unexecutable tasks. + * + * @param handler the new handler + * @throws NullPointerException if handler is null + * @see #getRejectedExecutionHandler + */ + public void setRejectedExecutionHandler(RejectedExecutionHandler handler) { + if (handler == null) + throw new NullPointerException(); + this.handler = handler; + } + + /** + * Returns the current handler for unexecutable tasks. + * + * @return the current handler + * @see #setRejectedExecutionHandler + */ + public RejectedExecutionHandler getRejectedExecutionHandler() { + return handler; + } + + /** + * Sets the core number of threads. This overrides any value set + * in the constructor. If the new value is smaller than the + * current value, excess existing threads will be terminated when + * they next become idle. If larger, new threads will, if needed, + * be started to execute any queued tasks. + * + * @param corePoolSize the new core size + * @throws IllegalArgumentException if {@code corePoolSize < 0} + * @see #getCorePoolSize + */ + public void setCorePoolSize(int corePoolSize) { + if (corePoolSize < 0) + throw new IllegalArgumentException(); + int delta = corePoolSize - this.corePoolSize; + this.corePoolSize = corePoolSize; + if (workerCountOf(ctl.get()) > corePoolSize) + interruptIdleWorkers(); + else if (delta > 0) { + // We don't really know how many new threads are "needed". + // As a heuristic, prestart enough new workers (up to new + // core size) to handle the current number of tasks in + // queue, but stop if queue becomes empty while doing so. + int k = Math.min(delta, workQueue.size()); + while (k-- > 0 && addWorker(null, true)) { + if (workQueue.isEmpty()) + break; + } + } + } + + /** + * Returns the core number of threads. + * + * @return the core number of threads + * @see #setCorePoolSize + */ + public int getCorePoolSize() { + return corePoolSize; + } + + /** + * Starts a core thread, causing it to idly wait for work. This + * overrides the default policy of starting core threads only when + * new tasks are executed. This method will return {@code false} + * if all core threads have already been started. + * + * @return {@code true} if a thread was started + */ + public boolean prestartCoreThread() { + return workerCountOf(ctl.get()) < corePoolSize && + addWorker(null, true); + } + + /** + * Starts all core threads, causing them to idly wait for work. This + * overrides the default policy of starting core threads only when + * new tasks are executed. + * + * @return the number of threads started + */ + public int prestartAllCoreThreads() { + int n = 0; + while (addWorker(null, true)) + ++n; + return n; + } + + /** + * Returns true if this pool allows core threads to time out and + * terminate if no tasks arrive within the keepAlive time, being + * replaced if needed when new tasks arrive. When true, the same + * keep-alive policy applying to non-core threads applies also to + * core threads. When false (the default), core threads are never + * terminated due to lack of incoming tasks. + * + * @return {@code true} if core threads are allowed to time out, + * else {@code false} + * + * @since 1.6 + */ + public boolean allowsCoreThreadTimeOut() { + return allowCoreThreadTimeOut; + } + + /** + * Sets the policy governing whether core threads may time out and + * terminate if no tasks arrive within the keep-alive time, being + * replaced if needed when new tasks arrive. When false, core + * threads are never terminated due to lack of incoming + * tasks. When true, the same keep-alive policy applying to + * non-core threads applies also to core threads. To avoid + * continual thread replacement, the keep-alive time must be + * greater than zero when setting {@code true}. This method + * should in general be called before the pool is actively used. + * + * @param value {@code true} if should time out, else {@code false} + * @throws IllegalArgumentException if value is {@code true} + * and the current keep-alive time is not greater than zero + * + * @since 1.6 + */ + public void allowCoreThreadTimeOut(boolean value) { + if (value && keepAliveTime <= 0) + throw new IllegalArgumentException("Core threads must have nonzero keep alive times"); + if (value != allowCoreThreadTimeOut) { + allowCoreThreadTimeOut = value; + if (value) + interruptIdleWorkers(); + } + } + + /** + * Sets the maximum allowed number of threads. This overrides any + * value set in the constructor. If the new value is smaller than + * the current value, excess existing threads will be + * terminated when they next become idle. + * + * @param maximumPoolSize the new maximum + * @throws IllegalArgumentException if the new maximum is + * less than or equal to zero, or + * less than the {@linkplain #getCorePoolSize core pool size} + * @see #getMaximumPoolSize + */ + public void setMaximumPoolSize(int maximumPoolSize) { + if (maximumPoolSize <= 0 || maximumPoolSize < corePoolSize) + throw new IllegalArgumentException(); + this.maximumPoolSize = maximumPoolSize; + if (workerCountOf(ctl.get()) > maximumPoolSize) + interruptIdleWorkers(); + } + + /** + * Returns the maximum allowed number of threads. + * + * @return the maximum allowed number of threads + * @see #setMaximumPoolSize + */ + public int getMaximumPoolSize() { + return maximumPoolSize; + } + + /** + * Sets the time limit for which threads may remain idle before + * being terminated. If there are more than the core number of + * threads currently in the pool, after waiting this amount of + * time without processing a task, excess threads will be + * terminated. This overrides any value set in the constructor. + * + * @param time the time to wait. A time value of zero will cause + * excess threads to terminate immediately after executing tasks. + * @param unit the time unit of the {@code time} argument + * @throws IllegalArgumentException if {@code time} less than zero or + * if {@code time} is zero and {@code allowsCoreThreadTimeOut} + * @see #getKeepAliveTime + */ + public void setKeepAliveTime(long time, TimeUnit unit) { + if (time < 0) + throw new IllegalArgumentException(); + if (time == 0 && allowsCoreThreadTimeOut()) + throw new IllegalArgumentException("Core threads must have nonzero keep alive times"); + long keepAliveTime = unit.toNanos(time); + long delta = keepAliveTime - this.keepAliveTime; + this.keepAliveTime = keepAliveTime; + if (delta < 0) + interruptIdleWorkers(); + } + + /** + * Returns the thread keep-alive time, which is the amount of time + * that threads in excess of the core pool size may remain + * idle before being terminated. + * + * @param unit the desired time unit of the result + * @return the time limit + * @see #setKeepAliveTime + */ + public long getKeepAliveTime(TimeUnit unit) { + return unit.convert(keepAliveTime, TimeUnit.NANOSECONDS); + } + + /* User-level queue utilities */ + + /** + * Returns the task queue used by this executor. Access to the + * task queue is intended primarily for debugging and monitoring. + * This queue may be in active use. Retrieving the task queue + * does not prevent queued tasks from executing. + * + * @return the task queue + */ + public BlockingQueue getQueue() { + return workQueue; + } + + /** + * Removes this task from the executor's internal queue if it is + * present, thus causing it not to be run if it has not already + * started. + * + *

This method may be useful as one part of a cancellation + * scheme. It may fail to remove tasks that have been converted + * into other forms before being placed on the internal queue. For + * example, a task entered using {@code submit} might be + * converted into a form that maintains {@code Future} status. + * However, in such cases, method {@link #purge} may be used to + * remove those Futures that have been cancelled. + * + * @param task the task to remove + * @return true if the task was removed + */ + public boolean remove(Runnable task) { + boolean removed = workQueue.remove(task); + tryTerminate(); // In case SHUTDOWN and now empty + return removed; + } + + /** + * Tries to remove from the work queue all {@link Future} + * tasks that have been cancelled. This method can be useful as a + * storage reclamation operation, that has no other impact on + * functionality. Cancelled tasks are never executed, but may + * accumulate in work queues until worker threads can actively + * remove them. Invoking this method instead tries to remove them now. + * However, this method may fail to remove tasks in + * the presence of interference by other threads. + */ + public void purge() { + final BlockingQueue q = workQueue; + try { + Iterator it = q.iterator(); + while (it.hasNext()) { + Runnable r = it.next(); + if (r instanceof Future && ((Future)r).isCancelled()) + it.remove(); + } + } catch (ConcurrentModificationException fallThrough) { + // Take slow path if we encounter interference during traversal. + // Make copy for traversal and call remove for cancelled entries. + // The slow path is more likely to be O(N*N). + for (Object r : q.toArray()) + if (r instanceof Future && ((Future)r).isCancelled()) + q.remove(r); + } + + tryTerminate(); // In case SHUTDOWN and now empty + } + + /* Statistics */ + + /** + * Returns the current number of threads in the pool. + * + * @return the number of threads + */ + public int getPoolSize() { + final ReentrantLock mainLock = this.mainLock; + mainLock.lock(); + try { + // Remove rare and surprising possibility of + // isTerminated() && getPoolSize() > 0 + return runStateAtLeast(ctl.get(), TIDYING) ? 0 + : workers.size(); + } finally { + mainLock.unlock(); + } + } + + /** + * Returns the approximate number of threads that are actively + * executing tasks. + * + * @return the number of threads + */ + public int getActiveCount() { + final ReentrantLock mainLock = this.mainLock; + mainLock.lock(); + try { + int n = 0; + for (Worker w : workers) + if (w.isLocked()) + ++n; + return n; + } finally { + mainLock.unlock(); + } + } + + /** + * Returns the largest number of threads that have ever + * simultaneously been in the pool. + * + * @return the number of threads + */ + public int getLargestPoolSize() { + final ReentrantLock mainLock = this.mainLock; + mainLock.lock(); + try { + return largestPoolSize; + } finally { + mainLock.unlock(); + } + } + + /** + * Returns the approximate total number of tasks that have ever been + * scheduled for execution. Because the states of tasks and + * threads may change dynamically during computation, the returned + * value is only an approximation. + * + * @return the number of tasks + */ + public long getTaskCount() { + final ReentrantLock mainLock = this.mainLock; + mainLock.lock(); + try { + long n = completedTaskCount; + for (Worker w : workers) { + n += w.completedTasks; + if (w.isLocked()) + ++n; + } + return n + workQueue.size(); + } finally { + mainLock.unlock(); + } + } + + /** + * Returns the approximate total number of tasks that have + * completed execution. Because the states of tasks and threads + * may change dynamically during computation, the returned value + * is only an approximation, but one that does not ever decrease + * across successive calls. + * + * @return the number of tasks + */ + public long getCompletedTaskCount() { + final ReentrantLock mainLock = this.mainLock; + mainLock.lock(); + try { + long n = completedTaskCount; + for (Worker w : workers) + n += w.completedTasks; + return n; + } finally { + mainLock.unlock(); + } + } + + /** + * Returns a string identifying this pool, as well as its state, + * including indications of run state and estimated worker and + * task counts. + * + * @return a string identifying this pool, as well as its state + */ + public String toString() { + long ncompleted; + int nworkers, nactive; + final ReentrantLock mainLock = this.mainLock; + mainLock.lock(); + try { + ncompleted = completedTaskCount; + nactive = 0; + nworkers = workers.size(); + for (Worker w : workers) { + ncompleted += w.completedTasks; + if (w.isLocked()) + ++nactive; + } + } finally { + mainLock.unlock(); + } + int c = ctl.get(); + String rs = (runStateLessThan(c, SHUTDOWN) ? "Running" : + (runStateAtLeast(c, TERMINATED) ? "Terminated" : + "Shutting down")); + return super.toString() + + "[" + rs + + ", pool size = " + nworkers + + ", active threads = " + nactive + + ", queued tasks = " + workQueue.size() + + ", completed tasks = " + ncompleted + + "]"; + } + + /* Extension hooks */ + + /** + * Method invoked prior to executing the given Runnable in the + * given thread. This method is invoked by thread {@code t} that + * will execute task {@code r}, and may be used to re-initialize + * ThreadLocals, or to perform logging. + * + *

This implementation does nothing, but may be customized in + * subclasses. Note: To properly nest multiple overridings, subclasses + * should generally invoke {@code super.beforeExecute} at the end of + * this method. + * + * @param t the thread that will run task {@code r} + * @param r the task that will be executed + */ + protected void beforeExecute(Thread t, Runnable r) { } + + /** + * Method invoked upon completion of execution of the given Runnable. + * This method is invoked by the thread that executed the task. If + * non-null, the Throwable is the uncaught {@code RuntimeException} + * or {@code Error} that caused execution to terminate abruptly. + * + *

This implementation does nothing, but may be customized in + * subclasses. Note: To properly nest multiple overridings, subclasses + * should generally invoke {@code super.afterExecute} at the + * beginning of this method. + * + *

Note: When actions are enclosed in tasks (such as + * {@link FutureTask}) either explicitly or via methods such as + * {@code submit}, these task objects catch and maintain + * computational exceptions, and so they do not cause abrupt + * termination, and the internal exceptions are not + * passed to this method. If you would like to trap both kinds of + * failures in this method, you can further probe for such cases, + * as in this sample subclass that prints either the direct cause + * or the underlying exception if a task has been aborted: + * + *

 {@code
+     * class ExtendedExecutor extends ThreadPoolExecutor {
+     *   // ...
+     *   protected void afterExecute(Runnable r, Throwable t) {
+     *     super.afterExecute(r, t);
+     *     if (t == null && r instanceof Future) {
+     *       try {
+     *         Object result = ((Future) r).get();
+     *       } catch (CancellationException ce) {
+     *           t = ce;
+     *       } catch (ExecutionException ee) {
+     *           t = ee.getCause();
+     *       } catch (InterruptedException ie) {
+     *           Thread.currentThread().interrupt(); // ignore/reset
+     *       }
+     *     }
+     *     if (t != null)
+     *       System.out.println(t);
+     *   }
+     * }}
+ * + * @param r the runnable that has completed + * @param t the exception that caused termination, or null if + * execution completed normally + */ + protected void afterExecute(Runnable r, Throwable t) { } + + /** + * Method invoked when the Executor has terminated. Default + * implementation does nothing. Note: To properly nest multiple + * overridings, subclasses should generally invoke + * {@code super.terminated} within this method. + */ + protected void terminated() { } + + /* Predefined RejectedExecutionHandlers */ + + /** + * A handler for rejected tasks that runs the rejected task + * directly in the calling thread of the {@code execute} method, + * unless the executor has been shut down, in which case the task + * is discarded. + */ + public static class CallerRunsPolicy implements RejectedExecutionHandler { + /** + * Creates a {@code CallerRunsPolicy}. + */ + public CallerRunsPolicy() { } + + /** + * Executes task r in the caller's thread, unless the executor + * has been shut down, in which case the task is discarded. + * + * @param r the runnable task requested to be executed + * @param e the executor attempting to execute this task + */ + public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { + if (!e.isShutdown()) { + r.run(); + } + } + } + + /** + * A handler for rejected tasks that throws a + * {@code RejectedExecutionException}. + */ + public static class AbortPolicy implements RejectedExecutionHandler { + /** + * Creates an {@code AbortPolicy}. + */ + public AbortPolicy() { } + + /** + * Always throws RejectedExecutionException. + * + * @param r the runnable task requested to be executed + * @param e the executor attempting to execute this task + * @throws RejectedExecutionException always. + */ + public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { + throw new RejectedExecutionException("Task " + r.toString() + + " rejected from " + + e.toString()); + } + } + + /** + * A handler for rejected tasks that silently discards the + * rejected task. + */ + public static class DiscardPolicy implements RejectedExecutionHandler { + /** + * Creates a {@code DiscardPolicy}. + */ + public DiscardPolicy() { } + + /** + * Does nothing, which has the effect of discarding task r. + * + * @param r the runnable task requested to be executed + * @param e the executor attempting to execute this task + */ + public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { + } + } + + /** + * A handler for rejected tasks that discards the oldest unhandled + * request and then retries {@code execute}, unless the executor + * is shut down, in which case the task is discarded. + */ + public static class DiscardOldestPolicy implements RejectedExecutionHandler { + /** + * Creates a {@code DiscardOldestPolicy} for the given executor. + */ + public DiscardOldestPolicy() { } + + /** + * Obtains and ignores the next task that the executor + * would otherwise execute, if one is immediately available, + * and then retries execution of task r, unless the executor + * is shut down, in which case task r is instead discarded. + * + * @param r the runnable task requested to be executed + * @param e the executor attempting to execute this task + */ + public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { + if (!e.isShutdown()) { + e.getQueue().poll(); + e.execute(r); + } + } + } +} diff -r e1953d8b8338 -r c8af252ea9eb rt/emul/compact/src/main/java/java/util/concurrent/TimeUnit.java --- a/rt/emul/compact/src/main/java/java/util/concurrent/TimeUnit.java Sat Mar 19 10:31:13 2016 +0100 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/TimeUnit.java Sat Mar 19 10:48:29 2016 +0100 @@ -357,11 +357,11 @@ if (timeout > 0) { long ms = toMillis(timeout); int ns = excessNanos(timeout, ms); - Object o = new Object(); - synchronized (o) { - o.wait(ms, ns); - } + Thread.sleep(ms, ns); } } } + } + +} diff -r e1953d8b8338 -r c8af252ea9eb rt/emul/compact/src/main/java/java/util/concurrent/TimeoutException.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/TimeoutException.java Sat Mar 19 10:48:29 2016 +0100 @@ -0,0 +1,67 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +package java.util.concurrent; + +/** + * Exception thrown when a blocking operation times out. Blocking + * operations for which a timeout is specified need a means to + * indicate that the timeout has occurred. For many such operations it + * is possible to return a value that indicates timeout; when that is + * not possible or desirable then TimeoutException should be + * declared and thrown. + * + * @since 1.5 + * @author Doug Lea + */ +public class TimeoutException extends Exception { + private static final long serialVersionUID = 1900926677490660714L; + + /** + * Constructs a TimeoutException with no specified detail + * message. + */ + public TimeoutException() {} + + /** + * Constructs a TimeoutException with the specified detail + * message. + * + * @param message the detail message + */ + public TimeoutException(String message) { + super(message); + } +} diff -r e1953d8b8338 -r c8af252ea9eb rt/emul/compact/src/main/java/java/util/concurrent/TransferQueue.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/TransferQueue.java Sat Mar 19 10:48:29 2016 +0100 @@ -0,0 +1,161 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +package java.util.concurrent; + +/** + * A {@link BlockingQueue} in which producers may wait for consumers + * to receive elements. A {@code TransferQueue} may be useful for + * example in message passing applications in which producers + * sometimes (using method {@link #transfer}) await receipt of + * elements by consumers invoking {@code take} or {@code poll}, while + * at other times enqueue elements (via method {@code put}) without + * waiting for receipt. + * {@linkplain #tryTransfer(Object) Non-blocking} and + * {@linkplain #tryTransfer(Object,long,TimeUnit) time-out} versions of + * {@code tryTransfer} are also available. + * A {@code TransferQueue} may also be queried, via {@link + * #hasWaitingConsumer}, whether there are any threads waiting for + * items, which is a converse analogy to a {@code peek} operation. + * + *

Like other blocking queues, a {@code TransferQueue} may be + * capacity bounded. If so, an attempted transfer operation may + * initially block waiting for available space, and/or subsequently + * block waiting for reception by a consumer. Note that in a queue + * with zero capacity, such as {@link SynchronousQueue}, {@code put} + * and {@code transfer} are effectively synonymous. + * + *

This interface is a member of the + * + * Java Collections Framework. + * + * @since 1.7 + * @author Doug Lea + * @param the type of elements held in this collection + */ +public interface TransferQueue extends BlockingQueue { + /** + * Transfers the element to a waiting consumer immediately, if possible. + * + *

More precisely, transfers the specified element immediately + * if there exists a consumer already waiting to receive it (in + * {@link #take} or timed {@link #poll(long,TimeUnit) poll}), + * otherwise returning {@code false} without enqueuing the element. + * + * @param e the element to transfer + * @return {@code true} if the element was transferred, else + * {@code false} + * @throws ClassCastException if the class of the specified element + * prevents it from being added to this queue + * @throws NullPointerException if the specified element is null + * @throws IllegalArgumentException if some property of the specified + * element prevents it from being added to this queue + */ + boolean tryTransfer(E e); + + /** + * Transfers the element to a consumer, waiting if necessary to do so. + * + *

More precisely, transfers the specified element immediately + * if there exists a consumer already waiting to receive it (in + * {@link #take} or timed {@link #poll(long,TimeUnit) poll}), + * else waits until the element is received by a consumer. + * + * @param e the element to transfer + * @throws InterruptedException if interrupted while waiting, + * in which case the element is not left enqueued + * @throws ClassCastException if the class of the specified element + * prevents it from being added to this queue + * @throws NullPointerException if the specified element is null + * @throws IllegalArgumentException if some property of the specified + * element prevents it from being added to this queue + */ + void transfer(E e) throws InterruptedException; + + /** + * Transfers the element to a consumer if it is possible to do so + * before the timeout elapses. + * + *

More precisely, transfers the specified element immediately + * if there exists a consumer already waiting to receive it (in + * {@link #take} or timed {@link #poll(long,TimeUnit) poll}), + * else waits until the element is received by a consumer, + * returning {@code false} if the specified wait time elapses + * before the element can be transferred. + * + * @param e the element to transfer + * @param timeout how long to wait before giving up, in units of + * {@code unit} + * @param unit a {@code TimeUnit} determining how to interpret the + * {@code timeout} parameter + * @return {@code true} if successful, or {@code false} if + * the specified waiting time elapses before completion, + * in which case the element is not left enqueued + * @throws InterruptedException if interrupted while waiting, + * in which case the element is not left enqueued + * @throws ClassCastException if the class of the specified element + * prevents it from being added to this queue + * @throws NullPointerException if the specified element is null + * @throws IllegalArgumentException if some property of the specified + * element prevents it from being added to this queue + */ + boolean tryTransfer(E e, long timeout, TimeUnit unit) + throws InterruptedException; + + /** + * Returns {@code true} if there is at least one consumer waiting + * to receive an element via {@link #take} or + * timed {@link #poll(long,TimeUnit) poll}. + * The return value represents a momentary state of affairs. + * + * @return {@code true} if there is at least one waiting consumer + */ + boolean hasWaitingConsumer(); + + /** + * Returns an estimate of the number of consumers waiting to + * receive elements via {@link #take} or timed + * {@link #poll(long,TimeUnit) poll}. The return value is an + * approximation of a momentary state of affairs, that may be + * inaccurate if consumers have completed or given up waiting. + * The value may be useful for monitoring and heuristics, but + * not for synchronization control. Implementations of this + * method are likely to be noticeably slower than those for + * {@link #hasWaitingConsumer}. + * + * @return the number of consumers waiting to receive elements + */ + int getWaitingConsumerCount(); +} diff -r e1953d8b8338 -r c8af252ea9eb rt/emul/compact/src/main/java/java/util/concurrent/locks/AbstractOwnableSynchronizer.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/locks/AbstractOwnableSynchronizer.java Sat Mar 19 10:48:29 2016 +0100 @@ -0,0 +1,86 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +package java.util.concurrent.locks; + +/** + * A synchronizer that may be exclusively owned by a thread. This + * class provides a basis for creating locks and related synchronizers + * that may entail a notion of ownership. The + * AbstractOwnableSynchronizer class itself does not manage or + * use this information. However, subclasses and tools may use + * appropriately maintained values to help control and monitor access + * and provide diagnostics. + * + * @since 1.6 + * @author Doug Lea + */ +public abstract class AbstractOwnableSynchronizer + implements java.io.Serializable { + + /** Use serial ID even though all fields transient. */ + private static final long serialVersionUID = 3737899427754241961L; + + /** + * Empty constructor for use by subclasses. + */ + protected AbstractOwnableSynchronizer() { } + + /** + * The current owner of exclusive mode synchronization. + */ + private transient Thread exclusiveOwnerThread; + + /** + * Sets the thread that currently owns exclusive access. A + * null argument indicates that no thread owns access. + * This method does not otherwise impose any synchronization or + * volatile field accesses. + */ + protected final void setExclusiveOwnerThread(Thread t) { + exclusiveOwnerThread = t; + } + + /** + * Returns the thread last set by + * setExclusiveOwnerThread, or null if never + * set. This method does not otherwise impose any synchronization + * or volatile field accesses. + * @return the owner thread + */ + protected final Thread getExclusiveOwnerThread() { + return exclusiveOwnerThread; + } +} diff -r e1953d8b8338 -r c8af252ea9eb rt/emul/compact/src/main/java/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java Sat Mar 19 10:48:29 2016 +0100 @@ -0,0 +1,2109 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +package java.util.concurrent.locks; +import java.util.*; +import java.util.concurrent.*; +import java.util.concurrent.atomic.*; +import sun.misc.Unsafe; + +/** + * A version of {@link AbstractQueuedSynchronizer} in + * which synchronization state is maintained as a long. + * This class has exactly the same structure, properties, and methods + * as AbstractQueuedSynchronizer with the exception + * that all state-related parameters and results are defined + * as long rather than int. This class + * may be useful when creating synchronizers such as + * multilevel locks and barriers that require + * 64 bits of state. + * + *

See {@link AbstractQueuedSynchronizer} for usage + * notes and examples. + * + * @since 1.6 + * @author Doug Lea + */ +public abstract class AbstractQueuedLongSynchronizer + extends AbstractOwnableSynchronizer + implements java.io.Serializable { + + private static final long serialVersionUID = 7373984972572414692L; + + /* + To keep sources in sync, the remainder of this source file is + exactly cloned from AbstractQueuedSynchronizer, replacing class + name and changing ints related with sync state to longs. Please + keep it that way. + */ + + /** + * Creates a new AbstractQueuedLongSynchronizer instance + * with initial synchronization state of zero. + */ + protected AbstractQueuedLongSynchronizer() { } + + /** + * Wait queue node class. + * + *

The wait queue is a variant of a "CLH" (Craig, Landin, and + * Hagersten) lock queue. CLH locks are normally used for + * spinlocks. We instead use them for blocking synchronizers, but + * use the same basic tactic of holding some of the control + * information about a thread in the predecessor of its node. A + * "status" field in each node keeps track of whether a thread + * should block. A node is signalled when its predecessor + * releases. Each node of the queue otherwise serves as a + * specific-notification-style monitor holding a single waiting + * thread. The status field does NOT control whether threads are + * granted locks etc though. A thread may try to acquire if it is + * first in the queue. But being first does not guarantee success; + * it only gives the right to contend. So the currently released + * contender thread may need to rewait. + * + *

To enqueue into a CLH lock, you atomically splice it in as new + * tail. To dequeue, you just set the head field. + *

+     *      +------+  prev +-----+       +-----+
+     * head |      | <---- |     | <---- |     |  tail
+     *      +------+       +-----+       +-----+
+     * 
+ * + *

Insertion into a CLH queue requires only a single atomic + * operation on "tail", so there is a simple atomic point of + * demarcation from unqueued to queued. Similarly, dequeing + * involves only updating the "head". However, it takes a bit + * more work for nodes to determine who their successors are, + * in part to deal with possible cancellation due to timeouts + * and interrupts. + * + *

The "prev" links (not used in original CLH locks), are mainly + * needed to handle cancellation. If a node is cancelled, its + * successor is (normally) relinked to a non-cancelled + * predecessor. For explanation of similar mechanics in the case + * of spin locks, see the papers by Scott and Scherer at + * http://www.cs.rochester.edu/u/scott/synchronization/ + * + *

We also use "next" links to implement blocking mechanics. + * The thread id for each node is kept in its own node, so a + * predecessor signals the next node to wake up by traversing + * next link to determine which thread it is. Determination of + * successor must avoid races with newly queued nodes to set + * the "next" fields of their predecessors. This is solved + * when necessary by checking backwards from the atomically + * updated "tail" when a node's successor appears to be null. + * (Or, said differently, the next-links are an optimization + * so that we don't usually need a backward scan.) + * + *

Cancellation introduces some conservatism to the basic + * algorithms. Since we must poll for cancellation of other + * nodes, we can miss noticing whether a cancelled node is + * ahead or behind us. This is dealt with by always unparking + * successors upon cancellation, allowing them to stabilize on + * a new predecessor, unless we can identify an uncancelled + * predecessor who will carry this responsibility. + * + *

CLH queues need a dummy header node to get started. But + * we don't create them on construction, because it would be wasted + * effort if there is never contention. Instead, the node + * is constructed and head and tail pointers are set upon first + * contention. + * + *

Threads waiting on Conditions use the same nodes, but + * use an additional link. Conditions only need to link nodes + * in simple (non-concurrent) linked queues because they are + * only accessed when exclusively held. Upon await, a node is + * inserted into a condition queue. Upon signal, the node is + * transferred to the main queue. A special value of status + * field is used to mark which queue a node is on. + * + *

Thanks go to Dave Dice, Mark Moir, Victor Luchangco, Bill + * Scherer and Michael Scott, along with members of JSR-166 + * expert group, for helpful ideas, discussions, and critiques + * on the design of this class. + */ + static final class Node { + /** Marker to indicate a node is waiting in shared mode */ + static final Node SHARED = new Node(); + /** Marker to indicate a node is waiting in exclusive mode */ + static final Node EXCLUSIVE = null; + + /** waitStatus value to indicate thread has cancelled */ + static final int CANCELLED = 1; + /** waitStatus value to indicate successor's thread needs unparking */ + static final int SIGNAL = -1; + /** waitStatus value to indicate thread is waiting on condition */ + static final int CONDITION = -2; + /** + * waitStatus value to indicate the next acquireShared should + * unconditionally propagate + */ + static final int PROPAGATE = -3; + + /** + * Status field, taking on only the values: + * SIGNAL: The successor of this node is (or will soon be) + * blocked (via park), so the current node must + * unpark its successor when it releases or + * cancels. To avoid races, acquire methods must + * first indicate they need a signal, + * then retry the atomic acquire, and then, + * on failure, block. + * CANCELLED: This node is cancelled due to timeout or interrupt. + * Nodes never leave this state. In particular, + * a thread with cancelled node never again blocks. + * CONDITION: This node is currently on a condition queue. + * It will not be used as a sync queue node + * until transferred, at which time the status + * will be set to 0. (Use of this value here has + * nothing to do with the other uses of the + * field, but simplifies mechanics.) + * PROPAGATE: A releaseShared should be propagated to other + * nodes. This is set (for head node only) in + * doReleaseShared to ensure propagation + * continues, even if other operations have + * since intervened. + * 0: None of the above + * + * The values are arranged numerically to simplify use. + * Non-negative values mean that a node doesn't need to + * signal. So, most code doesn't need to check for particular + * values, just for sign. + * + * The field is initialized to 0 for normal sync nodes, and + * CONDITION for condition nodes. It is modified using CAS + * (or when possible, unconditional volatile writes). + */ + volatile int waitStatus; + + /** + * Link to predecessor node that current node/thread relies on + * for checking waitStatus. Assigned during enqueing, and nulled + * out (for sake of GC) only upon dequeuing. Also, upon + * cancellation of a predecessor, we short-circuit while + * finding a non-cancelled one, which will always exist + * because the head node is never cancelled: A node becomes + * head only as a result of successful acquire. A + * cancelled thread never succeeds in acquiring, and a thread only + * cancels itself, not any other node. + */ + volatile Node prev; + + /** + * Link to the successor node that the current node/thread + * unparks upon release. Assigned during enqueuing, adjusted + * when bypassing cancelled predecessors, and nulled out (for + * sake of GC) when dequeued. The enq operation does not + * assign next field of a predecessor until after attachment, + * so seeing a null next field does not necessarily mean that + * node is at end of queue. However, if a next field appears + * to be null, we can scan prev's from the tail to + * double-check. The next field of cancelled nodes is set to + * point to the node itself instead of null, to make life + * easier for isOnSyncQueue. + */ + volatile Node next; + + /** + * The thread that enqueued this node. Initialized on + * construction and nulled out after use. + */ + volatile Thread thread; + + /** + * Link to next node waiting on condition, or the special + * value SHARED. Because condition queues are accessed only + * when holding in exclusive mode, we just need a simple + * linked queue to hold nodes while they are waiting on + * conditions. They are then transferred to the queue to + * re-acquire. And because conditions can only be exclusive, + * we save a field by using special value to indicate shared + * mode. + */ + Node nextWaiter; + + /** + * Returns true if node is waiting in shared mode + */ + final boolean isShared() { + return nextWaiter == SHARED; + } + + /** + * Returns previous node, or throws NullPointerException if null. + * Use when predecessor cannot be null. The null check could + * be elided, but is present to help the VM. + * + * @return the predecessor of this node + */ + final Node predecessor() throws NullPointerException { + Node p = prev; + if (p == null) + throw new NullPointerException(); + else + return p; + } + + Node() { // Used to establish initial head or SHARED marker + } + + Node(Thread thread, Node mode) { // Used by addWaiter + this.nextWaiter = mode; + this.thread = thread; + } + + Node(Thread thread, int waitStatus) { // Used by Condition + this.waitStatus = waitStatus; + this.thread = thread; + } + } + + /** + * Head of the wait queue, lazily initialized. Except for + * initialization, it is modified only via method setHead. Note: + * If head exists, its waitStatus is guaranteed not to be + * CANCELLED. + */ + private transient volatile Node head; + + /** + * Tail of the wait queue, lazily initialized. Modified only via + * method enq to add new wait node. + */ + private transient volatile Node tail; + + /** + * The synchronization state. + */ + private volatile long state; + + /** + * Returns the current value of synchronization state. + * This operation has memory semantics of a volatile read. + * @return current state value + */ + protected final long getState() { + return state; + } + + /** + * Sets the value of synchronization state. + * This operation has memory semantics of a volatile write. + * @param newState the new state value + */ + protected final void setState(long newState) { + state = newState; + } + + /** + * Atomically sets synchronization state to the given updated + * value if the current state value equals the expected value. + * This operation has memory semantics of a volatile read + * and write. + * + * @param expect the expected value + * @param update the new value + * @return true if successful. False return indicates that the actual + * value was not equal to the expected value. + */ + protected final boolean compareAndSetState(long expect, long update) { + // See below for intrinsics setup to support this + return unsafe.compareAndSwapLong(this, stateOffset, expect, update); + } + + // Queuing utilities + + /** + * The number of nanoseconds for which it is faster to spin + * rather than to use timed park. A rough estimate suffices + * to improve responsiveness with very short timeouts. + */ + static final long spinForTimeoutThreshold = 1000L; + + /** + * Inserts node into queue, initializing if necessary. See picture above. + * @param node the node to insert + * @return node's predecessor + */ + private Node enq(final Node node) { + for (;;) { + Node t = tail; + if (t == null) { // Must initialize + if (compareAndSetHead(new Node())) + tail = head; + } else { + node.prev = t; + if (compareAndSetTail(t, node)) { + t.next = node; + return t; + } + } + } + } + + /** + * Creates and enqueues node for current thread and given mode. + * + * @param mode Node.EXCLUSIVE for exclusive, Node.SHARED for shared + * @return the new node + */ + private Node addWaiter(Node mode) { + Node node = new Node(Thread.currentThread(), mode); + // Try the fast path of enq; backup to full enq on failure + Node pred = tail; + if (pred != null) { + node.prev = pred; + if (compareAndSetTail(pred, node)) { + pred.next = node; + return node; + } + } + enq(node); + return node; + } + + /** + * Sets head of queue to be node, thus dequeuing. Called only by + * acquire methods. Also nulls out unused fields for sake of GC + * and to suppress unnecessary signals and traversals. + * + * @param node the node + */ + private void setHead(Node node) { + head = node; + node.thread = null; + node.prev = null; + } + + /** + * Wakes up node's successor, if one exists. + * + * @param node the node + */ + private void unparkSuccessor(Node node) { + /* + * If status is negative (i.e., possibly needing signal) try + * to clear in anticipation of signalling. It is OK if this + * fails or if status is changed by waiting thread. + */ + int ws = node.waitStatus; + if (ws < 0) + compareAndSetWaitStatus(node, ws, 0); + + /* + * Thread to unpark is held in successor, which is normally + * just the next node. But if cancelled or apparently null, + * traverse backwards from tail to find the actual + * non-cancelled successor. + */ + Node s = node.next; + if (s == null || s.waitStatus > 0) { + s = null; + for (Node t = tail; t != null && t != node; t = t.prev) + if (t.waitStatus <= 0) + s = t; + } + if (s != null) + LockSupport.unpark(s.thread); + } + + /** + * Release action for shared mode -- signal successor and ensure + * propagation. (Note: For exclusive mode, release just amounts + * to calling unparkSuccessor of head if it needs signal.) + */ + private void doReleaseShared() { + /* + * Ensure that a release propagates, even if there are other + * in-progress acquires/releases. This proceeds in the usual + * way of trying to unparkSuccessor of head if it needs + * signal. But if it does not, status is set to PROPAGATE to + * ensure that upon release, propagation continues. + * Additionally, we must loop in case a new node is added + * while we are doing this. Also, unlike other uses of + * unparkSuccessor, we need to know if CAS to reset status + * fails, if so rechecking. + */ + for (;;) { + Node h = head; + if (h != null && h != tail) { + int ws = h.waitStatus; + if (ws == Node.SIGNAL) { + if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0)) + continue; // loop to recheck cases + unparkSuccessor(h); + } + else if (ws == 0 && + !compareAndSetWaitStatus(h, 0, Node.PROPAGATE)) + continue; // loop on failed CAS + } + if (h == head) // loop if head changed + break; + } + } + + /** + * Sets head of queue, and checks if successor may be waiting + * in shared mode, if so propagating if either propagate > 0 or + * PROPAGATE status was set. + * + * @param node the node + * @param propagate the return value from a tryAcquireShared + */ + private void setHeadAndPropagate(Node node, long propagate) { + Node h = head; // Record old head for check below + setHead(node); + /* + * Try to signal next queued node if: + * Propagation was indicated by caller, + * or was recorded (as h.waitStatus) by a previous operation + * (note: this uses sign-check of waitStatus because + * PROPAGATE status may transition to SIGNAL.) + * and + * The next node is waiting in shared mode, + * or we don't know, because it appears null + * + * The conservatism in both of these checks may cause + * unnecessary wake-ups, but only when there are multiple + * racing acquires/releases, so most need signals now or soon + * anyway. + */ + if (propagate > 0 || h == null || h.waitStatus < 0) { + Node s = node.next; + if (s == null || s.isShared()) + doReleaseShared(); + } + } + + // Utilities for various versions of acquire + + /** + * Cancels an ongoing attempt to acquire. + * + * @param node the node + */ + private void cancelAcquire(Node node) { + // Ignore if node doesn't exist + if (node == null) + return; + + node.thread = null; + + // Skip cancelled predecessors + Node pred = node.prev; + while (pred.waitStatus > 0) + node.prev = pred = pred.prev; + + // predNext is the apparent node to unsplice. CASes below will + // fail if not, in which case, we lost race vs another cancel + // or signal, so no further action is necessary. + Node predNext = pred.next; + + // Can use unconditional write instead of CAS here. + // After this atomic step, other Nodes can skip past us. + // Before, we are free of interference from other threads. + node.waitStatus = Node.CANCELLED; + + // If we are the tail, remove ourselves. + if (node == tail && compareAndSetTail(node, pred)) { + compareAndSetNext(pred, predNext, null); + } else { + // If successor needs signal, try to set pred's next-link + // so it will get one. Otherwise wake it up to propagate. + int ws; + if (pred != head && + ((ws = pred.waitStatus) == Node.SIGNAL || + (ws <= 0 && compareAndSetWaitStatus(pred, ws, Node.SIGNAL))) && + pred.thread != null) { + Node next = node.next; + if (next != null && next.waitStatus <= 0) + compareAndSetNext(pred, predNext, next); + } else { + unparkSuccessor(node); + } + + node.next = node; // help GC + } + } + + /** + * Checks and updates status for a node that failed to acquire. + * Returns true if thread should block. This is the main signal + * control in all acquire loops. Requires that pred == node.prev + * + * @param pred node's predecessor holding status + * @param node the node + * @return {@code true} if thread should block + */ + private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) { + int ws = pred.waitStatus; + if (ws == Node.SIGNAL) + /* + * This node has already set status asking a release + * to signal it, so it can safely park. + */ + return true; + if (ws > 0) { + /* + * Predecessor was cancelled. Skip over predecessors and + * indicate retry. + */ + do { + node.prev = pred = pred.prev; + } while (pred.waitStatus > 0); + pred.next = node; + } else { + /* + * waitStatus must be 0 or PROPAGATE. Indicate that we + * need a signal, but don't park yet. Caller will need to + * retry to make sure it cannot acquire before parking. + */ + compareAndSetWaitStatus(pred, ws, Node.SIGNAL); + } + return false; + } + + /** + * Convenience method to interrupt current thread. + */ + private static void selfInterrupt() { + Thread.currentThread().interrupt(); + } + + /** + * Convenience method to park and then check if interrupted + * + * @return {@code true} if interrupted + */ + private final boolean parkAndCheckInterrupt() { + LockSupport.park(this); + return Thread.interrupted(); + } + + /* + * Various flavors of acquire, varying in exclusive/shared and + * control modes. Each is mostly the same, but annoyingly + * different. Only a little bit of factoring is possible due to + * interactions of exception mechanics (including ensuring that we + * cancel if tryAcquire throws exception) and other control, at + * least not without hurting performance too much. + */ + + /** + * Acquires in exclusive uninterruptible mode for thread already in + * queue. Used by condition wait methods as well as acquire. + * + * @param node the node + * @param arg the acquire argument + * @return {@code true} if interrupted while waiting + */ + final boolean acquireQueued(final Node node, long arg) { + boolean failed = true; + try { + boolean interrupted = false; + for (;;) { + final Node p = node.predecessor(); + if (p == head && tryAcquire(arg)) { + setHead(node); + p.next = null; // help GC + failed = false; + return interrupted; + } + if (shouldParkAfterFailedAcquire(p, node) && + parkAndCheckInterrupt()) + interrupted = true; + } + } finally { + if (failed) + cancelAcquire(node); + } + } + + /** + * Acquires in exclusive interruptible mode. + * @param arg the acquire argument + */ + private void doAcquireInterruptibly(long arg) + throws InterruptedException { + final Node node = addWaiter(Node.EXCLUSIVE); + boolean failed = true; + try { + for (;;) { + final Node p = node.predecessor(); + if (p == head && tryAcquire(arg)) { + setHead(node); + p.next = null; // help GC + failed = false; + return; + } + if (shouldParkAfterFailedAcquire(p, node) && + parkAndCheckInterrupt()) + throw new InterruptedException(); + } + } finally { + if (failed) + cancelAcquire(node); + } + } + + /** + * Acquires in exclusive timed mode. + * + * @param arg the acquire argument + * @param nanosTimeout max wait time + * @return {@code true} if acquired + */ + private boolean doAcquireNanos(long arg, long nanosTimeout) + throws InterruptedException { + long lastTime = System.nanoTime(); + final Node node = addWaiter(Node.EXCLUSIVE); + boolean failed = true; + try { + for (;;) { + final Node p = node.predecessor(); + if (p == head && tryAcquire(arg)) { + setHead(node); + p.next = null; // help GC + failed = false; + return true; + } + if (nanosTimeout <= 0) + return false; + if (shouldParkAfterFailedAcquire(p, node) && + nanosTimeout > spinForTimeoutThreshold) + LockSupport.parkNanos(this, nanosTimeout); + long now = System.nanoTime(); + nanosTimeout -= now - lastTime; + lastTime = now; + if (Thread.interrupted()) + throw new InterruptedException(); + } + } finally { + if (failed) + cancelAcquire(node); + } + } + + /** + * Acquires in shared uninterruptible mode. + * @param arg the acquire argument + */ + private void doAcquireShared(long arg) { + final Node node = addWaiter(Node.SHARED); + boolean failed = true; + try { + boolean interrupted = false; + for (;;) { + final Node p = node.predecessor(); + if (p == head) { + long r = tryAcquireShared(arg); + if (r >= 0) { + setHeadAndPropagate(node, r); + p.next = null; // help GC + if (interrupted) + selfInterrupt(); + failed = false; + return; + } + } + if (shouldParkAfterFailedAcquire(p, node) && + parkAndCheckInterrupt()) + interrupted = true; + } + } finally { + if (failed) + cancelAcquire(node); + } + } + + /** + * Acquires in shared interruptible mode. + * @param arg the acquire argument + */ + private void doAcquireSharedInterruptibly(long arg) + throws InterruptedException { + final Node node = addWaiter(Node.SHARED); + boolean failed = true; + try { + for (;;) { + final Node p = node.predecessor(); + if (p == head) { + long r = tryAcquireShared(arg); + if (r >= 0) { + setHeadAndPropagate(node, r); + p.next = null; // help GC + failed = false; + return; + } + } + if (shouldParkAfterFailedAcquire(p, node) && + parkAndCheckInterrupt()) + throw new InterruptedException(); + } + } finally { + if (failed) + cancelAcquire(node); + } + } + + /** + * Acquires in shared timed mode. + * + * @param arg the acquire argument + * @param nanosTimeout max wait time + * @return {@code true} if acquired + */ + private boolean doAcquireSharedNanos(long arg, long nanosTimeout) + throws InterruptedException { + + long lastTime = System.nanoTime(); + final Node node = addWaiter(Node.SHARED); + boolean failed = true; + try { + for (;;) { + final Node p = node.predecessor(); + if (p == head) { + long r = tryAcquireShared(arg); + if (r >= 0) { + setHeadAndPropagate(node, r); + p.next = null; // help GC + failed = false; + return true; + } + } + if (nanosTimeout <= 0) + return false; + if (shouldParkAfterFailedAcquire(p, node) && + nanosTimeout > spinForTimeoutThreshold) + LockSupport.parkNanos(this, nanosTimeout); + long now = System.nanoTime(); + nanosTimeout -= now - lastTime; + lastTime = now; + if (Thread.interrupted()) + throw new InterruptedException(); + } + } finally { + if (failed) + cancelAcquire(node); + } + } + + // Main exported methods + + /** + * Attempts to acquire in exclusive mode. This method should query + * if the state of the object permits it to be acquired in the + * exclusive mode, and if so to acquire it. + * + *

This method is always invoked by the thread performing + * acquire. If this method reports failure, the acquire method + * may queue the thread, if it is not already queued, until it is + * signalled by a release from some other thread. This can be used + * to implement method {@link Lock#tryLock()}. + * + *

The default + * implementation throws {@link UnsupportedOperationException}. + * + * @param arg the acquire argument. This value is always the one + * passed to an acquire method, or is the value saved on entry + * to a condition wait. The value is otherwise uninterpreted + * and can represent anything you like. + * @return {@code true} if successful. Upon success, this object has + * been acquired. + * @throws IllegalMonitorStateException if acquiring would place this + * synchronizer in an illegal state. This exception must be + * thrown in a consistent fashion for synchronization to work + * correctly. + * @throws UnsupportedOperationException if exclusive mode is not supported + */ + protected boolean tryAcquire(long arg) { + throw new UnsupportedOperationException(); + } + + /** + * Attempts to set the state to reflect a release in exclusive + * mode. + * + *

This method is always invoked by the thread performing release. + * + *

The default implementation throws + * {@link UnsupportedOperationException}. + * + * @param arg the release argument. This value is always the one + * passed to a release method, or the current state value upon + * entry to a condition wait. The value is otherwise + * uninterpreted and can represent anything you like. + * @return {@code true} if this object is now in a fully released + * state, so that any waiting threads may attempt to acquire; + * and {@code false} otherwise. + * @throws IllegalMonitorStateException if releasing would place this + * synchronizer in an illegal state. This exception must be + * thrown in a consistent fashion for synchronization to work + * correctly. + * @throws UnsupportedOperationException if exclusive mode is not supported + */ + protected boolean tryRelease(long arg) { + throw new UnsupportedOperationException(); + } + + /** + * Attempts to acquire in shared mode. This method should query if + * the state of the object permits it to be acquired in the shared + * mode, and if so to acquire it. + * + *

This method is always invoked by the thread performing + * acquire. If this method reports failure, the acquire method + * may queue the thread, if it is not already queued, until it is + * signalled by a release from some other thread. + * + *

The default implementation throws {@link + * UnsupportedOperationException}. + * + * @param arg the acquire argument. This value is always the one + * passed to an acquire method, or is the value saved on entry + * to a condition wait. The value is otherwise uninterpreted + * and can represent anything you like. + * @return a negative value on failure; zero if acquisition in shared + * mode succeeded but no subsequent shared-mode acquire can + * succeed; and a positive value if acquisition in shared + * mode succeeded and subsequent shared-mode acquires might + * also succeed, in which case a subsequent waiting thread + * must check availability. (Support for three different + * return values enables this method to be used in contexts + * where acquires only sometimes act exclusively.) Upon + * success, this object has been acquired. + * @throws IllegalMonitorStateException if acquiring would place this + * synchronizer in an illegal state. This exception must be + * thrown in a consistent fashion for synchronization to work + * correctly. + * @throws UnsupportedOperationException if shared mode is not supported + */ + protected long tryAcquireShared(long arg) { + throw new UnsupportedOperationException(); + } + + /** + * Attempts to set the state to reflect a release in shared mode. + * + *

This method is always invoked by the thread performing release. + * + *

The default implementation throws + * {@link UnsupportedOperationException}. + * + * @param arg the release argument. This value is always the one + * passed to a release method, or the current state value upon + * entry to a condition wait. The value is otherwise + * uninterpreted and can represent anything you like. + * @return {@code true} if this release of shared mode may permit a + * waiting acquire (shared or exclusive) to succeed; and + * {@code false} otherwise + * @throws IllegalMonitorStateException if releasing would place this + * synchronizer in an illegal state. This exception must be + * thrown in a consistent fashion for synchronization to work + * correctly. + * @throws UnsupportedOperationException if shared mode is not supported + */ + protected boolean tryReleaseShared(long arg) { + throw new UnsupportedOperationException(); + } + + /** + * Returns {@code true} if synchronization is held exclusively with + * respect to the current (calling) thread. This method is invoked + * upon each call to a non-waiting {@link ConditionObject} method. + * (Waiting methods instead invoke {@link #release}.) + * + *

The default implementation throws {@link + * UnsupportedOperationException}. This method is invoked + * internally only within {@link ConditionObject} methods, so need + * not be defined if conditions are not used. + * + * @return {@code true} if synchronization is held exclusively; + * {@code false} otherwise + * @throws UnsupportedOperationException if conditions are not supported + */ + protected boolean isHeldExclusively() { + throw new UnsupportedOperationException(); + } + + /** + * Acquires in exclusive mode, ignoring interrupts. Implemented + * by invoking at least once {@link #tryAcquire}, + * returning on success. Otherwise the thread is queued, possibly + * repeatedly blocking and unblocking, invoking {@link + * #tryAcquire} until success. This method can be used + * to implement method {@link Lock#lock}. + * + * @param arg the acquire argument. This value is conveyed to + * {@link #tryAcquire} but is otherwise uninterpreted and + * can represent anything you like. + */ + public final void acquire(long arg) { + if (!tryAcquire(arg) && + acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) + selfInterrupt(); + } + + /** + * Acquires in exclusive mode, aborting if interrupted. + * Implemented by first checking interrupt status, then invoking + * at least once {@link #tryAcquire}, returning on + * success. Otherwise the thread is queued, possibly repeatedly + * blocking and unblocking, invoking {@link #tryAcquire} + * until success or the thread is interrupted. This method can be + * used to implement method {@link Lock#lockInterruptibly}. + * + * @param arg the acquire argument. This value is conveyed to + * {@link #tryAcquire} but is otherwise uninterpreted and + * can represent anything you like. + * @throws InterruptedException if the current thread is interrupted + */ + public final void acquireInterruptibly(long arg) + throws InterruptedException { + if (Thread.interrupted()) + throw new InterruptedException(); + if (!tryAcquire(arg)) + doAcquireInterruptibly(arg); + } + + /** + * Attempts to acquire in exclusive mode, aborting if interrupted, + * and failing if the given timeout elapses. Implemented by first + * checking interrupt status, then invoking at least once {@link + * #tryAcquire}, returning on success. Otherwise, the thread is + * queued, possibly repeatedly blocking and unblocking, invoking + * {@link #tryAcquire} until success or the thread is interrupted + * or the timeout elapses. This method can be used to implement + * method {@link Lock#tryLock(long, TimeUnit)}. + * + * @param arg the acquire argument. This value is conveyed to + * {@link #tryAcquire} but is otherwise uninterpreted and + * can represent anything you like. + * @param nanosTimeout the maximum number of nanoseconds to wait + * @return {@code true} if acquired; {@code false} if timed out + * @throws InterruptedException if the current thread is interrupted + */ + public final boolean tryAcquireNanos(long arg, long nanosTimeout) + throws InterruptedException { + if (Thread.interrupted()) + throw new InterruptedException(); + return tryAcquire(arg) || + doAcquireNanos(arg, nanosTimeout); + } + + /** + * Releases in exclusive mode. Implemented by unblocking one or + * more threads if {@link #tryRelease} returns true. + * This method can be used to implement method {@link Lock#unlock}. + * + * @param arg the release argument. This value is conveyed to + * {@link #tryRelease} but is otherwise uninterpreted and + * can represent anything you like. + * @return the value returned from {@link #tryRelease} + */ + public final boolean release(long arg) { + if (tryRelease(arg)) { + Node h = head; + if (h != null && h.waitStatus != 0) + unparkSuccessor(h); + return true; + } + return false; + } + + /** + * Acquires in shared mode, ignoring interrupts. Implemented by + * first invoking at least once {@link #tryAcquireShared}, + * returning on success. Otherwise the thread is queued, possibly + * repeatedly blocking and unblocking, invoking {@link + * #tryAcquireShared} until success. + * + * @param arg the acquire argument. This value is conveyed to + * {@link #tryAcquireShared} but is otherwise uninterpreted + * and can represent anything you like. + */ + public final void acquireShared(long arg) { + if (tryAcquireShared(arg) < 0) + doAcquireShared(arg); + } + + /** + * Acquires in shared mode, aborting if interrupted. Implemented + * by first checking interrupt status, then invoking at least once + * {@link #tryAcquireShared}, returning on success. Otherwise the + * thread is queued, possibly repeatedly blocking and unblocking, + * invoking {@link #tryAcquireShared} until success or the thread + * is interrupted. + * @param arg the acquire argument + * This value is conveyed to {@link #tryAcquireShared} but is + * otherwise uninterpreted and can represent anything + * you like. + * @throws InterruptedException if the current thread is interrupted + */ + public final void acquireSharedInterruptibly(long arg) + throws InterruptedException { + if (Thread.interrupted()) + throw new InterruptedException(); + if (tryAcquireShared(arg) < 0) + doAcquireSharedInterruptibly(arg); + } + + /** + * Attempts to acquire in shared mode, aborting if interrupted, and + * failing if the given timeout elapses. Implemented by first + * checking interrupt status, then invoking at least once {@link + * #tryAcquireShared}, returning on success. Otherwise, the + * thread is queued, possibly repeatedly blocking and unblocking, + * invoking {@link #tryAcquireShared} until success or the thread + * is interrupted or the timeout elapses. + * + * @param arg the acquire argument. This value is conveyed to + * {@link #tryAcquireShared} but is otherwise uninterpreted + * and can represent anything you like. + * @param nanosTimeout the maximum number of nanoseconds to wait + * @return {@code true} if acquired; {@code false} if timed out + * @throws InterruptedException if the current thread is interrupted + */ + public final boolean tryAcquireSharedNanos(long arg, long nanosTimeout) + throws InterruptedException { + if (Thread.interrupted()) + throw new InterruptedException(); + return tryAcquireShared(arg) >= 0 || + doAcquireSharedNanos(arg, nanosTimeout); + } + + /** + * Releases in shared mode. Implemented by unblocking one or more + * threads if {@link #tryReleaseShared} returns true. + * + * @param arg the release argument. This value is conveyed to + * {@link #tryReleaseShared} but is otherwise uninterpreted + * and can represent anything you like. + * @return the value returned from {@link #tryReleaseShared} + */ + public final boolean releaseShared(long arg) { + if (tryReleaseShared(arg)) { + doReleaseShared(); + return true; + } + return false; + } + + // Queue inspection methods + + /** + * Queries whether any threads are waiting to acquire. Note that + * because cancellations due to interrupts and timeouts may occur + * at any time, a {@code true} return does not guarantee that any + * other thread will ever acquire. + * + *

In this implementation, this operation returns in + * constant time. + * + * @return {@code true} if there may be other threads waiting to acquire + */ + public final boolean hasQueuedThreads() { + return head != tail; + } + + /** + * Queries whether any threads have ever contended to acquire this + * synchronizer; that is if an acquire method has ever blocked. + * + *

In this implementation, this operation returns in + * constant time. + * + * @return {@code true} if there has ever been contention + */ + public final boolean hasContended() { + return head != null; + } + + /** + * Returns the first (longest-waiting) thread in the queue, or + * {@code null} if no threads are currently queued. + * + *

In this implementation, this operation normally returns in + * constant time, but may iterate upon contention if other threads are + * concurrently modifying the queue. + * + * @return the first (longest-waiting) thread in the queue, or + * {@code null} if no threads are currently queued + */ + public final Thread getFirstQueuedThread() { + // handle only fast path, else relay + return (head == tail) ? null : fullGetFirstQueuedThread(); + } + + /** + * Version of getFirstQueuedThread called when fastpath fails + */ + private Thread fullGetFirstQueuedThread() { + /* + * The first node is normally head.next. Try to get its + * thread field, ensuring consistent reads: If thread + * field is nulled out or s.prev is no longer head, then + * some other thread(s) concurrently performed setHead in + * between some of our reads. We try this twice before + * resorting to traversal. + */ + Node h, s; + Thread st; + if (((h = head) != null && (s = h.next) != null && + s.prev == head && (st = s.thread) != null) || + ((h = head) != null && (s = h.next) != null && + s.prev == head && (st = s.thread) != null)) + return st; + + /* + * Head's next field might not have been set yet, or may have + * been unset after setHead. So we must check to see if tail + * is actually first node. If not, we continue on, safely + * traversing from tail back to head to find first, + * guaranteeing termination. + */ + + Node t = tail; + Thread firstThread = null; + while (t != null && t != head) { + Thread tt = t.thread; + if (tt != null) + firstThread = tt; + t = t.prev; + } + return firstThread; + } + + /** + * Returns true if the given thread is currently queued. + * + *

This implementation traverses the queue to determine + * presence of the given thread. + * + * @param thread the thread + * @return {@code true} if the given thread is on the queue + * @throws NullPointerException if the thread is null + */ + public final boolean isQueued(Thread thread) { + if (thread == null) + throw new NullPointerException(); + for (Node p = tail; p != null; p = p.prev) + if (p.thread == thread) + return true; + return false; + } + + /** + * Returns {@code true} if the apparent first queued thread, if one + * exists, is waiting in exclusive mode. If this method returns + * {@code true}, and the current thread is attempting to acquire in + * shared mode (that is, this method is invoked from {@link + * #tryAcquireShared}) then it is guaranteed that the current thread + * is not the first queued thread. Used only as a heuristic in + * ReentrantReadWriteLock. + */ + final boolean apparentlyFirstQueuedIsExclusive() { + Node h, s; + return (h = head) != null && + (s = h.next) != null && + !s.isShared() && + s.thread != null; + } + + /** + * Queries whether any threads have been waiting to acquire longer + * than the current thread. + * + *

An invocation of this method is equivalent to (but may be + * more efficient than): + *

 {@code
+     * getFirstQueuedThread() != Thread.currentThread() &&
+     * hasQueuedThreads()}
+ * + *

Note that because cancellations due to interrupts and + * timeouts may occur at any time, a {@code true} return does not + * guarantee that some other thread will acquire before the current + * thread. Likewise, it is possible for another thread to win a + * race to enqueue after this method has returned {@code false}, + * due to the queue being empty. + * + *

This method is designed to be used by a fair synchronizer to + * avoid barging. + * Such a synchronizer's {@link #tryAcquire} method should return + * {@code false}, and its {@link #tryAcquireShared} method should + * return a negative value, if this method returns {@code true} + * (unless this is a reentrant acquire). For example, the {@code + * tryAcquire} method for a fair, reentrant, exclusive mode + * synchronizer might look like this: + * + *

 {@code
+     * protected boolean tryAcquire(int arg) {
+     *   if (isHeldExclusively()) {
+     *     // A reentrant acquire; increment hold count
+     *     return true;
+     *   } else if (hasQueuedPredecessors()) {
+     *     return false;
+     *   } else {
+     *     // try to acquire normally
+     *   }
+     * }}
+ * + * @return {@code true} if there is a queued thread preceding the + * current thread, and {@code false} if the current thread + * is at the head of the queue or the queue is empty + * @since 1.7 + */ + public final boolean hasQueuedPredecessors() { + // The correctness of this depends on head being initialized + // before tail and on head.next being accurate if the current + // thread is first in queue. + Node t = tail; // Read fields in reverse initialization order + Node h = head; + Node s; + return h != t && + ((s = h.next) == null || s.thread != Thread.currentThread()); + } + + + // Instrumentation and monitoring methods + + /** + * Returns an estimate of the number of threads waiting to + * acquire. The value is only an estimate because the number of + * threads may change dynamically while this method traverses + * internal data structures. This method is designed for use in + * monitoring system state, not for synchronization + * control. + * + * @return the estimated number of threads waiting to acquire + */ + public final int getQueueLength() { + int n = 0; + for (Node p = tail; p != null; p = p.prev) { + if (p.thread != null) + ++n; + } + return n; + } + + /** + * Returns a collection containing threads that may be waiting to + * acquire. Because the actual set of threads may change + * dynamically while constructing this result, the returned + * collection is only a best-effort estimate. The elements of the + * returned collection are in no particular order. This method is + * designed to facilitate construction of subclasses that provide + * more extensive monitoring facilities. + * + * @return the collection of threads + */ + public final Collection getQueuedThreads() { + ArrayList list = new ArrayList(); + for (Node p = tail; p != null; p = p.prev) { + Thread t = p.thread; + if (t != null) + list.add(t); + } + return list; + } + + /** + * Returns a collection containing threads that may be waiting to + * acquire in exclusive mode. This has the same properties + * as {@link #getQueuedThreads} except that it only returns + * those threads waiting due to an exclusive acquire. + * + * @return the collection of threads + */ + public final Collection getExclusiveQueuedThreads() { + ArrayList list = new ArrayList(); + for (Node p = tail; p != null; p = p.prev) { + if (!p.isShared()) { + Thread t = p.thread; + if (t != null) + list.add(t); + } + } + return list; + } + + /** + * Returns a collection containing threads that may be waiting to + * acquire in shared mode. This has the same properties + * as {@link #getQueuedThreads} except that it only returns + * those threads waiting due to a shared acquire. + * + * @return the collection of threads + */ + public final Collection getSharedQueuedThreads() { + ArrayList list = new ArrayList(); + for (Node p = tail; p != null; p = p.prev) { + if (p.isShared()) { + Thread t = p.thread; + if (t != null) + list.add(t); + } + } + return list; + } + + /** + * Returns a string identifying this synchronizer, as well as its state. + * The state, in brackets, includes the String {@code "State ="} + * followed by the current value of {@link #getState}, and either + * {@code "nonempty"} or {@code "empty"} depending on whether the + * queue is empty. + * + * @return a string identifying this synchronizer, as well as its state + */ + public String toString() { + long s = getState(); + String q = hasQueuedThreads() ? "non" : ""; + return super.toString() + + "[State = " + s + ", " + q + "empty queue]"; + } + + + // Internal support methods for Conditions + + /** + * Returns true if a node, always one that was initially placed on + * a condition queue, is now waiting to reacquire on sync queue. + * @param node the node + * @return true if is reacquiring + */ + final boolean isOnSyncQueue(Node node) { + if (node.waitStatus == Node.CONDITION || node.prev == null) + return false; + if (node.next != null) // If has successor, it must be on queue + return true; + /* + * node.prev can be non-null, but not yet on queue because + * the CAS to place it on queue can fail. So we have to + * traverse from tail to make sure it actually made it. It + * will always be near the tail in calls to this method, and + * unless the CAS failed (which is unlikely), it will be + * there, so we hardly ever traverse much. + */ + return findNodeFromTail(node); + } + + /** + * Returns true if node is on sync queue by searching backwards from tail. + * Called only when needed by isOnSyncQueue. + * @return true if present + */ + private boolean findNodeFromTail(Node node) { + Node t = tail; + for (;;) { + if (t == node) + return true; + if (t == null) + return false; + t = t.prev; + } + } + + /** + * Transfers a node from a condition queue onto sync queue. + * Returns true if successful. + * @param node the node + * @return true if successfully transferred (else the node was + * cancelled before signal). + */ + final boolean transferForSignal(Node node) { + /* + * If cannot change waitStatus, the node has been cancelled. + */ + if (!compareAndSetWaitStatus(node, Node.CONDITION, 0)) + return false; + + /* + * Splice onto queue and try to set waitStatus of predecessor to + * indicate that thread is (probably) waiting. If cancelled or + * attempt to set waitStatus fails, wake up to resync (in which + * case the waitStatus can be transiently and harmlessly wrong). + */ + Node p = enq(node); + int ws = p.waitStatus; + if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL)) + LockSupport.unpark(node.thread); + return true; + } + + /** + * Transfers node, if necessary, to sync queue after a cancelled + * wait. Returns true if thread was cancelled before being + * signalled. + * @param current the waiting thread + * @param node its node + * @return true if cancelled before the node was signalled + */ + final boolean transferAfterCancelledWait(Node node) { + if (compareAndSetWaitStatus(node, Node.CONDITION, 0)) { + enq(node); + return true; + } + /* + * If we lost out to a signal(), then we can't proceed + * until it finishes its enq(). Cancelling during an + * incomplete transfer is both rare and transient, so just + * spin. + */ + while (!isOnSyncQueue(node)) + Thread.yield(); + return false; + } + + /** + * Invokes release with current state value; returns saved state. + * Cancels node and throws exception on failure. + * @param node the condition node for this wait + * @return previous sync state + */ + final long fullyRelease(Node node) { + boolean failed = true; + try { + long savedState = getState(); + if (release(savedState)) { + failed = false; + return savedState; + } else { + throw new IllegalMonitorStateException(); + } + } finally { + if (failed) + node.waitStatus = Node.CANCELLED; + } + } + + // Instrumentation methods for conditions + + /** + * Queries whether the given ConditionObject + * uses this synchronizer as its lock. + * + * @param condition the condition + * @return true if owned + * @throws NullPointerException if the condition is null + */ + public final boolean owns(ConditionObject condition) { + if (condition == null) + throw new NullPointerException(); + return condition.isOwnedBy(this); + } + + /** + * Queries whether any threads are waiting on the given condition + * associated with this synchronizer. Note that because timeouts + * and interrupts may occur at any time, a true return + * does not guarantee that a future signal will awaken + * any threads. This method is designed primarily for use in + * monitoring of the system state. + * + * @param condition the condition + * @return true if there are any waiting threads + * @throws IllegalMonitorStateException if exclusive synchronization + * is not held + * @throws IllegalArgumentException if the given condition is + * not associated with this synchronizer + * @throws NullPointerException if the condition is null + */ + public final boolean hasWaiters(ConditionObject condition) { + if (!owns(condition)) + throw new IllegalArgumentException("Not owner"); + return condition.hasWaiters(); + } + + /** + * Returns an estimate of the number of threads waiting on the + * given condition associated with this synchronizer. Note that + * because timeouts and interrupts may occur at any time, the + * estimate serves only as an upper bound on the actual number of + * waiters. This method is designed for use in monitoring of the + * system state, not for synchronization control. + * + * @param condition the condition + * @return the estimated number of waiting threads + * @throws IllegalMonitorStateException if exclusive synchronization + * is not held + * @throws IllegalArgumentException if the given condition is + * not associated with this synchronizer + * @throws NullPointerException if the condition is null + */ + public final int getWaitQueueLength(ConditionObject condition) { + if (!owns(condition)) + throw new IllegalArgumentException("Not owner"); + return condition.getWaitQueueLength(); + } + + /** + * Returns a collection containing those threads that may be + * waiting on the given condition associated with this + * synchronizer. Because the actual set of threads may change + * dynamically while constructing this result, the returned + * collection is only a best-effort estimate. The elements of the + * returned collection are in no particular order. + * + * @param condition the condition + * @return the collection of threads + * @throws IllegalMonitorStateException if exclusive synchronization + * is not held + * @throws IllegalArgumentException if the given condition is + * not associated with this synchronizer + * @throws NullPointerException if the condition is null + */ + public final Collection getWaitingThreads(ConditionObject condition) { + if (!owns(condition)) + throw new IllegalArgumentException("Not owner"); + return condition.getWaitingThreads(); + } + + /** + * Condition implementation for a {@link + * AbstractQueuedLongSynchronizer} serving as the basis of a {@link + * Lock} implementation. + * + *

Method documentation for this class describes mechanics, + * not behavioral specifications from the point of view of Lock + * and Condition users. Exported versions of this class will in + * general need to be accompanied by documentation describing + * condition semantics that rely on those of the associated + * AbstractQueuedLongSynchronizer. + * + *

This class is Serializable, but all fields are transient, + * so deserialized conditions have no waiters. + * + * @since 1.6 + */ + public class ConditionObject implements Condition, java.io.Serializable { + private static final long serialVersionUID = 1173984872572414699L; + /** First node of condition queue. */ + private transient Node firstWaiter; + /** Last node of condition queue. */ + private transient Node lastWaiter; + + /** + * Creates a new ConditionObject instance. + */ + public ConditionObject() { } + + // Internal methods + + /** + * Adds a new waiter to wait queue. + * @return its new wait node + */ + private Node addConditionWaiter() { + Node t = lastWaiter; + // If lastWaiter is cancelled, clean out. + if (t != null && t.waitStatus != Node.CONDITION) { + unlinkCancelledWaiters(); + t = lastWaiter; + } + Node node = new Node(Thread.currentThread(), Node.CONDITION); + if (t == null) + firstWaiter = node; + else + t.nextWaiter = node; + lastWaiter = node; + return node; + } + + /** + * Removes and transfers nodes until hit non-cancelled one or + * null. Split out from signal in part to encourage compilers + * to inline the case of no waiters. + * @param first (non-null) the first node on condition queue + */ + private void doSignal(Node first) { + do { + if ( (firstWaiter = first.nextWaiter) == null) + lastWaiter = null; + first.nextWaiter = null; + } while (!transferForSignal(first) && + (first = firstWaiter) != null); + } + + /** + * Removes and transfers all nodes. + * @param first (non-null) the first node on condition queue + */ + private void doSignalAll(Node first) { + lastWaiter = firstWaiter = null; + do { + Node next = first.nextWaiter; + first.nextWaiter = null; + transferForSignal(first); + first = next; + } while (first != null); + } + + /** + * Unlinks cancelled waiter nodes from condition queue. + * Called only while holding lock. This is called when + * cancellation occurred during condition wait, and upon + * insertion of a new waiter when lastWaiter is seen to have + * been cancelled. This method is needed to avoid garbage + * retention in the absence of signals. So even though it may + * require a full traversal, it comes into play only when + * timeouts or cancellations occur in the absence of + * signals. It traverses all nodes rather than stopping at a + * particular target to unlink all pointers to garbage nodes + * without requiring many re-traversals during cancellation + * storms. + */ + private void unlinkCancelledWaiters() { + Node t = firstWaiter; + Node trail = null; + while (t != null) { + Node next = t.nextWaiter; + if (t.waitStatus != Node.CONDITION) { + t.nextWaiter = null; + if (trail == null) + firstWaiter = next; + else + trail.nextWaiter = next; + if (next == null) + lastWaiter = trail; + } + else + trail = t; + t = next; + } + } + + // public methods + + /** + * Moves the longest-waiting thread, if one exists, from the + * wait queue for this condition to the wait queue for the + * owning lock. + * + * @throws IllegalMonitorStateException if {@link #isHeldExclusively} + * returns {@code false} + */ + public final void signal() { + if (!isHeldExclusively()) + throw new IllegalMonitorStateException(); + Node first = firstWaiter; + if (first != null) + doSignal(first); + } + + /** + * Moves all threads from the wait queue for this condition to + * the wait queue for the owning lock. + * + * @throws IllegalMonitorStateException if {@link #isHeldExclusively} + * returns {@code false} + */ + public final void signalAll() { + if (!isHeldExclusively()) + throw new IllegalMonitorStateException(); + Node first = firstWaiter; + if (first != null) + doSignalAll(first); + } + + /** + * Implements uninterruptible condition wait. + *

    + *
  1. Save lock state returned by {@link #getState}. + *
  2. Invoke {@link #release} with + * saved state as argument, throwing + * IllegalMonitorStateException if it fails. + *
  3. Block until signalled. + *
  4. Reacquire by invoking specialized version of + * {@link #acquire} with saved state as argument. + *
+ */ + public final void awaitUninterruptibly() { + Node node = addConditionWaiter(); + long savedState = fullyRelease(node); + boolean interrupted = false; + while (!isOnSyncQueue(node)) { + LockSupport.park(this); + if (Thread.interrupted()) + interrupted = true; + } + if (acquireQueued(node, savedState) || interrupted) + selfInterrupt(); + } + + /* + * For interruptible waits, we need to track whether to throw + * InterruptedException, if interrupted while blocked on + * condition, versus reinterrupt current thread, if + * interrupted while blocked waiting to re-acquire. + */ + + /** Mode meaning to reinterrupt on exit from wait */ + private static final int REINTERRUPT = 1; + /** Mode meaning to throw InterruptedException on exit from wait */ + private static final int THROW_IE = -1; + + /** + * Checks for interrupt, returning THROW_IE if interrupted + * before signalled, REINTERRUPT if after signalled, or + * 0 if not interrupted. + */ + private int checkInterruptWhileWaiting(Node node) { + return Thread.interrupted() ? + (transferAfterCancelledWait(node) ? THROW_IE : REINTERRUPT) : + 0; + } + + /** + * Throws InterruptedException, reinterrupts current thread, or + * does nothing, depending on mode. + */ + private void reportInterruptAfterWait(int interruptMode) + throws InterruptedException { + if (interruptMode == THROW_IE) + throw new InterruptedException(); + else if (interruptMode == REINTERRUPT) + selfInterrupt(); + } + + /** + * Implements interruptible condition wait. + *
    + *
  1. If current thread is interrupted, throw InterruptedException. + *
  2. Save lock state returned by {@link #getState}. + *
  3. Invoke {@link #release} with + * saved state as argument, throwing + * IllegalMonitorStateException if it fails. + *
  4. Block until signalled or interrupted. + *
  5. Reacquire by invoking specialized version of + * {@link #acquire} with saved state as argument. + *
  6. If interrupted while blocked in step 4, throw InterruptedException. + *
+ */ + public final void await() throws InterruptedException { + if (Thread.interrupted()) + throw new InterruptedException(); + Node node = addConditionWaiter(); + long savedState = fullyRelease(node); + int interruptMode = 0; + while (!isOnSyncQueue(node)) { + LockSupport.park(this); + if ((interruptMode = checkInterruptWhileWaiting(node)) != 0) + break; + } + if (acquireQueued(node, savedState) && interruptMode != THROW_IE) + interruptMode = REINTERRUPT; + if (node.nextWaiter != null) // clean up if cancelled + unlinkCancelledWaiters(); + if (interruptMode != 0) + reportInterruptAfterWait(interruptMode); + } + + /** + * Implements timed condition wait. + *
    + *
  1. If current thread is interrupted, throw InterruptedException. + *
  2. Save lock state returned by {@link #getState}. + *
  3. Invoke {@link #release} with + * saved state as argument, throwing + * IllegalMonitorStateException if it fails. + *
  4. Block until signalled, interrupted, or timed out. + *
  5. Reacquire by invoking specialized version of + * {@link #acquire} with saved state as argument. + *
  6. If interrupted while blocked in step 4, throw InterruptedException. + *
+ */ + public final long awaitNanos(long nanosTimeout) + throws InterruptedException { + if (Thread.interrupted()) + throw new InterruptedException(); + Node node = addConditionWaiter(); + long savedState = fullyRelease(node); + long lastTime = System.nanoTime(); + int interruptMode = 0; + while (!isOnSyncQueue(node)) { + if (nanosTimeout <= 0L) { + transferAfterCancelledWait(node); + break; + } + LockSupport.parkNanos(this, nanosTimeout); + if ((interruptMode = checkInterruptWhileWaiting(node)) != 0) + break; + + long now = System.nanoTime(); + nanosTimeout -= now - lastTime; + lastTime = now; + } + if (acquireQueued(node, savedState) && interruptMode != THROW_IE) + interruptMode = REINTERRUPT; + if (node.nextWaiter != null) + unlinkCancelledWaiters(); + if (interruptMode != 0) + reportInterruptAfterWait(interruptMode); + return nanosTimeout - (System.nanoTime() - lastTime); + } + + /** + * Implements absolute timed condition wait. + *
    + *
  1. If current thread is interrupted, throw InterruptedException. + *
  2. Save lock state returned by {@link #getState}. + *
  3. Invoke {@link #release} with + * saved state as argument, throwing + * IllegalMonitorStateException if it fails. + *
  4. Block until signalled, interrupted, or timed out. + *
  5. Reacquire by invoking specialized version of + * {@link #acquire} with saved state as argument. + *
  6. If interrupted while blocked in step 4, throw InterruptedException. + *
  7. If timed out while blocked in step 4, return false, else true. + *
+ */ + public final boolean awaitUntil(Date deadline) + throws InterruptedException { + if (deadline == null) + throw new NullPointerException(); + long abstime = deadline.getTime(); + if (Thread.interrupted()) + throw new InterruptedException(); + Node node = addConditionWaiter(); + long savedState = fullyRelease(node); + boolean timedout = false; + int interruptMode = 0; + while (!isOnSyncQueue(node)) { + if (System.currentTimeMillis() > abstime) { + timedout = transferAfterCancelledWait(node); + break; + } + LockSupport.parkUntil(this, abstime); + if ((interruptMode = checkInterruptWhileWaiting(node)) != 0) + break; + } + if (acquireQueued(node, savedState) && interruptMode != THROW_IE) + interruptMode = REINTERRUPT; + if (node.nextWaiter != null) + unlinkCancelledWaiters(); + if (interruptMode != 0) + reportInterruptAfterWait(interruptMode); + return !timedout; + } + + /** + * Implements timed condition wait. + *
    + *
  1. If current thread is interrupted, throw InterruptedException. + *
  2. Save lock state returned by {@link #getState}. + *
  3. Invoke {@link #release} with + * saved state as argument, throwing + * IllegalMonitorStateException if it fails. + *
  4. Block until signalled, interrupted, or timed out. + *
  5. Reacquire by invoking specialized version of + * {@link #acquire} with saved state as argument. + *
  6. If interrupted while blocked in step 4, throw InterruptedException. + *
  7. If timed out while blocked in step 4, return false, else true. + *
+ */ + public final boolean await(long time, TimeUnit unit) + throws InterruptedException { + if (unit == null) + throw new NullPointerException(); + long nanosTimeout = unit.toNanos(time); + if (Thread.interrupted()) + throw new InterruptedException(); + Node node = addConditionWaiter(); + long savedState = fullyRelease(node); + long lastTime = System.nanoTime(); + boolean timedout = false; + int interruptMode = 0; + while (!isOnSyncQueue(node)) { + if (nanosTimeout <= 0L) { + timedout = transferAfterCancelledWait(node); + break; + } + if (nanosTimeout >= spinForTimeoutThreshold) + LockSupport.parkNanos(this, nanosTimeout); + if ((interruptMode = checkInterruptWhileWaiting(node)) != 0) + break; + long now = System.nanoTime(); + nanosTimeout -= now - lastTime; + lastTime = now; + } + if (acquireQueued(node, savedState) && interruptMode != THROW_IE) + interruptMode = REINTERRUPT; + if (node.nextWaiter != null) + unlinkCancelledWaiters(); + if (interruptMode != 0) + reportInterruptAfterWait(interruptMode); + return !timedout; + } + + // support for instrumentation + + /** + * Returns true if this condition was created by the given + * synchronization object. + * + * @return {@code true} if owned + */ + final boolean isOwnedBy(AbstractQueuedLongSynchronizer sync) { + return sync == AbstractQueuedLongSynchronizer.this; + } + + /** + * Queries whether any threads are waiting on this condition. + * Implements {@link AbstractQueuedLongSynchronizer#hasWaiters}. + * + * @return {@code true} if there are any waiting threads + * @throws IllegalMonitorStateException if {@link #isHeldExclusively} + * returns {@code false} + */ + protected final boolean hasWaiters() { + if (!isHeldExclusively()) + throw new IllegalMonitorStateException(); + for (Node w = firstWaiter; w != null; w = w.nextWaiter) { + if (w.waitStatus == Node.CONDITION) + return true; + } + return false; + } + + /** + * Returns an estimate of the number of threads waiting on + * this condition. + * Implements {@link AbstractQueuedLongSynchronizer#getWaitQueueLength}. + * + * @return the estimated number of waiting threads + * @throws IllegalMonitorStateException if {@link #isHeldExclusively} + * returns {@code false} + */ + protected final int getWaitQueueLength() { + if (!isHeldExclusively()) + throw new IllegalMonitorStateException(); + int n = 0; + for (Node w = firstWaiter; w != null; w = w.nextWaiter) { + if (w.waitStatus == Node.CONDITION) + ++n; + } + return n; + } + + /** + * Returns a collection containing those threads that may be + * waiting on this Condition. + * Implements {@link AbstractQueuedLongSynchronizer#getWaitingThreads}. + * + * @return the collection of threads + * @throws IllegalMonitorStateException if {@link #isHeldExclusively} + * returns {@code false} + */ + protected final Collection getWaitingThreads() { + if (!isHeldExclusively()) + throw new IllegalMonitorStateException(); + ArrayList list = new ArrayList(); + for (Node w = firstWaiter; w != null; w = w.nextWaiter) { + if (w.waitStatus == Node.CONDITION) { + Thread t = w.thread; + if (t != null) + list.add(t); + } + } + return list; + } + } + + /** + * Setup to support compareAndSet. We need to natively implement + * this here: For the sake of permitting future enhancements, we + * cannot explicitly subclass AtomicLong, which would be + * efficient and useful otherwise. So, as the lesser of evils, we + * natively implement using hotspot intrinsics API. And while we + * are at it, we do the same for other CASable fields (which could + * otherwise be done with atomic field updaters). + */ + private static final Unsafe unsafe = Unsafe.getUnsafe(); + private static final long stateOffset; + private static final long headOffset; + private static final long tailOffset; + private static final long waitStatusOffset; + private static final long nextOffset; + + static { + try { + stateOffset = unsafe.objectFieldOffset + (AbstractQueuedLongSynchronizer.class.getDeclaredField("state")); + headOffset = unsafe.objectFieldOffset + (AbstractQueuedLongSynchronizer.class.getDeclaredField("head")); + tailOffset = unsafe.objectFieldOffset + (AbstractQueuedLongSynchronizer.class.getDeclaredField("tail")); + waitStatusOffset = unsafe.objectFieldOffset + (Node.class.getDeclaredField("waitStatus")); + nextOffset = unsafe.objectFieldOffset + (Node.class.getDeclaredField("next")); + + } catch (Exception ex) { throw new Error(ex); } + } + + /** + * CAS head field. Used only by enq. + */ + private final boolean compareAndSetHead(Node update) { + return unsafe.compareAndSwapObject(this, headOffset, null, update); + } + + /** + * CAS tail field. Used only by enq. + */ + private final boolean compareAndSetTail(Node expect, Node update) { + return unsafe.compareAndSwapObject(this, tailOffset, expect, update); + } + + /** + * CAS waitStatus field of a node. + */ + private static final boolean compareAndSetWaitStatus(Node node, + int expect, + int update) { + return unsafe.compareAndSwapInt(node, waitStatusOffset, + expect, update); + } + + /** + * CAS next field of a node. + */ + private static final boolean compareAndSetNext(Node node, + Node expect, + Node update) { + return unsafe.compareAndSwapObject(node, nextOffset, expect, update); + } +} diff -r e1953d8b8338 -r c8af252ea9eb rt/emul/compact/src/main/java/java/util/concurrent/locks/AbstractQueuedSynchronizer.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/locks/AbstractQueuedSynchronizer.java Sat Mar 19 10:48:29 2016 +0100 @@ -0,0 +1,2330 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +package java.util.concurrent.locks; +import java.util.*; +import java.util.concurrent.*; +import java.util.concurrent.atomic.*; +import sun.misc.Unsafe; + +/** + * Provides a framework for implementing blocking locks and related + * synchronizers (semaphores, events, etc) that rely on + * first-in-first-out (FIFO) wait queues. This class is designed to + * be a useful basis for most kinds of synchronizers that rely on a + * single atomic int value to represent state. Subclasses + * must define the protected methods that change this state, and which + * define what that state means in terms of this object being acquired + * or released. Given these, the other methods in this class carry + * out all queuing and blocking mechanics. Subclasses can maintain + * other state fields, but only the atomically updated int + * value manipulated using methods {@link #getState}, {@link + * #setState} and {@link #compareAndSetState} is tracked with respect + * to synchronization. + * + *

Subclasses should be defined as non-public internal helper + * classes that are used to implement the synchronization properties + * of their enclosing class. Class + * AbstractQueuedSynchronizer does not implement any + * synchronization interface. Instead it defines methods such as + * {@link #acquireInterruptibly} that can be invoked as + * appropriate by concrete locks and related synchronizers to + * implement their public methods. + * + *

This class supports either or both a default exclusive + * mode and a shared mode. When acquired in exclusive mode, + * attempted acquires by other threads cannot succeed. Shared mode + * acquires by multiple threads may (but need not) succeed. This class + * does not "understand" these differences except in the + * mechanical sense that when a shared mode acquire succeeds, the next + * waiting thread (if one exists) must also determine whether it can + * acquire as well. Threads waiting in the different modes share the + * same FIFO queue. Usually, implementation subclasses support only + * one of these modes, but both can come into play for example in a + * {@link ReadWriteLock}. Subclasses that support only exclusive or + * only shared modes need not define the methods supporting the unused mode. + * + *

This class defines a nested {@link ConditionObject} class that + * can be used as a {@link Condition} implementation by subclasses + * supporting exclusive mode for which method {@link + * #isHeldExclusively} reports whether synchronization is exclusively + * held with respect to the current thread, method {@link #release} + * invoked with the current {@link #getState} value fully releases + * this object, and {@link #acquire}, given this saved state value, + * eventually restores this object to its previous acquired state. No + * AbstractQueuedSynchronizer method otherwise creates such a + * condition, so if this constraint cannot be met, do not use it. The + * behavior of {@link ConditionObject} depends of course on the + * semantics of its synchronizer implementation. + * + *

This class provides inspection, instrumentation, and monitoring + * methods for the internal queue, as well as similar methods for + * condition objects. These can be exported as desired into classes + * using an AbstractQueuedSynchronizer for their + * synchronization mechanics. + * + *

Serialization of this class stores only the underlying atomic + * integer maintaining state, so deserialized objects have empty + * thread queues. Typical subclasses requiring serializability will + * define a readObject method that restores this to a known + * initial state upon deserialization. + * + *

Usage

+ * + *

To use this class as the basis of a synchronizer, redefine the + * following methods, as applicable, by inspecting and/or modifying + * the synchronization state using {@link #getState}, {@link + * #setState} and/or {@link #compareAndSetState}: + * + *

    + *
  • {@link #tryAcquire} + *
  • {@link #tryRelease} + *
  • {@link #tryAcquireShared} + *
  • {@link #tryReleaseShared} + *
  • {@link #isHeldExclusively} + *
+ * + * Each of these methods by default throws {@link + * UnsupportedOperationException}. Implementations of these methods + * must be internally thread-safe, and should in general be short and + * not block. Defining these methods is the only supported + * means of using this class. All other methods are declared + * final because they cannot be independently varied. + * + *

You may also find the inherited methods from {@link + * AbstractOwnableSynchronizer} useful to keep track of the thread + * owning an exclusive synchronizer. You are encouraged to use them + * -- this enables monitoring and diagnostic tools to assist users in + * determining which threads hold locks. + * + *

Even though this class is based on an internal FIFO queue, it + * does not automatically enforce FIFO acquisition policies. The core + * of exclusive synchronization takes the form: + * + *

+ * Acquire:
+ *     while (!tryAcquire(arg)) {
+ *        enqueue thread if it is not already queued;
+ *        possibly block current thread;
+ *     }
+ *
+ * Release:
+ *     if (tryRelease(arg))
+ *        unblock the first queued thread;
+ * 
+ * + * (Shared mode is similar but may involve cascading signals.) + * + *

Because checks in acquire are invoked before + * enqueuing, a newly acquiring thread may barge ahead of + * others that are blocked and queued. However, you can, if desired, + * define tryAcquire and/or tryAcquireShared to + * disable barging by internally invoking one or more of the inspection + * methods, thereby providing a fair FIFO acquisition order. + * In particular, most fair synchronizers can define tryAcquire + * to return false if {@link #hasQueuedPredecessors} (a method + * specifically designed to be used by fair synchronizers) returns + * true. Other variations are possible. + * + *

Throughput and scalability are generally highest for the + * default barging (also known as greedy, + * renouncement, and convoy-avoidance) strategy. + * While this is not guaranteed to be fair or starvation-free, earlier + * queued threads are allowed to recontend before later queued + * threads, and each recontention has an unbiased chance to succeed + * against incoming threads. Also, while acquires do not + * "spin" in the usual sense, they may perform multiple + * invocations of tryAcquire interspersed with other + * computations before blocking. This gives most of the benefits of + * spins when exclusive synchronization is only briefly held, without + * most of the liabilities when it isn't. If so desired, you can + * augment this by preceding calls to acquire methods with + * "fast-path" checks, possibly prechecking {@link #hasContended} + * and/or {@link #hasQueuedThreads} to only do so if the synchronizer + * is likely not to be contended. + * + *

This class provides an efficient and scalable basis for + * synchronization in part by specializing its range of use to + * synchronizers that can rely on int state, acquire, and + * release parameters, and an internal FIFO wait queue. When this does + * not suffice, you can build synchronizers from a lower level using + * {@link java.util.concurrent.atomic atomic} classes, your own custom + * {@link java.util.Queue} classes, and {@link LockSupport} blocking + * support. + * + *

Usage Examples

+ * + *

Here is a non-reentrant mutual exclusion lock class that uses + * the value zero to represent the unlocked state, and one to + * represent the locked state. While a non-reentrant lock + * does not strictly require recording of the current owner + * thread, this class does so anyway to make usage easier to monitor. + * It also supports conditions and exposes + * one of the instrumentation methods: + * + *

+ * class Mutex implements Lock, java.io.Serializable {
+ *
+ *   // Our internal helper class
+ *   private static class Sync extends AbstractQueuedSynchronizer {
+ *     // Report whether in locked state
+ *     protected boolean isHeldExclusively() {
+ *       return getState() == 1;
+ *     }
+ *
+ *     // Acquire the lock if state is zero
+ *     public boolean tryAcquire(int acquires) {
+ *       assert acquires == 1; // Otherwise unused
+ *       if (compareAndSetState(0, 1)) {
+ *         setExclusiveOwnerThread(Thread.currentThread());
+ *         return true;
+ *       }
+ *       return false;
+ *     }
+ *
+ *     // Release the lock by setting state to zero
+ *     protected boolean tryRelease(int releases) {
+ *       assert releases == 1; // Otherwise unused
+ *       if (getState() == 0) throw new IllegalMonitorStateException();
+ *       setExclusiveOwnerThread(null);
+ *       setState(0);
+ *       return true;
+ *     }
+ *
+ *     // Provide a Condition
+ *     Condition newCondition() { return new ConditionObject(); }
+ *
+ *     // Deserialize properly
+ *     private void readObject(ObjectInputStream s)
+ *         throws IOException, ClassNotFoundException {
+ *       s.defaultReadObject();
+ *       setState(0); // reset to unlocked state
+ *     }
+ *   }
+ *
+ *   // The sync object does all the hard work. We just forward to it.
+ *   private final Sync sync = new Sync();
+ *
+ *   public void lock()                { sync.acquire(1); }
+ *   public boolean tryLock()          { return sync.tryAcquire(1); }
+ *   public void unlock()              { sync.release(1); }
+ *   public Condition newCondition()   { return sync.newCondition(); }
+ *   public boolean isLocked()         { return sync.isHeldExclusively(); }
+ *   public boolean hasQueuedThreads() { return sync.hasQueuedThreads(); }
+ *   public void lockInterruptibly() throws InterruptedException {
+ *     sync.acquireInterruptibly(1);
+ *   }
+ *   public boolean tryLock(long timeout, TimeUnit unit)
+ *       throws InterruptedException {
+ *     return sync.tryAcquireNanos(1, unit.toNanos(timeout));
+ *   }
+ * }
+ * 
+ * + *

Here is a latch class that is like a {@link CountDownLatch} + * except that it only requires a single signal to + * fire. Because a latch is non-exclusive, it uses the shared + * acquire and release methods. + * + *

+ * class BooleanLatch {
+ *
+ *   private static class Sync extends AbstractQueuedSynchronizer {
+ *     boolean isSignalled() { return getState() != 0; }
+ *
+ *     protected int tryAcquireShared(int ignore) {
+ *       return isSignalled() ? 1 : -1;
+ *     }
+ *
+ *     protected boolean tryReleaseShared(int ignore) {
+ *       setState(1);
+ *       return true;
+ *     }
+ *   }
+ *
+ *   private final Sync sync = new Sync();
+ *   public boolean isSignalled() { return sync.isSignalled(); }
+ *   public void signal()         { sync.releaseShared(1); }
+ *   public void await() throws InterruptedException {
+ *     sync.acquireSharedInterruptibly(1);
+ *   }
+ * }
+ * 
+ * + * @since 1.5 + * @author Doug Lea + */ +public abstract class AbstractQueuedSynchronizer + extends AbstractOwnableSynchronizer + implements java.io.Serializable { + + private static final long serialVersionUID = 7373984972572414691L; + + /** + * Creates a new AbstractQueuedSynchronizer instance + * with initial synchronization state of zero. + */ + protected AbstractQueuedSynchronizer() { } + + /** + * Wait queue node class. + * + *

The wait queue is a variant of a "CLH" (Craig, Landin, and + * Hagersten) lock queue. CLH locks are normally used for + * spinlocks. We instead use them for blocking synchronizers, but + * use the same basic tactic of holding some of the control + * information about a thread in the predecessor of its node. A + * "status" field in each node keeps track of whether a thread + * should block. A node is signalled when its predecessor + * releases. Each node of the queue otherwise serves as a + * specific-notification-style monitor holding a single waiting + * thread. The status field does NOT control whether threads are + * granted locks etc though. A thread may try to acquire if it is + * first in the queue. But being first does not guarantee success; + * it only gives the right to contend. So the currently released + * contender thread may need to rewait. + * + *

To enqueue into a CLH lock, you atomically splice it in as new + * tail. To dequeue, you just set the head field. + *

+     *      +------+  prev +-----+       +-----+
+     * head |      | <---- |     | <---- |     |  tail
+     *      +------+       +-----+       +-----+
+     * 
+ * + *

Insertion into a CLH queue requires only a single atomic + * operation on "tail", so there is a simple atomic point of + * demarcation from unqueued to queued. Similarly, dequeing + * involves only updating the "head". However, it takes a bit + * more work for nodes to determine who their successors are, + * in part to deal with possible cancellation due to timeouts + * and interrupts. + * + *

The "prev" links (not used in original CLH locks), are mainly + * needed to handle cancellation. If a node is cancelled, its + * successor is (normally) relinked to a non-cancelled + * predecessor. For explanation of similar mechanics in the case + * of spin locks, see the papers by Scott and Scherer at + * http://www.cs.rochester.edu/u/scott/synchronization/ + * + *

We also use "next" links to implement blocking mechanics. + * The thread id for each node is kept in its own node, so a + * predecessor signals the next node to wake up by traversing + * next link to determine which thread it is. Determination of + * successor must avoid races with newly queued nodes to set + * the "next" fields of their predecessors. This is solved + * when necessary by checking backwards from the atomically + * updated "tail" when a node's successor appears to be null. + * (Or, said differently, the next-links are an optimization + * so that we don't usually need a backward scan.) + * + *

Cancellation introduces some conservatism to the basic + * algorithms. Since we must poll for cancellation of other + * nodes, we can miss noticing whether a cancelled node is + * ahead or behind us. This is dealt with by always unparking + * successors upon cancellation, allowing them to stabilize on + * a new predecessor, unless we can identify an uncancelled + * predecessor who will carry this responsibility. + * + *

CLH queues need a dummy header node to get started. But + * we don't create them on construction, because it would be wasted + * effort if there is never contention. Instead, the node + * is constructed and head and tail pointers are set upon first + * contention. + * + *

Threads waiting on Conditions use the same nodes, but + * use an additional link. Conditions only need to link nodes + * in simple (non-concurrent) linked queues because they are + * only accessed when exclusively held. Upon await, a node is + * inserted into a condition queue. Upon signal, the node is + * transferred to the main queue. A special value of status + * field is used to mark which queue a node is on. + * + *

Thanks go to Dave Dice, Mark Moir, Victor Luchangco, Bill + * Scherer and Michael Scott, along with members of JSR-166 + * expert group, for helpful ideas, discussions, and critiques + * on the design of this class. + */ + static final class Node { + /** Marker to indicate a node is waiting in shared mode */ + static final Node SHARED = new Node(); + /** Marker to indicate a node is waiting in exclusive mode */ + static final Node EXCLUSIVE = null; + + /** waitStatus value to indicate thread has cancelled */ + static final int CANCELLED = 1; + /** waitStatus value to indicate successor's thread needs unparking */ + static final int SIGNAL = -1; + /** waitStatus value to indicate thread is waiting on condition */ + static final int CONDITION = -2; + /** + * waitStatus value to indicate the next acquireShared should + * unconditionally propagate + */ + static final int PROPAGATE = -3; + + /** + * Status field, taking on only the values: + * SIGNAL: The successor of this node is (or will soon be) + * blocked (via park), so the current node must + * unpark its successor when it releases or + * cancels. To avoid races, acquire methods must + * first indicate they need a signal, + * then retry the atomic acquire, and then, + * on failure, block. + * CANCELLED: This node is cancelled due to timeout or interrupt. + * Nodes never leave this state. In particular, + * a thread with cancelled node never again blocks. + * CONDITION: This node is currently on a condition queue. + * It will not be used as a sync queue node + * until transferred, at which time the status + * will be set to 0. (Use of this value here has + * nothing to do with the other uses of the + * field, but simplifies mechanics.) + * PROPAGATE: A releaseShared should be propagated to other + * nodes. This is set (for head node only) in + * doReleaseShared to ensure propagation + * continues, even if other operations have + * since intervened. + * 0: None of the above + * + * The values are arranged numerically to simplify use. + * Non-negative values mean that a node doesn't need to + * signal. So, most code doesn't need to check for particular + * values, just for sign. + * + * The field is initialized to 0 for normal sync nodes, and + * CONDITION for condition nodes. It is modified using CAS + * (or when possible, unconditional volatile writes). + */ + volatile int waitStatus; + + /** + * Link to predecessor node that current node/thread relies on + * for checking waitStatus. Assigned during enqueing, and nulled + * out (for sake of GC) only upon dequeuing. Also, upon + * cancellation of a predecessor, we short-circuit while + * finding a non-cancelled one, which will always exist + * because the head node is never cancelled: A node becomes + * head only as a result of successful acquire. A + * cancelled thread never succeeds in acquiring, and a thread only + * cancels itself, not any other node. + */ + volatile Node prev; + + /** + * Link to the successor node that the current node/thread + * unparks upon release. Assigned during enqueuing, adjusted + * when bypassing cancelled predecessors, and nulled out (for + * sake of GC) when dequeued. The enq operation does not + * assign next field of a predecessor until after attachment, + * so seeing a null next field does not necessarily mean that + * node is at end of queue. However, if a next field appears + * to be null, we can scan prev's from the tail to + * double-check. The next field of cancelled nodes is set to + * point to the node itself instead of null, to make life + * easier for isOnSyncQueue. + */ + volatile Node next; + + /** + * The thread that enqueued this node. Initialized on + * construction and nulled out after use. + */ + volatile Thread thread; + + /** + * Link to next node waiting on condition, or the special + * value SHARED. Because condition queues are accessed only + * when holding in exclusive mode, we just need a simple + * linked queue to hold nodes while they are waiting on + * conditions. They are then transferred to the queue to + * re-acquire. And because conditions can only be exclusive, + * we save a field by using special value to indicate shared + * mode. + */ + Node nextWaiter; + + /** + * Returns true if node is waiting in shared mode + */ + final boolean isShared() { + return nextWaiter == SHARED; + } + + /** + * Returns previous node, or throws NullPointerException if null. + * Use when predecessor cannot be null. The null check could + * be elided, but is present to help the VM. + * + * @return the predecessor of this node + */ + final Node predecessor() throws NullPointerException { + Node p = prev; + if (p == null) + throw new NullPointerException(); + else + return p; + } + + Node() { // Used to establish initial head or SHARED marker + } + + Node(Thread thread, Node mode) { // Used by addWaiter + this.nextWaiter = mode; + this.thread = thread; + } + + Node(Thread thread, int waitStatus) { // Used by Condition + this.waitStatus = waitStatus; + this.thread = thread; + } + } + + /** + * Head of the wait queue, lazily initialized. Except for + * initialization, it is modified only via method setHead. Note: + * If head exists, its waitStatus is guaranteed not to be + * CANCELLED. + */ + private transient volatile Node head; + + /** + * Tail of the wait queue, lazily initialized. Modified only via + * method enq to add new wait node. + */ + private transient volatile Node tail; + + /** + * The synchronization state. + */ + private volatile int state; + + /** + * Returns the current value of synchronization state. + * This operation has memory semantics of a volatile read. + * @return current state value + */ + protected final int getState() { + return state; + } + + /** + * Sets the value of synchronization state. + * This operation has memory semantics of a volatile write. + * @param newState the new state value + */ + protected final void setState(int newState) { + state = newState; + } + + /** + * Atomically sets synchronization state to the given updated + * value if the current state value equals the expected value. + * This operation has memory semantics of a volatile read + * and write. + * + * @param expect the expected value + * @param update the new value + * @return true if successful. False return indicates that the actual + * value was not equal to the expected value. + */ + protected final boolean compareAndSetState(int expect, int update) { + // See below for intrinsics setup to support this + return unsafe.compareAndSwapInt(this, stateOffset, expect, update); + } + + // Queuing utilities + + /** + * The number of nanoseconds for which it is faster to spin + * rather than to use timed park. A rough estimate suffices + * to improve responsiveness with very short timeouts. + */ + static final long spinForTimeoutThreshold = 1000L; + + /** + * Inserts node into queue, initializing if necessary. See picture above. + * @param node the node to insert + * @return node's predecessor + */ + private Node enq(final Node node) { + for (;;) { + Node t = tail; + if (t == null) { // Must initialize + if (compareAndSetHead(new Node())) + tail = head; + } else { + node.prev = t; + if (compareAndSetTail(t, node)) { + t.next = node; + return t; + } + } + } + } + + /** + * Creates and enqueues node for current thread and given mode. + * + * @param mode Node.EXCLUSIVE for exclusive, Node.SHARED for shared + * @return the new node + */ + private Node addWaiter(Node mode) { + Node node = new Node(Thread.currentThread(), mode); + // Try the fast path of enq; backup to full enq on failure + Node pred = tail; + if (pred != null) { + node.prev = pred; + if (compareAndSetTail(pred, node)) { + pred.next = node; + return node; + } + } + enq(node); + return node; + } + + /** + * Sets head of queue to be node, thus dequeuing. Called only by + * acquire methods. Also nulls out unused fields for sake of GC + * and to suppress unnecessary signals and traversals. + * + * @param node the node + */ + private void setHead(Node node) { + head = node; + node.thread = null; + node.prev = null; + } + + /** + * Wakes up node's successor, if one exists. + * + * @param node the node + */ + private void unparkSuccessor(Node node) { + /* + * If status is negative (i.e., possibly needing signal) try + * to clear in anticipation of signalling. It is OK if this + * fails or if status is changed by waiting thread. + */ + int ws = node.waitStatus; + if (ws < 0) + compareAndSetWaitStatus(node, ws, 0); + + /* + * Thread to unpark is held in successor, which is normally + * just the next node. But if cancelled or apparently null, + * traverse backwards from tail to find the actual + * non-cancelled successor. + */ + Node s = node.next; + if (s == null || s.waitStatus > 0) { + s = null; + for (Node t = tail; t != null && t != node; t = t.prev) + if (t.waitStatus <= 0) + s = t; + } + if (s != null) + LockSupport.unpark(s.thread); + } + + /** + * Release action for shared mode -- signal successor and ensure + * propagation. (Note: For exclusive mode, release just amounts + * to calling unparkSuccessor of head if it needs signal.) + */ + private void doReleaseShared() { + /* + * Ensure that a release propagates, even if there are other + * in-progress acquires/releases. This proceeds in the usual + * way of trying to unparkSuccessor of head if it needs + * signal. But if it does not, status is set to PROPAGATE to + * ensure that upon release, propagation continues. + * Additionally, we must loop in case a new node is added + * while we are doing this. Also, unlike other uses of + * unparkSuccessor, we need to know if CAS to reset status + * fails, if so rechecking. + */ + for (;;) { + Node h = head; + if (h != null && h != tail) { + int ws = h.waitStatus; + if (ws == Node.SIGNAL) { + if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0)) + continue; // loop to recheck cases + unparkSuccessor(h); + } + else if (ws == 0 && + !compareAndSetWaitStatus(h, 0, Node.PROPAGATE)) + continue; // loop on failed CAS + } + if (h == head) // loop if head changed + break; + } + } + + /** + * Sets head of queue, and checks if successor may be waiting + * in shared mode, if so propagating if either propagate > 0 or + * PROPAGATE status was set. + * + * @param node the node + * @param propagate the return value from a tryAcquireShared + */ + private void setHeadAndPropagate(Node node, int propagate) { + Node h = head; // Record old head for check below + setHead(node); + /* + * Try to signal next queued node if: + * Propagation was indicated by caller, + * or was recorded (as h.waitStatus) by a previous operation + * (note: this uses sign-check of waitStatus because + * PROPAGATE status may transition to SIGNAL.) + * and + * The next node is waiting in shared mode, + * or we don't know, because it appears null + * + * The conservatism in both of these checks may cause + * unnecessary wake-ups, but only when there are multiple + * racing acquires/releases, so most need signals now or soon + * anyway. + */ + if (propagate > 0 || h == null || h.waitStatus < 0) { + Node s = node.next; + if (s == null || s.isShared()) + doReleaseShared(); + } + } + + // Utilities for various versions of acquire + + /** + * Cancels an ongoing attempt to acquire. + * + * @param node the node + */ + private void cancelAcquire(Node node) { + // Ignore if node doesn't exist + if (node == null) + return; + + node.thread = null; + + // Skip cancelled predecessors + Node pred = node.prev; + while (pred.waitStatus > 0) + node.prev = pred = pred.prev; + + // predNext is the apparent node to unsplice. CASes below will + // fail if not, in which case, we lost race vs another cancel + // or signal, so no further action is necessary. + Node predNext = pred.next; + + // Can use unconditional write instead of CAS here. + // After this atomic step, other Nodes can skip past us. + // Before, we are free of interference from other threads. + node.waitStatus = Node.CANCELLED; + + // If we are the tail, remove ourselves. + if (node == tail && compareAndSetTail(node, pred)) { + compareAndSetNext(pred, predNext, null); + } else { + // If successor needs signal, try to set pred's next-link + // so it will get one. Otherwise wake it up to propagate. + int ws; + if (pred != head && + ((ws = pred.waitStatus) == Node.SIGNAL || + (ws <= 0 && compareAndSetWaitStatus(pred, ws, Node.SIGNAL))) && + pred.thread != null) { + Node next = node.next; + if (next != null && next.waitStatus <= 0) + compareAndSetNext(pred, predNext, next); + } else { + unparkSuccessor(node); + } + + node.next = node; // help GC + } + } + + /** + * Checks and updates status for a node that failed to acquire. + * Returns true if thread should block. This is the main signal + * control in all acquire loops. Requires that pred == node.prev + * + * @param pred node's predecessor holding status + * @param node the node + * @return {@code true} if thread should block + */ + private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) { + int ws = pred.waitStatus; + if (ws == Node.SIGNAL) + /* + * This node has already set status asking a release + * to signal it, so it can safely park. + */ + return true; + if (ws > 0) { + /* + * Predecessor was cancelled. Skip over predecessors and + * indicate retry. + */ + do { + node.prev = pred = pred.prev; + } while (pred.waitStatus > 0); + pred.next = node; + } else { + /* + * waitStatus must be 0 or PROPAGATE. Indicate that we + * need a signal, but don't park yet. Caller will need to + * retry to make sure it cannot acquire before parking. + */ + compareAndSetWaitStatus(pred, ws, Node.SIGNAL); + } + return false; + } + + /** + * Convenience method to interrupt current thread. + */ + private static void selfInterrupt() { + Thread.currentThread().interrupt(); + } + + /** + * Convenience method to park and then check if interrupted + * + * @return {@code true} if interrupted + */ + private final boolean parkAndCheckInterrupt() { + LockSupport.park(this); + return Thread.interrupted(); + } + + /* + * Various flavors of acquire, varying in exclusive/shared and + * control modes. Each is mostly the same, but annoyingly + * different. Only a little bit of factoring is possible due to + * interactions of exception mechanics (including ensuring that we + * cancel if tryAcquire throws exception) and other control, at + * least not without hurting performance too much. + */ + + /** + * Acquires in exclusive uninterruptible mode for thread already in + * queue. Used by condition wait methods as well as acquire. + * + * @param node the node + * @param arg the acquire argument + * @return {@code true} if interrupted while waiting + */ + final boolean acquireQueued(final Node node, int arg) { + boolean failed = true; + try { + boolean interrupted = false; + for (;;) { + final Node p = node.predecessor(); + if (p == head && tryAcquire(arg)) { + setHead(node); + p.next = null; // help GC + failed = false; + return interrupted; + } + if (shouldParkAfterFailedAcquire(p, node) && + parkAndCheckInterrupt()) + interrupted = true; + } + } finally { + if (failed) + cancelAcquire(node); + } + } + + /** + * Acquires in exclusive interruptible mode. + * @param arg the acquire argument + */ + private void doAcquireInterruptibly(int arg) + throws InterruptedException { + final Node node = addWaiter(Node.EXCLUSIVE); + boolean failed = true; + try { + for (;;) { + final Node p = node.predecessor(); + if (p == head && tryAcquire(arg)) { + setHead(node); + p.next = null; // help GC + failed = false; + return; + } + if (shouldParkAfterFailedAcquire(p, node) && + parkAndCheckInterrupt()) + throw new InterruptedException(); + } + } finally { + if (failed) + cancelAcquire(node); + } + } + + /** + * Acquires in exclusive timed mode. + * + * @param arg the acquire argument + * @param nanosTimeout max wait time + * @return {@code true} if acquired + */ + private boolean doAcquireNanos(int arg, long nanosTimeout) + throws InterruptedException { + long lastTime = System.nanoTime(); + final Node node = addWaiter(Node.EXCLUSIVE); + boolean failed = true; + try { + for (;;) { + final Node p = node.predecessor(); + if (p == head && tryAcquire(arg)) { + setHead(node); + p.next = null; // help GC + failed = false; + return true; + } + if (nanosTimeout <= 0) + return false; + if (shouldParkAfterFailedAcquire(p, node) && + nanosTimeout > spinForTimeoutThreshold) + LockSupport.parkNanos(this, nanosTimeout); + long now = System.nanoTime(); + nanosTimeout -= now - lastTime; + lastTime = now; + if (Thread.interrupted()) + throw new InterruptedException(); + } + } finally { + if (failed) + cancelAcquire(node); + } + } + + /** + * Acquires in shared uninterruptible mode. + * @param arg the acquire argument + */ + private void doAcquireShared(int arg) { + final Node node = addWaiter(Node.SHARED); + boolean failed = true; + try { + boolean interrupted = false; + for (;;) { + final Node p = node.predecessor(); + if (p == head) { + int r = tryAcquireShared(arg); + if (r >= 0) { + setHeadAndPropagate(node, r); + p.next = null; // help GC + if (interrupted) + selfInterrupt(); + failed = false; + return; + } + } + if (shouldParkAfterFailedAcquire(p, node) && + parkAndCheckInterrupt()) + interrupted = true; + } + } finally { + if (failed) + cancelAcquire(node); + } + } + + /** + * Acquires in shared interruptible mode. + * @param arg the acquire argument + */ + private void doAcquireSharedInterruptibly(int arg) + throws InterruptedException { + final Node node = addWaiter(Node.SHARED); + boolean failed = true; + try { + for (;;) { + final Node p = node.predecessor(); + if (p == head) { + int r = tryAcquireShared(arg); + if (r >= 0) { + setHeadAndPropagate(node, r); + p.next = null; // help GC + failed = false; + return; + } + } + if (shouldParkAfterFailedAcquire(p, node) && + parkAndCheckInterrupt()) + throw new InterruptedException(); + } + } finally { + if (failed) + cancelAcquire(node); + } + } + + /** + * Acquires in shared timed mode. + * + * @param arg the acquire argument + * @param nanosTimeout max wait time + * @return {@code true} if acquired + */ + private boolean doAcquireSharedNanos(int arg, long nanosTimeout) + throws InterruptedException { + + long lastTime = System.nanoTime(); + final Node node = addWaiter(Node.SHARED); + boolean failed = true; + try { + for (;;) { + final Node p = node.predecessor(); + if (p == head) { + int r = tryAcquireShared(arg); + if (r >= 0) { + setHeadAndPropagate(node, r); + p.next = null; // help GC + failed = false; + return true; + } + } + if (nanosTimeout <= 0) + return false; + if (shouldParkAfterFailedAcquire(p, node) && + nanosTimeout > spinForTimeoutThreshold) + LockSupport.parkNanos(this, nanosTimeout); + long now = System.nanoTime(); + nanosTimeout -= now - lastTime; + lastTime = now; + if (Thread.interrupted()) + throw new InterruptedException(); + } + } finally { + if (failed) + cancelAcquire(node); + } + } + + // Main exported methods + + /** + * Attempts to acquire in exclusive mode. This method should query + * if the state of the object permits it to be acquired in the + * exclusive mode, and if so to acquire it. + * + *

This method is always invoked by the thread performing + * acquire. If this method reports failure, the acquire method + * may queue the thread, if it is not already queued, until it is + * signalled by a release from some other thread. This can be used + * to implement method {@link Lock#tryLock()}. + * + *

The default + * implementation throws {@link UnsupportedOperationException}. + * + * @param arg the acquire argument. This value is always the one + * passed to an acquire method, or is the value saved on entry + * to a condition wait. The value is otherwise uninterpreted + * and can represent anything you like. + * @return {@code true} if successful. Upon success, this object has + * been acquired. + * @throws IllegalMonitorStateException if acquiring would place this + * synchronizer in an illegal state. This exception must be + * thrown in a consistent fashion for synchronization to work + * correctly. + * @throws UnsupportedOperationException if exclusive mode is not supported + */ + protected boolean tryAcquire(int arg) { + throw new UnsupportedOperationException(); + } + + /** + * Attempts to set the state to reflect a release in exclusive + * mode. + * + *

This method is always invoked by the thread performing release. + * + *

The default implementation throws + * {@link UnsupportedOperationException}. + * + * @param arg the release argument. This value is always the one + * passed to a release method, or the current state value upon + * entry to a condition wait. The value is otherwise + * uninterpreted and can represent anything you like. + * @return {@code true} if this object is now in a fully released + * state, so that any waiting threads may attempt to acquire; + * and {@code false} otherwise. + * @throws IllegalMonitorStateException if releasing would place this + * synchronizer in an illegal state. This exception must be + * thrown in a consistent fashion for synchronization to work + * correctly. + * @throws UnsupportedOperationException if exclusive mode is not supported + */ + protected boolean tryRelease(int arg) { + throw new UnsupportedOperationException(); + } + + /** + * Attempts to acquire in shared mode. This method should query if + * the state of the object permits it to be acquired in the shared + * mode, and if so to acquire it. + * + *

This method is always invoked by the thread performing + * acquire. If this method reports failure, the acquire method + * may queue the thread, if it is not already queued, until it is + * signalled by a release from some other thread. + * + *

The default implementation throws {@link + * UnsupportedOperationException}. + * + * @param arg the acquire argument. This value is always the one + * passed to an acquire method, or is the value saved on entry + * to a condition wait. The value is otherwise uninterpreted + * and can represent anything you like. + * @return a negative value on failure; zero if acquisition in shared + * mode succeeded but no subsequent shared-mode acquire can + * succeed; and a positive value if acquisition in shared + * mode succeeded and subsequent shared-mode acquires might + * also succeed, in which case a subsequent waiting thread + * must check availability. (Support for three different + * return values enables this method to be used in contexts + * where acquires only sometimes act exclusively.) Upon + * success, this object has been acquired. + * @throws IllegalMonitorStateException if acquiring would place this + * synchronizer in an illegal state. This exception must be + * thrown in a consistent fashion for synchronization to work + * correctly. + * @throws UnsupportedOperationException if shared mode is not supported + */ + protected int tryAcquireShared(int arg) { + throw new UnsupportedOperationException(); + } + + /** + * Attempts to set the state to reflect a release in shared mode. + * + *

This method is always invoked by the thread performing release. + * + *

The default implementation throws + * {@link UnsupportedOperationException}. + * + * @param arg the release argument. This value is always the one + * passed to a release method, or the current state value upon + * entry to a condition wait. The value is otherwise + * uninterpreted and can represent anything you like. + * @return {@code true} if this release of shared mode may permit a + * waiting acquire (shared or exclusive) to succeed; and + * {@code false} otherwise + * @throws IllegalMonitorStateException if releasing would place this + * synchronizer in an illegal state. This exception must be + * thrown in a consistent fashion for synchronization to work + * correctly. + * @throws UnsupportedOperationException if shared mode is not supported + */ + protected boolean tryReleaseShared(int arg) { + throw new UnsupportedOperationException(); + } + + /** + * Returns {@code true} if synchronization is held exclusively with + * respect to the current (calling) thread. This method is invoked + * upon each call to a non-waiting {@link ConditionObject} method. + * (Waiting methods instead invoke {@link #release}.) + * + *

The default implementation throws {@link + * UnsupportedOperationException}. This method is invoked + * internally only within {@link ConditionObject} methods, so need + * not be defined if conditions are not used. + * + * @return {@code true} if synchronization is held exclusively; + * {@code false} otherwise + * @throws UnsupportedOperationException if conditions are not supported + */ + protected boolean isHeldExclusively() { + throw new UnsupportedOperationException(); + } + + /** + * Acquires in exclusive mode, ignoring interrupts. Implemented + * by invoking at least once {@link #tryAcquire}, + * returning on success. Otherwise the thread is queued, possibly + * repeatedly blocking and unblocking, invoking {@link + * #tryAcquire} until success. This method can be used + * to implement method {@link Lock#lock}. + * + * @param arg the acquire argument. This value is conveyed to + * {@link #tryAcquire} but is otherwise uninterpreted and + * can represent anything you like. + */ + public final void acquire(int arg) { + if (!tryAcquire(arg) && + acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) + selfInterrupt(); + } + + /** + * Acquires in exclusive mode, aborting if interrupted. + * Implemented by first checking interrupt status, then invoking + * at least once {@link #tryAcquire}, returning on + * success. Otherwise the thread is queued, possibly repeatedly + * blocking and unblocking, invoking {@link #tryAcquire} + * until success or the thread is interrupted. This method can be + * used to implement method {@link Lock#lockInterruptibly}. + * + * @param arg the acquire argument. This value is conveyed to + * {@link #tryAcquire} but is otherwise uninterpreted and + * can represent anything you like. + * @throws InterruptedException if the current thread is interrupted + */ + public final void acquireInterruptibly(int arg) + throws InterruptedException { + if (Thread.interrupted()) + throw new InterruptedException(); + if (!tryAcquire(arg)) + doAcquireInterruptibly(arg); + } + + /** + * Attempts to acquire in exclusive mode, aborting if interrupted, + * and failing if the given timeout elapses. Implemented by first + * checking interrupt status, then invoking at least once {@link + * #tryAcquire}, returning on success. Otherwise, the thread is + * queued, possibly repeatedly blocking and unblocking, invoking + * {@link #tryAcquire} until success or the thread is interrupted + * or the timeout elapses. This method can be used to implement + * method {@link Lock#tryLock(long, TimeUnit)}. + * + * @param arg the acquire argument. This value is conveyed to + * {@link #tryAcquire} but is otherwise uninterpreted and + * can represent anything you like. + * @param nanosTimeout the maximum number of nanoseconds to wait + * @return {@code true} if acquired; {@code false} if timed out + * @throws InterruptedException if the current thread is interrupted + */ + public final boolean tryAcquireNanos(int arg, long nanosTimeout) + throws InterruptedException { + if (Thread.interrupted()) + throw new InterruptedException(); + return tryAcquire(arg) || + doAcquireNanos(arg, nanosTimeout); + } + + /** + * Releases in exclusive mode. Implemented by unblocking one or + * more threads if {@link #tryRelease} returns true. + * This method can be used to implement method {@link Lock#unlock}. + * + * @param arg the release argument. This value is conveyed to + * {@link #tryRelease} but is otherwise uninterpreted and + * can represent anything you like. + * @return the value returned from {@link #tryRelease} + */ + public final boolean release(int arg) { + if (tryRelease(arg)) { + Node h = head; + if (h != null && h.waitStatus != 0) + unparkSuccessor(h); + return true; + } + return false; + } + + /** + * Acquires in shared mode, ignoring interrupts. Implemented by + * first invoking at least once {@link #tryAcquireShared}, + * returning on success. Otherwise the thread is queued, possibly + * repeatedly blocking and unblocking, invoking {@link + * #tryAcquireShared} until success. + * + * @param arg the acquire argument. This value is conveyed to + * {@link #tryAcquireShared} but is otherwise uninterpreted + * and can represent anything you like. + */ + public final void acquireShared(int arg) { + if (tryAcquireShared(arg) < 0) + doAcquireShared(arg); + } + + /** + * Acquires in shared mode, aborting if interrupted. Implemented + * by first checking interrupt status, then invoking at least once + * {@link #tryAcquireShared}, returning on success. Otherwise the + * thread is queued, possibly repeatedly blocking and unblocking, + * invoking {@link #tryAcquireShared} until success or the thread + * is interrupted. + * @param arg the acquire argument + * This value is conveyed to {@link #tryAcquireShared} but is + * otherwise uninterpreted and can represent anything + * you like. + * @throws InterruptedException if the current thread is interrupted + */ + public final void acquireSharedInterruptibly(int arg) + throws InterruptedException { + if (Thread.interrupted()) + throw new InterruptedException(); + if (tryAcquireShared(arg) < 0) + doAcquireSharedInterruptibly(arg); + } + + /** + * Attempts to acquire in shared mode, aborting if interrupted, and + * failing if the given timeout elapses. Implemented by first + * checking interrupt status, then invoking at least once {@link + * #tryAcquireShared}, returning on success. Otherwise, the + * thread is queued, possibly repeatedly blocking and unblocking, + * invoking {@link #tryAcquireShared} until success or the thread + * is interrupted or the timeout elapses. + * + * @param arg the acquire argument. This value is conveyed to + * {@link #tryAcquireShared} but is otherwise uninterpreted + * and can represent anything you like. + * @param nanosTimeout the maximum number of nanoseconds to wait + * @return {@code true} if acquired; {@code false} if timed out + * @throws InterruptedException if the current thread is interrupted + */ + public final boolean tryAcquireSharedNanos(int arg, long nanosTimeout) + throws InterruptedException { + if (Thread.interrupted()) + throw new InterruptedException(); + return tryAcquireShared(arg) >= 0 || + doAcquireSharedNanos(arg, nanosTimeout); + } + + /** + * Releases in shared mode. Implemented by unblocking one or more + * threads if {@link #tryReleaseShared} returns true. + * + * @param arg the release argument. This value is conveyed to + * {@link #tryReleaseShared} but is otherwise uninterpreted + * and can represent anything you like. + * @return the value returned from {@link #tryReleaseShared} + */ + public final boolean releaseShared(int arg) { + if (tryReleaseShared(arg)) { + doReleaseShared(); + return true; + } + return false; + } + + // Queue inspection methods + + /** + * Queries whether any threads are waiting to acquire. Note that + * because cancellations due to interrupts and timeouts may occur + * at any time, a {@code true} return does not guarantee that any + * other thread will ever acquire. + * + *

In this implementation, this operation returns in + * constant time. + * + * @return {@code true} if there may be other threads waiting to acquire + */ + public final boolean hasQueuedThreads() { + return head != tail; + } + + /** + * Queries whether any threads have ever contended to acquire this + * synchronizer; that is if an acquire method has ever blocked. + * + *

In this implementation, this operation returns in + * constant time. + * + * @return {@code true} if there has ever been contention + */ + public final boolean hasContended() { + return head != null; + } + + /** + * Returns the first (longest-waiting) thread in the queue, or + * {@code null} if no threads are currently queued. + * + *

In this implementation, this operation normally returns in + * constant time, but may iterate upon contention if other threads are + * concurrently modifying the queue. + * + * @return the first (longest-waiting) thread in the queue, or + * {@code null} if no threads are currently queued + */ + public final Thread getFirstQueuedThread() { + // handle only fast path, else relay + return (head == tail) ? null : fullGetFirstQueuedThread(); + } + + /** + * Version of getFirstQueuedThread called when fastpath fails + */ + private Thread fullGetFirstQueuedThread() { + /* + * The first node is normally head.next. Try to get its + * thread field, ensuring consistent reads: If thread + * field is nulled out or s.prev is no longer head, then + * some other thread(s) concurrently performed setHead in + * between some of our reads. We try this twice before + * resorting to traversal. + */ + Node h, s; + Thread st; + if (((h = head) != null && (s = h.next) != null && + s.prev == head && (st = s.thread) != null) || + ((h = head) != null && (s = h.next) != null && + s.prev == head && (st = s.thread) != null)) + return st; + + /* + * Head's next field might not have been set yet, or may have + * been unset after setHead. So we must check to see if tail + * is actually first node. If not, we continue on, safely + * traversing from tail back to head to find first, + * guaranteeing termination. + */ + + Node t = tail; + Thread firstThread = null; + while (t != null && t != head) { + Thread tt = t.thread; + if (tt != null) + firstThread = tt; + t = t.prev; + } + return firstThread; + } + + /** + * Returns true if the given thread is currently queued. + * + *

This implementation traverses the queue to determine + * presence of the given thread. + * + * @param thread the thread + * @return {@code true} if the given thread is on the queue + * @throws NullPointerException if the thread is null + */ + public final boolean isQueued(Thread thread) { + if (thread == null) + throw new NullPointerException(); + for (Node p = tail; p != null; p = p.prev) + if (p.thread == thread) + return true; + return false; + } + + /** + * Returns {@code true} if the apparent first queued thread, if one + * exists, is waiting in exclusive mode. If this method returns + * {@code true}, and the current thread is attempting to acquire in + * shared mode (that is, this method is invoked from {@link + * #tryAcquireShared}) then it is guaranteed that the current thread + * is not the first queued thread. Used only as a heuristic in + * ReentrantReadWriteLock. + */ + final boolean apparentlyFirstQueuedIsExclusive() { + Node h, s; + return (h = head) != null && + (s = h.next) != null && + !s.isShared() && + s.thread != null; + } + + /** + * Queries whether any threads have been waiting to acquire longer + * than the current thread. + * + *

An invocation of this method is equivalent to (but may be + * more efficient than): + *

 {@code
+     * getFirstQueuedThread() != Thread.currentThread() &&
+     * hasQueuedThreads()}
+ * + *

Note that because cancellations due to interrupts and + * timeouts may occur at any time, a {@code true} return does not + * guarantee that some other thread will acquire before the current + * thread. Likewise, it is possible for another thread to win a + * race to enqueue after this method has returned {@code false}, + * due to the queue being empty. + * + *

This method is designed to be used by a fair synchronizer to + * avoid barging. + * Such a synchronizer's {@link #tryAcquire} method should return + * {@code false}, and its {@link #tryAcquireShared} method should + * return a negative value, if this method returns {@code true} + * (unless this is a reentrant acquire). For example, the {@code + * tryAcquire} method for a fair, reentrant, exclusive mode + * synchronizer might look like this: + * + *

 {@code
+     * protected boolean tryAcquire(int arg) {
+     *   if (isHeldExclusively()) {
+     *     // A reentrant acquire; increment hold count
+     *     return true;
+     *   } else if (hasQueuedPredecessors()) {
+     *     return false;
+     *   } else {
+     *     // try to acquire normally
+     *   }
+     * }}
+ * + * @return {@code true} if there is a queued thread preceding the + * current thread, and {@code false} if the current thread + * is at the head of the queue or the queue is empty + * @since 1.7 + */ + public final boolean hasQueuedPredecessors() { + // The correctness of this depends on head being initialized + // before tail and on head.next being accurate if the current + // thread is first in queue. + Node t = tail; // Read fields in reverse initialization order + Node h = head; + Node s; + return h != t && + ((s = h.next) == null || s.thread != Thread.currentThread()); + } + + + // Instrumentation and monitoring methods + + /** + * Returns an estimate of the number of threads waiting to + * acquire. The value is only an estimate because the number of + * threads may change dynamically while this method traverses + * internal data structures. This method is designed for use in + * monitoring system state, not for synchronization + * control. + * + * @return the estimated number of threads waiting to acquire + */ + public final int getQueueLength() { + int n = 0; + for (Node p = tail; p != null; p = p.prev) { + if (p.thread != null) + ++n; + } + return n; + } + + /** + * Returns a collection containing threads that may be waiting to + * acquire. Because the actual set of threads may change + * dynamically while constructing this result, the returned + * collection is only a best-effort estimate. The elements of the + * returned collection are in no particular order. This method is + * designed to facilitate construction of subclasses that provide + * more extensive monitoring facilities. + * + * @return the collection of threads + */ + public final Collection getQueuedThreads() { + ArrayList list = new ArrayList(); + for (Node p = tail; p != null; p = p.prev) { + Thread t = p.thread; + if (t != null) + list.add(t); + } + return list; + } + + /** + * Returns a collection containing threads that may be waiting to + * acquire in exclusive mode. This has the same properties + * as {@link #getQueuedThreads} except that it only returns + * those threads waiting due to an exclusive acquire. + * + * @return the collection of threads + */ + public final Collection getExclusiveQueuedThreads() { + ArrayList list = new ArrayList(); + for (Node p = tail; p != null; p = p.prev) { + if (!p.isShared()) { + Thread t = p.thread; + if (t != null) + list.add(t); + } + } + return list; + } + + /** + * Returns a collection containing threads that may be waiting to + * acquire in shared mode. This has the same properties + * as {@link #getQueuedThreads} except that it only returns + * those threads waiting due to a shared acquire. + * + * @return the collection of threads + */ + public final Collection getSharedQueuedThreads() { + ArrayList list = new ArrayList(); + for (Node p = tail; p != null; p = p.prev) { + if (p.isShared()) { + Thread t = p.thread; + if (t != null) + list.add(t); + } + } + return list; + } + + /** + * Returns a string identifying this synchronizer, as well as its state. + * The state, in brackets, includes the String {@code "State ="} + * followed by the current value of {@link #getState}, and either + * {@code "nonempty"} or {@code "empty"} depending on whether the + * queue is empty. + * + * @return a string identifying this synchronizer, as well as its state + */ + public String toString() { + int s = getState(); + String q = hasQueuedThreads() ? "non" : ""; + return super.toString() + + "[State = " + s + ", " + q + "empty queue]"; + } + + + // Internal support methods for Conditions + + /** + * Returns true if a node, always one that was initially placed on + * a condition queue, is now waiting to reacquire on sync queue. + * @param node the node + * @return true if is reacquiring + */ + final boolean isOnSyncQueue(Node node) { + if (node.waitStatus == Node.CONDITION || node.prev == null) + return false; + if (node.next != null) // If has successor, it must be on queue + return true; + /* + * node.prev can be non-null, but not yet on queue because + * the CAS to place it on queue can fail. So we have to + * traverse from tail to make sure it actually made it. It + * will always be near the tail in calls to this method, and + * unless the CAS failed (which is unlikely), it will be + * there, so we hardly ever traverse much. + */ + return findNodeFromTail(node); + } + + /** + * Returns true if node is on sync queue by searching backwards from tail. + * Called only when needed by isOnSyncQueue. + * @return true if present + */ + private boolean findNodeFromTail(Node node) { + Node t = tail; + for (;;) { + if (t == node) + return true; + if (t == null) + return false; + t = t.prev; + } + } + + /** + * Transfers a node from a condition queue onto sync queue. + * Returns true if successful. + * @param node the node + * @return true if successfully transferred (else the node was + * cancelled before signal). + */ + final boolean transferForSignal(Node node) { + /* + * If cannot change waitStatus, the node has been cancelled. + */ + if (!compareAndSetWaitStatus(node, Node.CONDITION, 0)) + return false; + + /* + * Splice onto queue and try to set waitStatus of predecessor to + * indicate that thread is (probably) waiting. If cancelled or + * attempt to set waitStatus fails, wake up to resync (in which + * case the waitStatus can be transiently and harmlessly wrong). + */ + Node p = enq(node); + int ws = p.waitStatus; + if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL)) + LockSupport.unpark(node.thread); + return true; + } + + /** + * Transfers node, if necessary, to sync queue after a cancelled + * wait. Returns true if thread was cancelled before being + * signalled. + * @param current the waiting thread + * @param node its node + * @return true if cancelled before the node was signalled + */ + final boolean transferAfterCancelledWait(Node node) { + if (compareAndSetWaitStatus(node, Node.CONDITION, 0)) { + enq(node); + return true; + } + /* + * If we lost out to a signal(), then we can't proceed + * until it finishes its enq(). Cancelling during an + * incomplete transfer is both rare and transient, so just + * spin. + */ + while (!isOnSyncQueue(node)) + Thread.yield(); + return false; + } + + /** + * Invokes release with current state value; returns saved state. + * Cancels node and throws exception on failure. + * @param node the condition node for this wait + * @return previous sync state + */ + final int fullyRelease(Node node) { + boolean failed = true; + try { + int savedState = getState(); + if (release(savedState)) { + failed = false; + return savedState; + } else { + throw new IllegalMonitorStateException(); + } + } finally { + if (failed) + node.waitStatus = Node.CANCELLED; + } + } + + // Instrumentation methods for conditions + + /** + * Queries whether the given ConditionObject + * uses this synchronizer as its lock. + * + * @param condition the condition + * @return true if owned + * @throws NullPointerException if the condition is null + */ + public final boolean owns(ConditionObject condition) { + if (condition == null) + throw new NullPointerException(); + return condition.isOwnedBy(this); + } + + /** + * Queries whether any threads are waiting on the given condition + * associated with this synchronizer. Note that because timeouts + * and interrupts may occur at any time, a true return + * does not guarantee that a future signal will awaken + * any threads. This method is designed primarily for use in + * monitoring of the system state. + * + * @param condition the condition + * @return true if there are any waiting threads + * @throws IllegalMonitorStateException if exclusive synchronization + * is not held + * @throws IllegalArgumentException if the given condition is + * not associated with this synchronizer + * @throws NullPointerException if the condition is null + */ + public final boolean hasWaiters(ConditionObject condition) { + if (!owns(condition)) + throw new IllegalArgumentException("Not owner"); + return condition.hasWaiters(); + } + + /** + * Returns an estimate of the number of threads waiting on the + * given condition associated with this synchronizer. Note that + * because timeouts and interrupts may occur at any time, the + * estimate serves only as an upper bound on the actual number of + * waiters. This method is designed for use in monitoring of the + * system state, not for synchronization control. + * + * @param condition the condition + * @return the estimated number of waiting threads + * @throws IllegalMonitorStateException if exclusive synchronization + * is not held + * @throws IllegalArgumentException if the given condition is + * not associated with this synchronizer + * @throws NullPointerException if the condition is null + */ + public final int getWaitQueueLength(ConditionObject condition) { + if (!owns(condition)) + throw new IllegalArgumentException("Not owner"); + return condition.getWaitQueueLength(); + } + + /** + * Returns a collection containing those threads that may be + * waiting on the given condition associated with this + * synchronizer. Because the actual set of threads may change + * dynamically while constructing this result, the returned + * collection is only a best-effort estimate. The elements of the + * returned collection are in no particular order. + * + * @param condition the condition + * @return the collection of threads + * @throws IllegalMonitorStateException if exclusive synchronization + * is not held + * @throws IllegalArgumentException if the given condition is + * not associated with this synchronizer + * @throws NullPointerException if the condition is null + */ + public final Collection getWaitingThreads(ConditionObject condition) { + if (!owns(condition)) + throw new IllegalArgumentException("Not owner"); + return condition.getWaitingThreads(); + } + + /** + * Condition implementation for a {@link + * AbstractQueuedSynchronizer} serving as the basis of a {@link + * Lock} implementation. + * + *

Method documentation for this class describes mechanics, + * not behavioral specifications from the point of view of Lock + * and Condition users. Exported versions of this class will in + * general need to be accompanied by documentation describing + * condition semantics that rely on those of the associated + * AbstractQueuedSynchronizer. + * + *

This class is Serializable, but all fields are transient, + * so deserialized conditions have no waiters. + */ + public class ConditionObject implements Condition, java.io.Serializable { + private static final long serialVersionUID = 1173984872572414699L; + /** First node of condition queue. */ + private transient Node firstWaiter; + /** Last node of condition queue. */ + private transient Node lastWaiter; + + /** + * Creates a new ConditionObject instance. + */ + public ConditionObject() { } + + // Internal methods + + /** + * Adds a new waiter to wait queue. + * @return its new wait node + */ + private Node addConditionWaiter() { + Node t = lastWaiter; + // If lastWaiter is cancelled, clean out. + if (t != null && t.waitStatus != Node.CONDITION) { + unlinkCancelledWaiters(); + t = lastWaiter; + } + Node node = new Node(Thread.currentThread(), Node.CONDITION); + if (t == null) + firstWaiter = node; + else + t.nextWaiter = node; + lastWaiter = node; + return node; + } + + /** + * Removes and transfers nodes until hit non-cancelled one or + * null. Split out from signal in part to encourage compilers + * to inline the case of no waiters. + * @param first (non-null) the first node on condition queue + */ + private void doSignal(Node first) { + do { + if ( (firstWaiter = first.nextWaiter) == null) + lastWaiter = null; + first.nextWaiter = null; + } while (!transferForSignal(first) && + (first = firstWaiter) != null); + } + + /** + * Removes and transfers all nodes. + * @param first (non-null) the first node on condition queue + */ + private void doSignalAll(Node first) { + lastWaiter = firstWaiter = null; + do { + Node next = first.nextWaiter; + first.nextWaiter = null; + transferForSignal(first); + first = next; + } while (first != null); + } + + /** + * Unlinks cancelled waiter nodes from condition queue. + * Called only while holding lock. This is called when + * cancellation occurred during condition wait, and upon + * insertion of a new waiter when lastWaiter is seen to have + * been cancelled. This method is needed to avoid garbage + * retention in the absence of signals. So even though it may + * require a full traversal, it comes into play only when + * timeouts or cancellations occur in the absence of + * signals. It traverses all nodes rather than stopping at a + * particular target to unlink all pointers to garbage nodes + * without requiring many re-traversals during cancellation + * storms. + */ + private void unlinkCancelledWaiters() { + Node t = firstWaiter; + Node trail = null; + while (t != null) { + Node next = t.nextWaiter; + if (t.waitStatus != Node.CONDITION) { + t.nextWaiter = null; + if (trail == null) + firstWaiter = next; + else + trail.nextWaiter = next; + if (next == null) + lastWaiter = trail; + } + else + trail = t; + t = next; + } + } + + // public methods + + /** + * Moves the longest-waiting thread, if one exists, from the + * wait queue for this condition to the wait queue for the + * owning lock. + * + * @throws IllegalMonitorStateException if {@link #isHeldExclusively} + * returns {@code false} + */ + public final void signal() { + if (!isHeldExclusively()) + throw new IllegalMonitorStateException(); + Node first = firstWaiter; + if (first != null) + doSignal(first); + } + + /** + * Moves all threads from the wait queue for this condition to + * the wait queue for the owning lock. + * + * @throws IllegalMonitorStateException if {@link #isHeldExclusively} + * returns {@code false} + */ + public final void signalAll() { + if (!isHeldExclusively()) + throw new IllegalMonitorStateException(); + Node first = firstWaiter; + if (first != null) + doSignalAll(first); + } + + /** + * Implements uninterruptible condition wait. + *

    + *
  1. Save lock state returned by {@link #getState}. + *
  2. Invoke {@link #release} with + * saved state as argument, throwing + * IllegalMonitorStateException if it fails. + *
  3. Block until signalled. + *
  4. Reacquire by invoking specialized version of + * {@link #acquire} with saved state as argument. + *
+ */ + public final void awaitUninterruptibly() { + Node node = addConditionWaiter(); + int savedState = fullyRelease(node); + boolean interrupted = false; + while (!isOnSyncQueue(node)) { + LockSupport.park(this); + if (Thread.interrupted()) + interrupted = true; + } + if (acquireQueued(node, savedState) || interrupted) + selfInterrupt(); + } + + /* + * For interruptible waits, we need to track whether to throw + * InterruptedException, if interrupted while blocked on + * condition, versus reinterrupt current thread, if + * interrupted while blocked waiting to re-acquire. + */ + + /** Mode meaning to reinterrupt on exit from wait */ + private static final int REINTERRUPT = 1; + /** Mode meaning to throw InterruptedException on exit from wait */ + private static final int THROW_IE = -1; + + /** + * Checks for interrupt, returning THROW_IE if interrupted + * before signalled, REINTERRUPT if after signalled, or + * 0 if not interrupted. + */ + private int checkInterruptWhileWaiting(Node node) { + return Thread.interrupted() ? + (transferAfterCancelledWait(node) ? THROW_IE : REINTERRUPT) : + 0; + } + + /** + * Throws InterruptedException, reinterrupts current thread, or + * does nothing, depending on mode. + */ + private void reportInterruptAfterWait(int interruptMode) + throws InterruptedException { + if (interruptMode == THROW_IE) + throw new InterruptedException(); + else if (interruptMode == REINTERRUPT) + selfInterrupt(); + } + + /** + * Implements interruptible condition wait. + *
    + *
  1. If current thread is interrupted, throw InterruptedException. + *
  2. Save lock state returned by {@link #getState}. + *
  3. Invoke {@link #release} with + * saved state as argument, throwing + * IllegalMonitorStateException if it fails. + *
  4. Block until signalled or interrupted. + *
  5. Reacquire by invoking specialized version of + * {@link #acquire} with saved state as argument. + *
  6. If interrupted while blocked in step 4, throw InterruptedException. + *
+ */ + public final void await() throws InterruptedException { + if (Thread.interrupted()) + throw new InterruptedException(); + Node node = addConditionWaiter(); + int savedState = fullyRelease(node); + int interruptMode = 0; + while (!isOnSyncQueue(node)) { + LockSupport.park(this); + if ((interruptMode = checkInterruptWhileWaiting(node)) != 0) + break; + } + if (acquireQueued(node, savedState) && interruptMode != THROW_IE) + interruptMode = REINTERRUPT; + if (node.nextWaiter != null) // clean up if cancelled + unlinkCancelledWaiters(); + if (interruptMode != 0) + reportInterruptAfterWait(interruptMode); + } + + /** + * Implements timed condition wait. + *
    + *
  1. If current thread is interrupted, throw InterruptedException. + *
  2. Save lock state returned by {@link #getState}. + *
  3. Invoke {@link #release} with + * saved state as argument, throwing + * IllegalMonitorStateException if it fails. + *
  4. Block until signalled, interrupted, or timed out. + *
  5. Reacquire by invoking specialized version of + * {@link #acquire} with saved state as argument. + *
  6. If interrupted while blocked in step 4, throw InterruptedException. + *
+ */ + public final long awaitNanos(long nanosTimeout) + throws InterruptedException { + if (Thread.interrupted()) + throw new InterruptedException(); + Node node = addConditionWaiter(); + int savedState = fullyRelease(node); + long lastTime = System.nanoTime(); + int interruptMode = 0; + while (!isOnSyncQueue(node)) { + if (nanosTimeout <= 0L) { + transferAfterCancelledWait(node); + break; + } + LockSupport.parkNanos(this, nanosTimeout); + if ((interruptMode = checkInterruptWhileWaiting(node)) != 0) + break; + + long now = System.nanoTime(); + nanosTimeout -= now - lastTime; + lastTime = now; + } + if (acquireQueued(node, savedState) && interruptMode != THROW_IE) + interruptMode = REINTERRUPT; + if (node.nextWaiter != null) + unlinkCancelledWaiters(); + if (interruptMode != 0) + reportInterruptAfterWait(interruptMode); + return nanosTimeout - (System.nanoTime() - lastTime); + } + + /** + * Implements absolute timed condition wait. + *
    + *
  1. If current thread is interrupted, throw InterruptedException. + *
  2. Save lock state returned by {@link #getState}. + *
  3. Invoke {@link #release} with + * saved state as argument, throwing + * IllegalMonitorStateException if it fails. + *
  4. Block until signalled, interrupted, or timed out. + *
  5. Reacquire by invoking specialized version of + * {@link #acquire} with saved state as argument. + *
  6. If interrupted while blocked in step 4, throw InterruptedException. + *
  7. If timed out while blocked in step 4, return false, else true. + *
+ */ + public final boolean awaitUntil(Date deadline) + throws InterruptedException { + if (deadline == null) + throw new NullPointerException(); + long abstime = deadline.getTime(); + if (Thread.interrupted()) + throw new InterruptedException(); + Node node = addConditionWaiter(); + int savedState = fullyRelease(node); + boolean timedout = false; + int interruptMode = 0; + while (!isOnSyncQueue(node)) { + if (System.currentTimeMillis() > abstime) { + timedout = transferAfterCancelledWait(node); + break; + } + LockSupport.parkUntil(this, abstime); + if ((interruptMode = checkInterruptWhileWaiting(node)) != 0) + break; + } + if (acquireQueued(node, savedState) && interruptMode != THROW_IE) + interruptMode = REINTERRUPT; + if (node.nextWaiter != null) + unlinkCancelledWaiters(); + if (interruptMode != 0) + reportInterruptAfterWait(interruptMode); + return !timedout; + } + + /** + * Implements timed condition wait. + *
    + *
  1. If current thread is interrupted, throw InterruptedException. + *
  2. Save lock state returned by {@link #getState}. + *
  3. Invoke {@link #release} with + * saved state as argument, throwing + * IllegalMonitorStateException if it fails. + *
  4. Block until signalled, interrupted, or timed out. + *
  5. Reacquire by invoking specialized version of + * {@link #acquire} with saved state as argument. + *
  6. If interrupted while blocked in step 4, throw InterruptedException. + *
  7. If timed out while blocked in step 4, return false, else true. + *
+ */ + public final boolean await(long time, TimeUnit unit) + throws InterruptedException { + if (unit == null) + throw new NullPointerException(); + long nanosTimeout = unit.toNanos(time); + if (Thread.interrupted()) + throw new InterruptedException(); + Node node = addConditionWaiter(); + int savedState = fullyRelease(node); + long lastTime = System.nanoTime(); + boolean timedout = false; + int interruptMode = 0; + while (!isOnSyncQueue(node)) { + if (nanosTimeout <= 0L) { + timedout = transferAfterCancelledWait(node); + break; + } + if (nanosTimeout >= spinForTimeoutThreshold) + LockSupport.parkNanos(this, nanosTimeout); + if ((interruptMode = checkInterruptWhileWaiting(node)) != 0) + break; + long now = System.nanoTime(); + nanosTimeout -= now - lastTime; + lastTime = now; + } + if (acquireQueued(node, savedState) && interruptMode != THROW_IE) + interruptMode = REINTERRUPT; + if (node.nextWaiter != null) + unlinkCancelledWaiters(); + if (interruptMode != 0) + reportInterruptAfterWait(interruptMode); + return !timedout; + } + + // support for instrumentation + + /** + * Returns true if this condition was created by the given + * synchronization object. + * + * @return {@code true} if owned + */ + final boolean isOwnedBy(AbstractQueuedSynchronizer sync) { + return sync == AbstractQueuedSynchronizer.this; + } + + /** + * Queries whether any threads are waiting on this condition. + * Implements {@link AbstractQueuedSynchronizer#hasWaiters}. + * + * @return {@code true} if there are any waiting threads + * @throws IllegalMonitorStateException if {@link #isHeldExclusively} + * returns {@code false} + */ + protected final boolean hasWaiters() { + if (!isHeldExclusively()) + throw new IllegalMonitorStateException(); + for (Node w = firstWaiter; w != null; w = w.nextWaiter) { + if (w.waitStatus == Node.CONDITION) + return true; + } + return false; + } + + /** + * Returns an estimate of the number of threads waiting on + * this condition. + * Implements {@link AbstractQueuedSynchronizer#getWaitQueueLength}. + * + * @return the estimated number of waiting threads + * @throws IllegalMonitorStateException if {@link #isHeldExclusively} + * returns {@code false} + */ + protected final int getWaitQueueLength() { + if (!isHeldExclusively()) + throw new IllegalMonitorStateException(); + int n = 0; + for (Node w = firstWaiter; w != null; w = w.nextWaiter) { + if (w.waitStatus == Node.CONDITION) + ++n; + } + return n; + } + + /** + * Returns a collection containing those threads that may be + * waiting on this Condition. + * Implements {@link AbstractQueuedSynchronizer#getWaitingThreads}. + * + * @return the collection of threads + * @throws IllegalMonitorStateException if {@link #isHeldExclusively} + * returns {@code false} + */ + protected final Collection getWaitingThreads() { + if (!isHeldExclusively()) + throw new IllegalMonitorStateException(); + ArrayList list = new ArrayList(); + for (Node w = firstWaiter; w != null; w = w.nextWaiter) { + if (w.waitStatus == Node.CONDITION) { + Thread t = w.thread; + if (t != null) + list.add(t); + } + } + return list; + } + } + + /** + * Setup to support compareAndSet. We need to natively implement + * this here: For the sake of permitting future enhancements, we + * cannot explicitly subclass AtomicInteger, which would be + * efficient and useful otherwise. So, as the lesser of evils, we + * natively implement using hotspot intrinsics API. And while we + * are at it, we do the same for other CASable fields (which could + * otherwise be done with atomic field updaters). + */ + private static final Unsafe unsafe = Unsafe.getUnsafe(); + private static final long stateOffset; + private static final long headOffset; + private static final long tailOffset; + private static final long waitStatusOffset; + private static final long nextOffset; + + static { + try { + stateOffset = unsafe.objectFieldOffset + (AbstractQueuedSynchronizer.class.getDeclaredField("state")); + headOffset = unsafe.objectFieldOffset + (AbstractQueuedSynchronizer.class.getDeclaredField("head")); + tailOffset = unsafe.objectFieldOffset + (AbstractQueuedSynchronizer.class.getDeclaredField("tail")); + waitStatusOffset = unsafe.objectFieldOffset + (Node.class.getDeclaredField("waitStatus")); + nextOffset = unsafe.objectFieldOffset + (Node.class.getDeclaredField("next")); + + } catch (Exception ex) { throw new Error(ex); } + } + + /** + * CAS head field. Used only by enq. + */ + private final boolean compareAndSetHead(Node update) { + return unsafe.compareAndSwapObject(this, headOffset, null, update); + } + + /** + * CAS tail field. Used only by enq. + */ + private final boolean compareAndSetTail(Node expect, Node update) { + return unsafe.compareAndSwapObject(this, tailOffset, expect, update); + } + + /** + * CAS waitStatus field of a node. + */ + private static final boolean compareAndSetWaitStatus(Node node, + int expect, + int update) { + return unsafe.compareAndSwapInt(node, waitStatusOffset, + expect, update); + } + + /** + * CAS next field of a node. + */ + private static final boolean compareAndSetNext(Node node, + Node expect, + Node update) { + return unsafe.compareAndSwapObject(node, nextOffset, expect, update); + } +} diff -r e1953d8b8338 -r c8af252ea9eb rt/emul/compact/src/main/java/java/util/concurrent/locks/Condition.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/locks/Condition.java Sat Mar 19 10:48:29 2016 +0100 @@ -0,0 +1,488 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +package java.util.concurrent.locks; +import java.util.concurrent.*; +import java.util.Date; + +/** + * {@code Condition} factors out the {@code Object} monitor + * methods ({@link Object#wait() wait}, {@link Object#notify notify} + * and {@link Object#notifyAll notifyAll}) into distinct objects to + * give the effect of having multiple wait-sets per object, by + * combining them with the use of arbitrary {@link Lock} implementations. + * Where a {@code Lock} replaces the use of {@code synchronized} methods + * and statements, a {@code Condition} replaces the use of the Object + * monitor methods. + * + *

Conditions (also known as condition queues or + * condition variables) provide a means for one thread to + * suspend execution (to "wait") until notified by another + * thread that some state condition may now be true. Because access + * to this shared state information occurs in different threads, it + * must be protected, so a lock of some form is associated with the + * condition. The key property that waiting for a condition provides + * is that it atomically releases the associated lock and + * suspends the current thread, just like {@code Object.wait}. + * + *

A {@code Condition} instance is intrinsically bound to a lock. + * To obtain a {@code Condition} instance for a particular {@link Lock} + * instance use its {@link Lock#newCondition newCondition()} method. + * + *

As an example, suppose we have a bounded buffer which supports + * {@code put} and {@code take} methods. If a + * {@code take} is attempted on an empty buffer, then the thread will block + * until an item becomes available; if a {@code put} is attempted on a + * full buffer, then the thread will block until a space becomes available. + * We would like to keep waiting {@code put} threads and {@code take} + * threads in separate wait-sets so that we can use the optimization of + * only notifying a single thread at a time when items or spaces become + * available in the buffer. This can be achieved using two + * {@link Condition} instances. + *

+ * class BoundedBuffer {
+ *   final Lock lock = new ReentrantLock();
+ *   final Condition notFull  = lock.newCondition(); 
+ *   final Condition notEmpty = lock.newCondition(); 
+ *
+ *   final Object[] items = new Object[100];
+ *   int putptr, takeptr, count;
+ *
+ *   public void put(Object x) throws InterruptedException {
+ *     lock.lock();
+ *     try {
+ *       while (count == items.length)
+ *         notFull.await();
+ *       items[putptr] = x;
+ *       if (++putptr == items.length) putptr = 0;
+ *       ++count;
+ *       notEmpty.signal();
+ *     } finally {
+ *       lock.unlock();
+ *     }
+ *   }
+ *
+ *   public Object take() throws InterruptedException {
+ *     lock.lock();
+ *     try {
+ *       while (count == 0)
+ *         notEmpty.await();
+ *       Object x = items[takeptr];
+ *       if (++takeptr == items.length) takeptr = 0;
+ *       --count;
+ *       notFull.signal();
+ *       return x;
+ *     } finally {
+ *       lock.unlock();
+ *     }
+ *   }
+ * }
+ * 
+ * + * (The {@link java.util.concurrent.ArrayBlockingQueue} class provides + * this functionality, so there is no reason to implement this + * sample usage class.) + * + *

A {@code Condition} implementation can provide behavior and semantics + * that is + * different from that of the {@code Object} monitor methods, such as + * guaranteed ordering for notifications, or not requiring a lock to be held + * when performing notifications. + * If an implementation provides such specialized semantics then the + * implementation must document those semantics. + * + *

Note that {@code Condition} instances are just normal objects and can + * themselves be used as the target in a {@code synchronized} statement, + * and can have their own monitor {@link Object#wait wait} and + * {@link Object#notify notification} methods invoked. + * Acquiring the monitor lock of a {@code Condition} instance, or using its + * monitor methods, has no specified relationship with acquiring the + * {@link Lock} associated with that {@code Condition} or the use of its + * {@linkplain #await waiting} and {@linkplain #signal signalling} methods. + * It is recommended that to avoid confusion you never use {@code Condition} + * instances in this way, except perhaps within their own implementation. + * + *

Except where noted, passing a {@code null} value for any parameter + * will result in a {@link NullPointerException} being thrown. + * + *

Implementation Considerations

+ * + *

When waiting upon a {@code Condition}, a "spurious + * wakeup" is permitted to occur, in + * general, as a concession to the underlying platform semantics. + * This has little practical impact on most application programs as a + * {@code Condition} should always be waited upon in a loop, testing + * the state predicate that is being waited for. An implementation is + * free to remove the possibility of spurious wakeups but it is + * recommended that applications programmers always assume that they can + * occur and so always wait in a loop. + * + *

The three forms of condition waiting + * (interruptible, non-interruptible, and timed) may differ in their ease of + * implementation on some platforms and in their performance characteristics. + * In particular, it may be difficult to provide these features and maintain + * specific semantics such as ordering guarantees. + * Further, the ability to interrupt the actual suspension of the thread may + * not always be feasible to implement on all platforms. + * + *

Consequently, an implementation is not required to define exactly the + * same guarantees or semantics for all three forms of waiting, nor is it + * required to support interruption of the actual suspension of the thread. + * + *

An implementation is required to + * clearly document the semantics and guarantees provided by each of the + * waiting methods, and when an implementation does support interruption of + * thread suspension then it must obey the interruption semantics as defined + * in this interface. + * + *

As interruption generally implies cancellation, and checks for + * interruption are often infrequent, an implementation can favor responding + * to an interrupt over normal method return. This is true even if it can be + * shown that the interrupt occurred after another action that may have + * unblocked the thread. An implementation should document this behavior. + * + * @since 1.5 + * @author Doug Lea + */ +public interface Condition { + + /** + * Causes the current thread to wait until it is signalled or + * {@linkplain Thread#interrupt interrupted}. + * + *

The lock associated with this {@code Condition} is atomically + * released and the current thread becomes disabled for thread scheduling + * purposes and lies dormant until one of four things happens: + *

    + *
  • Some other thread invokes the {@link #signal} method for this + * {@code Condition} and the current thread happens to be chosen as the + * thread to be awakened; or + *
  • Some other thread invokes the {@link #signalAll} method for this + * {@code Condition}; or + *
  • Some other thread {@linkplain Thread#interrupt interrupts} the + * current thread, and interruption of thread suspension is supported; or + *
  • A "spurious wakeup" occurs. + *
+ * + *

In all cases, before this method can return the current thread must + * re-acquire the lock associated with this condition. When the + * thread returns it is guaranteed to hold this lock. + * + *

If the current thread: + *

    + *
  • has its interrupted status set on entry to this method; or + *
  • is {@linkplain Thread#interrupt interrupted} while waiting + * and interruption of thread suspension is supported, + *
+ * then {@link InterruptedException} is thrown and the current thread's + * interrupted status is cleared. It is not specified, in the first + * case, whether or not the test for interruption occurs before the lock + * is released. + * + *

Implementation Considerations + * + *

The current thread is assumed to hold the lock associated with this + * {@code Condition} when this method is called. + * It is up to the implementation to determine if this is + * the case and if not, how to respond. Typically, an exception will be + * thrown (such as {@link IllegalMonitorStateException}) and the + * implementation must document that fact. + * + *

An implementation can favor responding to an interrupt over normal + * method return in response to a signal. In that case the implementation + * must ensure that the signal is redirected to another waiting thread, if + * there is one. + * + * @throws InterruptedException if the current thread is interrupted + * (and interruption of thread suspension is supported) + */ + void await() throws InterruptedException; + + /** + * Causes the current thread to wait until it is signalled. + * + *

The lock associated with this condition is atomically + * released and the current thread becomes disabled for thread scheduling + * purposes and lies dormant until one of three things happens: + *

    + *
  • Some other thread invokes the {@link #signal} method for this + * {@code Condition} and the current thread happens to be chosen as the + * thread to be awakened; or + *
  • Some other thread invokes the {@link #signalAll} method for this + * {@code Condition}; or + *
  • A "spurious wakeup" occurs. + *
+ * + *

In all cases, before this method can return the current thread must + * re-acquire the lock associated with this condition. When the + * thread returns it is guaranteed to hold this lock. + * + *

If the current thread's interrupted status is set when it enters + * this method, or it is {@linkplain Thread#interrupt interrupted} + * while waiting, it will continue to wait until signalled. When it finally + * returns from this method its interrupted status will still + * be set. + * + *

Implementation Considerations + * + *

The current thread is assumed to hold the lock associated with this + * {@code Condition} when this method is called. + * It is up to the implementation to determine if this is + * the case and if not, how to respond. Typically, an exception will be + * thrown (such as {@link IllegalMonitorStateException}) and the + * implementation must document that fact. + */ + void awaitUninterruptibly(); + + /** + * Causes the current thread to wait until it is signalled or interrupted, + * or the specified waiting time elapses. + * + *

The lock associated with this condition is atomically + * released and the current thread becomes disabled for thread scheduling + * purposes and lies dormant until one of five things happens: + *

    + *
  • Some other thread invokes the {@link #signal} method for this + * {@code Condition} and the current thread happens to be chosen as the + * thread to be awakened; or + *
  • Some other thread invokes the {@link #signalAll} method for this + * {@code Condition}; or + *
  • Some other thread {@linkplain Thread#interrupt interrupts} the + * current thread, and interruption of thread suspension is supported; or + *
  • The specified waiting time elapses; or + *
  • A "spurious wakeup" occurs. + *
+ * + *

In all cases, before this method can return the current thread must + * re-acquire the lock associated with this condition. When the + * thread returns it is guaranteed to hold this lock. + * + *

If the current thread: + *

    + *
  • has its interrupted status set on entry to this method; or + *
  • is {@linkplain Thread#interrupt interrupted} while waiting + * and interruption of thread suspension is supported, + *
+ * then {@link InterruptedException} is thrown and the current thread's + * interrupted status is cleared. It is not specified, in the first + * case, whether or not the test for interruption occurs before the lock + * is released. + * + *

The method returns an estimate of the number of nanoseconds + * remaining to wait given the supplied {@code nanosTimeout} + * value upon return, or a value less than or equal to zero if it + * timed out. This value can be used to determine whether and how + * long to re-wait in cases where the wait returns but an awaited + * condition still does not hold. Typical uses of this method take + * the following form: + * + *

 {@code
+     * boolean aMethod(long timeout, TimeUnit unit) {
+     *   long nanos = unit.toNanos(timeout);
+     *   lock.lock();
+     *   try {
+     *     while (!conditionBeingWaitedFor()) {
+     *       if (nanos <= 0L)
+     *         return false;
+     *       nanos = theCondition.awaitNanos(nanos);
+     *     }
+     *     // ...
+     *   } finally {
+     *     lock.unlock();
+     *   }
+     * }}
+ * + *

Design note: This method requires a nanosecond argument so + * as to avoid truncation errors in reporting remaining times. + * Such precision loss would make it difficult for programmers to + * ensure that total waiting times are not systematically shorter + * than specified when re-waits occur. + * + *

Implementation Considerations + * + *

The current thread is assumed to hold the lock associated with this + * {@code Condition} when this method is called. + * It is up to the implementation to determine if this is + * the case and if not, how to respond. Typically, an exception will be + * thrown (such as {@link IllegalMonitorStateException}) and the + * implementation must document that fact. + * + *

An implementation can favor responding to an interrupt over normal + * method return in response to a signal, or over indicating the elapse + * of the specified waiting time. In either case the implementation + * must ensure that the signal is redirected to another waiting thread, if + * there is one. + * + * @param nanosTimeout the maximum time to wait, in nanoseconds + * @return an estimate of the {@code nanosTimeout} value minus + * the time spent waiting upon return from this method. + * A positive value may be used as the argument to a + * subsequent call to this method to finish waiting out + * the desired time. A value less than or equal to zero + * indicates that no time remains. + * @throws InterruptedException if the current thread is interrupted + * (and interruption of thread suspension is supported) + */ + long awaitNanos(long nanosTimeout) throws InterruptedException; + + /** + * Causes the current thread to wait until it is signalled or interrupted, + * or the specified waiting time elapses. This method is behaviorally + * equivalent to:
+ *

+     *   awaitNanos(unit.toNanos(time)) > 0
+     * 
+ * @param time the maximum time to wait + * @param unit the time unit of the {@code time} argument + * @return {@code false} if the waiting time detectably elapsed + * before return from the method, else {@code true} + * @throws InterruptedException if the current thread is interrupted + * (and interruption of thread suspension is supported) + */ + boolean await(long time, TimeUnit unit) throws InterruptedException; + + /** + * Causes the current thread to wait until it is signalled or interrupted, + * or the specified deadline elapses. + * + *

The lock associated with this condition is atomically + * released and the current thread becomes disabled for thread scheduling + * purposes and lies dormant until one of five things happens: + *

    + *
  • Some other thread invokes the {@link #signal} method for this + * {@code Condition} and the current thread happens to be chosen as the + * thread to be awakened; or + *
  • Some other thread invokes the {@link #signalAll} method for this + * {@code Condition}; or + *
  • Some other thread {@linkplain Thread#interrupt interrupts} the + * current thread, and interruption of thread suspension is supported; or + *
  • The specified deadline elapses; or + *
  • A "spurious wakeup" occurs. + *
+ * + *

In all cases, before this method can return the current thread must + * re-acquire the lock associated with this condition. When the + * thread returns it is guaranteed to hold this lock. + * + * + *

If the current thread: + *

    + *
  • has its interrupted status set on entry to this method; or + *
  • is {@linkplain Thread#interrupt interrupted} while waiting + * and interruption of thread suspension is supported, + *
+ * then {@link InterruptedException} is thrown and the current thread's + * interrupted status is cleared. It is not specified, in the first + * case, whether or not the test for interruption occurs before the lock + * is released. + * + * + *

The return value indicates whether the deadline has elapsed, + * which can be used as follows: + *

 {@code
+     * boolean aMethod(Date deadline) {
+     *   boolean stillWaiting = true;
+     *   lock.lock();
+     *   try {
+     *     while (!conditionBeingWaitedFor()) {
+     *       if (!stillWaiting)
+     *         return false;
+     *       stillWaiting = theCondition.awaitUntil(deadline);
+     *     }
+     *     // ...
+     *   } finally {
+     *     lock.unlock();
+     *   }
+     * }}
+ * + *

Implementation Considerations + * + *

The current thread is assumed to hold the lock associated with this + * {@code Condition} when this method is called. + * It is up to the implementation to determine if this is + * the case and if not, how to respond. Typically, an exception will be + * thrown (such as {@link IllegalMonitorStateException}) and the + * implementation must document that fact. + * + *

An implementation can favor responding to an interrupt over normal + * method return in response to a signal, or over indicating the passing + * of the specified deadline. In either case the implementation + * must ensure that the signal is redirected to another waiting thread, if + * there is one. + * + * @param deadline the absolute time to wait until + * @return {@code false} if the deadline has elapsed upon return, else + * {@code true} + * @throws InterruptedException if the current thread is interrupted + * (and interruption of thread suspension is supported) + */ + boolean awaitUntil(Date deadline) throws InterruptedException; + + /** + * Wakes up one waiting thread. + * + *

If any threads are waiting on this condition then one + * is selected for waking up. That thread must then re-acquire the + * lock before returning from {@code await}. + * + *

Implementation Considerations + * + *

An implementation may (and typically does) require that the + * current thread hold the lock associated with this {@code + * Condition} when this method is called. Implementations must + * document this precondition and any actions taken if the lock is + * not held. Typically, an exception such as {@link + * IllegalMonitorStateException} will be thrown. + */ + void signal(); + + /** + * Wakes up all waiting threads. + * + *

If any threads are waiting on this condition then they are + * all woken up. Each thread must re-acquire the lock before it can + * return from {@code await}. + * + *

Implementation Considerations + * + *

An implementation may (and typically does) require that the + * current thread hold the lock associated with this {@code + * Condition} when this method is called. Implementations must + * document this precondition and any actions taken if the lock is + * not held. Typically, an exception such as {@link + * IllegalMonitorStateException} will be thrown. + */ + void signalAll(); +} diff -r e1953d8b8338 -r c8af252ea9eb rt/emul/compact/src/main/java/java/util/concurrent/locks/Lock.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/locks/Lock.java Sat Mar 19 10:48:29 2016 +0100 @@ -0,0 +1,356 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +package java.util.concurrent.locks; +import java.util.concurrent.TimeUnit; + +/** + * {@code Lock} implementations provide more extensive locking + * operations than can be obtained using {@code synchronized} methods + * and statements. They allow more flexible structuring, may have + * quite different properties, and may support multiple associated + * {@link Condition} objects. + * + *

A lock is a tool for controlling access to a shared resource by + * multiple threads. Commonly, a lock provides exclusive access to a + * shared resource: only one thread at a time can acquire the lock and + * all access to the shared resource requires that the lock be + * acquired first. However, some locks may allow concurrent access to + * a shared resource, such as the read lock of a {@link ReadWriteLock}. + * + *

The use of {@code synchronized} methods or statements provides + * access to the implicit monitor lock associated with every object, but + * forces all lock acquisition and release to occur in a block-structured way: + * when multiple locks are acquired they must be released in the opposite + * order, and all locks must be released in the same lexical scope in which + * they were acquired. + * + *

While the scoping mechanism for {@code synchronized} methods + * and statements makes it much easier to program with monitor locks, + * and helps avoid many common programming errors involving locks, + * there are occasions where you need to work with locks in a more + * flexible way. For example, some algorithms for traversing + * concurrently accessed data structures require the use of + * "hand-over-hand" or "chain locking": you + * acquire the lock of node A, then node B, then release A and acquire + * C, then release B and acquire D and so on. Implementations of the + * {@code Lock} interface enable the use of such techniques by + * allowing a lock to be acquired and released in different scopes, + * and allowing multiple locks to be acquired and released in any + * order. + * + *

With this increased flexibility comes additional + * responsibility. The absence of block-structured locking removes the + * automatic release of locks that occurs with {@code synchronized} + * methods and statements. In most cases, the following idiom + * should be used: + * + *

     Lock l = ...;
+ *     l.lock();
+ *     try {
+ *         // access the resource protected by this lock
+ *     } finally {
+ *         l.unlock();
+ *     }
+ * 
+ * + * When locking and unlocking occur in different scopes, care must be + * taken to ensure that all code that is executed while the lock is + * held is protected by try-finally or try-catch to ensure that the + * lock is released when necessary. + * + *

{@code Lock} implementations provide additional functionality + * over the use of {@code synchronized} methods and statements by + * providing a non-blocking attempt to acquire a lock ({@link + * #tryLock()}), an attempt to acquire the lock that can be + * interrupted ({@link #lockInterruptibly}, and an attempt to acquire + * the lock that can timeout ({@link #tryLock(long, TimeUnit)}). + * + *

A {@code Lock} class can also provide behavior and semantics + * that is quite different from that of the implicit monitor lock, + * such as guaranteed ordering, non-reentrant usage, or deadlock + * detection. If an implementation provides such specialized semantics + * then the implementation must document those semantics. + * + *

Note that {@code Lock} instances are just normal objects and can + * themselves be used as the target in a {@code synchronized} statement. + * Acquiring the + * monitor lock of a {@code Lock} instance has no specified relationship + * with invoking any of the {@link #lock} methods of that instance. + * It is recommended that to avoid confusion you never use {@code Lock} + * instances in this way, except within their own implementation. + * + *

Except where noted, passing a {@code null} value for any + * parameter will result in a {@link NullPointerException} being + * thrown. + * + *

Memory Synchronization

+ * + *

All {@code Lock} implementations must enforce the same + * memory synchronization semantics as provided by the built-in monitor + * lock, as described in section 17.4 of + * The Java™ Language Specification: + *

    + *
  • A successful {@code lock} operation has the same memory + * synchronization effects as a successful Lock action. + *
  • A successful {@code unlock} operation has the same + * memory synchronization effects as a successful Unlock action. + *
+ * + * Unsuccessful locking and unlocking operations, and reentrant + * locking/unlocking operations, do not require any memory + * synchronization effects. + * + *

Implementation Considerations

+ * + *

The three forms of lock acquisition (interruptible, + * non-interruptible, and timed) may differ in their performance + * characteristics, ordering guarantees, or other implementation + * qualities. Further, the ability to interrupt the ongoing + * acquisition of a lock may not be available in a given {@code Lock} + * class. Consequently, an implementation is not required to define + * exactly the same guarantees or semantics for all three forms of + * lock acquisition, nor is it required to support interruption of an + * ongoing lock acquisition. An implementation is required to clearly + * document the semantics and guarantees provided by each of the + * locking methods. It must also obey the interruption semantics as + * defined in this interface, to the extent that interruption of lock + * acquisition is supported: which is either totally, or only on + * method entry. + * + *

As interruption generally implies cancellation, and checks for + * interruption are often infrequent, an implementation can favor responding + * to an interrupt over normal method return. This is true even if it can be + * shown that the interrupt occurred after another action may have unblocked + * the thread. An implementation should document this behavior. + * + * @see ReentrantLock + * @see Condition + * @see ReadWriteLock + * + * @since 1.5 + * @author Doug Lea + */ +public interface Lock { + + /** + * Acquires the lock. + * + *

If the lock is not available then the current thread becomes + * disabled for thread scheduling purposes and lies dormant until the + * lock has been acquired. + * + *

Implementation Considerations + * + *

A {@code Lock} implementation may be able to detect erroneous use + * of the lock, such as an invocation that would cause deadlock, and + * may throw an (unchecked) exception in such circumstances. The + * circumstances and the exception type must be documented by that + * {@code Lock} implementation. + */ + void lock(); + + /** + * Acquires the lock unless the current thread is + * {@linkplain Thread#interrupt interrupted}. + * + *

Acquires the lock if it is available and returns immediately. + * + *

If the lock is not available then the current thread becomes + * disabled for thread scheduling purposes and lies dormant until + * one of two things happens: + * + *

    + *
  • The lock is acquired by the current thread; or + *
  • Some other thread {@linkplain Thread#interrupt interrupts} the + * current thread, and interruption of lock acquisition is supported. + *
+ * + *

If the current thread: + *

    + *
  • has its interrupted status set on entry to this method; or + *
  • is {@linkplain Thread#interrupt interrupted} while acquiring the + * lock, and interruption of lock acquisition is supported, + *
+ * then {@link InterruptedException} is thrown and the current thread's + * interrupted status is cleared. + * + *

Implementation Considerations + * + *

The ability to interrupt a lock acquisition in some + * implementations may not be possible, and if possible may be an + * expensive operation. The programmer should be aware that this + * may be the case. An implementation should document when this is + * the case. + * + *

An implementation can favor responding to an interrupt over + * normal method return. + * + *

A {@code Lock} implementation may be able to detect + * erroneous use of the lock, such as an invocation that would + * cause deadlock, and may throw an (unchecked) exception in such + * circumstances. The circumstances and the exception type must + * be documented by that {@code Lock} implementation. + * + * @throws InterruptedException if the current thread is + * interrupted while acquiring the lock (and interruption + * of lock acquisition is supported). + */ + void lockInterruptibly() throws InterruptedException; + + /** + * Acquires the lock only if it is free at the time of invocation. + * + *

Acquires the lock if it is available and returns immediately + * with the value {@code true}. + * If the lock is not available then this method will return + * immediately with the value {@code false}. + * + *

A typical usage idiom for this method would be: + *

+     *      Lock lock = ...;
+     *      if (lock.tryLock()) {
+     *          try {
+     *              // manipulate protected state
+     *          } finally {
+     *              lock.unlock();
+     *          }
+     *      } else {
+     *          // perform alternative actions
+     *      }
+     * 
+ * This usage ensures that the lock is unlocked if it was acquired, and + * doesn't try to unlock if the lock was not acquired. + * + * @return {@code true} if the lock was acquired and + * {@code false} otherwise + */ + boolean tryLock(); + + /** + * Acquires the lock if it is free within the given waiting time and the + * current thread has not been {@linkplain Thread#interrupt interrupted}. + * + *

If the lock is available this method returns immediately + * with the value {@code true}. + * If the lock is not available then + * the current thread becomes disabled for thread scheduling + * purposes and lies dormant until one of three things happens: + *

    + *
  • The lock is acquired by the current thread; or + *
  • Some other thread {@linkplain Thread#interrupt interrupts} the + * current thread, and interruption of lock acquisition is supported; or + *
  • The specified waiting time elapses + *
+ * + *

If the lock is acquired then the value {@code true} is returned. + * + *

If the current thread: + *

    + *
  • has its interrupted status set on entry to this method; or + *
  • is {@linkplain Thread#interrupt interrupted} while acquiring + * the lock, and interruption of lock acquisition is supported, + *
+ * then {@link InterruptedException} is thrown and the current thread's + * interrupted status is cleared. + * + *

If the specified waiting time elapses then the value {@code false} + * is returned. + * If the time is + * less than or equal to zero, the method will not wait at all. + * + *

Implementation Considerations + * + *

The ability to interrupt a lock acquisition in some implementations + * may not be possible, and if possible may + * be an expensive operation. + * The programmer should be aware that this may be the case. An + * implementation should document when this is the case. + * + *

An implementation can favor responding to an interrupt over normal + * method return, or reporting a timeout. + * + *

A {@code Lock} implementation may be able to detect + * erroneous use of the lock, such as an invocation that would cause + * deadlock, and may throw an (unchecked) exception in such circumstances. + * The circumstances and the exception type must be documented by that + * {@code Lock} implementation. + * + * @param time the maximum time to wait for the lock + * @param unit the time unit of the {@code time} argument + * @return {@code true} if the lock was acquired and {@code false} + * if the waiting time elapsed before the lock was acquired + * + * @throws InterruptedException if the current thread is interrupted + * while acquiring the lock (and interruption of lock + * acquisition is supported) + */ + boolean tryLock(long time, TimeUnit unit) throws InterruptedException; + + /** + * Releases the lock. + * + *

Implementation Considerations + * + *

A {@code Lock} implementation will usually impose + * restrictions on which thread can release a lock (typically only the + * holder of the lock can release it) and may throw + * an (unchecked) exception if the restriction is violated. + * Any restrictions and the exception + * type must be documented by that {@code Lock} implementation. + */ + void unlock(); + + /** + * Returns a new {@link Condition} instance that is bound to this + * {@code Lock} instance. + * + *

Before waiting on the condition the lock must be held by the + * current thread. + * A call to {@link Condition#await()} will atomically release the lock + * before waiting and re-acquire the lock before the wait returns. + * + *

Implementation Considerations + * + *

The exact operation of the {@link Condition} instance depends on + * the {@code Lock} implementation and must be documented by that + * implementation. + * + * @return A new {@link Condition} instance for this {@code Lock} instance + * @throws UnsupportedOperationException if this {@code Lock} + * implementation does not support conditions + */ + Condition newCondition(); +} diff -r e1953d8b8338 -r c8af252ea9eb rt/emul/compact/src/main/java/java/util/concurrent/locks/LockSupport.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/locks/LockSupport.java Sat Mar 19 10:48:29 2016 +0100 @@ -0,0 +1,385 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +package java.util.concurrent.locks; +import java.util.concurrent.*; +import sun.misc.Unsafe; + + +/** + * Basic thread blocking primitives for creating locks and other + * synchronization classes. + * + *

This class associates, with each thread that uses it, a permit + * (in the sense of the {@link java.util.concurrent.Semaphore + * Semaphore} class). A call to {@code park} will return immediately + * if the permit is available, consuming it in the process; otherwise + * it may block. A call to {@code unpark} makes the permit + * available, if it was not already available. (Unlike with Semaphores + * though, permits do not accumulate. There is at most one.) + * + *

Methods {@code park} and {@code unpark} provide efficient + * means of blocking and unblocking threads that do not encounter the + * problems that cause the deprecated methods {@code Thread.suspend} + * and {@code Thread.resume} to be unusable for such purposes: Races + * between one thread invoking {@code park} and another thread trying + * to {@code unpark} it will preserve liveness, due to the + * permit. Additionally, {@code park} will return if the caller's + * thread was interrupted, and timeout versions are supported. The + * {@code park} method may also return at any other time, for "no + * reason", so in general must be invoked within a loop that rechecks + * conditions upon return. In this sense {@code park} serves as an + * optimization of a "busy wait" that does not waste as much time + * spinning, but must be paired with an {@code unpark} to be + * effective. + * + *

The three forms of {@code park} each also support a + * {@code blocker} object parameter. This object is recorded while + * the thread is blocked to permit monitoring and diagnostic tools to + * identify the reasons that threads are blocked. (Such tools may + * access blockers using method {@link #getBlocker}.) The use of these + * forms rather than the original forms without this parameter is + * strongly encouraged. The normal argument to supply as a + * {@code blocker} within a lock implementation is {@code this}. + * + *

These methods are designed to be used as tools for creating + * higher-level synchronization utilities, and are not in themselves + * useful for most concurrency control applications. The {@code park} + * method is designed for use only in constructions of the form: + *

while (!canProceed()) { ... LockSupport.park(this); }
+ * where neither {@code canProceed} nor any other actions prior to the + * call to {@code park} entail locking or blocking. Because only one + * permit is associated with each thread, any intermediary uses of + * {@code park} could interfere with its intended effects. + * + *

Sample Usage. Here is a sketch of a first-in-first-out + * non-reentrant lock class: + *

{@code
+ * class FIFOMutex {
+ *   private final AtomicBoolean locked = new AtomicBoolean(false);
+ *   private final Queue waiters
+ *     = new ConcurrentLinkedQueue();
+ *
+ *   public void lock() {
+ *     boolean wasInterrupted = false;
+ *     Thread current = Thread.currentThread();
+ *     waiters.add(current);
+ *
+ *     // Block while not first in queue or cannot acquire lock
+ *     while (waiters.peek() != current ||
+ *            !locked.compareAndSet(false, true)) {
+ *        LockSupport.park(this);
+ *        if (Thread.interrupted()) // ignore interrupts while waiting
+ *          wasInterrupted = true;
+ *     }
+ *
+ *     waiters.remove();
+ *     if (wasInterrupted)          // reassert interrupt status on exit
+ *        current.interrupt();
+ *   }
+ *
+ *   public void unlock() {
+ *     locked.set(false);
+ *     LockSupport.unpark(waiters.peek());
+ *   }
+ * }}
+ */ + +public class LockSupport { + private LockSupport() {} // Cannot be instantiated. + + // Hotspot implementation via intrinsics API + private static final Unsafe unsafe = Unsafe.getUnsafe(); + private static final long parkBlockerOffset; + + static { + try { + parkBlockerOffset = unsafe.objectFieldOffset + (java.lang.Thread.class.getDeclaredField("parkBlocker")); + } catch (Exception ex) { throw new Error(ex); } + } + + private static void setBlocker(Thread t, Object arg) { + // Even though volatile, hotspot doesn't need a write barrier here. + unsafe.putObject(t, parkBlockerOffset, arg); + } + + /** + * Makes available the permit for the given thread, if it + * was not already available. If the thread was blocked on + * {@code park} then it will unblock. Otherwise, its next call + * to {@code park} is guaranteed not to block. This operation + * is not guaranteed to have any effect at all if the given + * thread has not been started. + * + * @param thread the thread to unpark, or {@code null}, in which case + * this operation has no effect + */ + public static void unpark(Thread thread) { + if (thread != null) + unsafe.unpark(thread); + } + + /** + * Disables the current thread for thread scheduling purposes unless the + * permit is available. + * + *

If the permit is available then it is consumed and the call returns + * immediately; otherwise + * the current thread becomes disabled for thread scheduling + * purposes and lies dormant until one of three things happens: + * + *

    + *
  • Some other thread invokes {@link #unpark unpark} with the + * current thread as the target; or + * + *
  • Some other thread {@linkplain Thread#interrupt interrupts} + * the current thread; or + * + *
  • The call spuriously (that is, for no reason) returns. + *
+ * + *

This method does not report which of these caused the + * method to return. Callers should re-check the conditions which caused + * the thread to park in the first place. Callers may also determine, + * for example, the interrupt status of the thread upon return. + * + * @param blocker the synchronization object responsible for this + * thread parking + * @since 1.6 + */ + public static void park(Object blocker) { + Thread t = Thread.currentThread(); + setBlocker(t, blocker); + unsafe.park(false, 0L); + setBlocker(t, null); + } + + /** + * Disables the current thread for thread scheduling purposes, for up to + * the specified waiting time, unless the permit is available. + * + *

If the permit is available then it is consumed and the call + * returns immediately; otherwise the current thread becomes disabled + * for thread scheduling purposes and lies dormant until one of four + * things happens: + * + *

    + *
  • Some other thread invokes {@link #unpark unpark} with the + * current thread as the target; or + * + *
  • Some other thread {@linkplain Thread#interrupt interrupts} + * the current thread; or + * + *
  • The specified waiting time elapses; or + * + *
  • The call spuriously (that is, for no reason) returns. + *
+ * + *

This method does not report which of these caused the + * method to return. Callers should re-check the conditions which caused + * the thread to park in the first place. Callers may also determine, + * for example, the interrupt status of the thread, or the elapsed time + * upon return. + * + * @param blocker the synchronization object responsible for this + * thread parking + * @param nanos the maximum number of nanoseconds to wait + * @since 1.6 + */ + public static void parkNanos(Object blocker, long nanos) { + if (nanos > 0) { + Thread t = Thread.currentThread(); + setBlocker(t, blocker); + unsafe.park(false, nanos); + setBlocker(t, null); + } + } + + /** + * Disables the current thread for thread scheduling purposes, until + * the specified deadline, unless the permit is available. + * + *

If the permit is available then it is consumed and the call + * returns immediately; otherwise the current thread becomes disabled + * for thread scheduling purposes and lies dormant until one of four + * things happens: + * + *

    + *
  • Some other thread invokes {@link #unpark unpark} with the + * current thread as the target; or + * + *
  • Some other thread {@linkplain Thread#interrupt interrupts} the + * current thread; or + * + *
  • The specified deadline passes; or + * + *
  • The call spuriously (that is, for no reason) returns. + *
+ * + *

This method does not report which of these caused the + * method to return. Callers should re-check the conditions which caused + * the thread to park in the first place. Callers may also determine, + * for example, the interrupt status of the thread, or the current time + * upon return. + * + * @param blocker the synchronization object responsible for this + * thread parking + * @param deadline the absolute time, in milliseconds from the Epoch, + * to wait until + * @since 1.6 + */ + public static void parkUntil(Object blocker, long deadline) { + Thread t = Thread.currentThread(); + setBlocker(t, blocker); + unsafe.park(true, deadline); + setBlocker(t, null); + } + + /** + * Returns the blocker object supplied to the most recent + * invocation of a park method that has not yet unblocked, or null + * if not blocked. The value returned is just a momentary + * snapshot -- the thread may have since unblocked or blocked on a + * different blocker object. + * + * @param t the thread + * @return the blocker + * @throws NullPointerException if argument is null + * @since 1.6 + */ + public static Object getBlocker(Thread t) { + if (t == null) + throw new NullPointerException(); + return unsafe.getObjectVolatile(t, parkBlockerOffset); + } + + /** + * Disables the current thread for thread scheduling purposes unless the + * permit is available. + * + *

If the permit is available then it is consumed and the call + * returns immediately; otherwise the current thread becomes disabled + * for thread scheduling purposes and lies dormant until one of three + * things happens: + * + *

    + * + *
  • Some other thread invokes {@link #unpark unpark} with the + * current thread as the target; or + * + *
  • Some other thread {@linkplain Thread#interrupt interrupts} + * the current thread; or + * + *
  • The call spuriously (that is, for no reason) returns. + *
+ * + *

This method does not report which of these caused the + * method to return. Callers should re-check the conditions which caused + * the thread to park in the first place. Callers may also determine, + * for example, the interrupt status of the thread upon return. + */ + public static void park() { + unsafe.park(false, 0L); + } + + /** + * Disables the current thread for thread scheduling purposes, for up to + * the specified waiting time, unless the permit is available. + * + *

If the permit is available then it is consumed and the call + * returns immediately; otherwise the current thread becomes disabled + * for thread scheduling purposes and lies dormant until one of four + * things happens: + * + *

    + *
  • Some other thread invokes {@link #unpark unpark} with the + * current thread as the target; or + * + *
  • Some other thread {@linkplain Thread#interrupt interrupts} + * the current thread; or + * + *
  • The specified waiting time elapses; or + * + *
  • The call spuriously (that is, for no reason) returns. + *
+ * + *

This method does not report which of these caused the + * method to return. Callers should re-check the conditions which caused + * the thread to park in the first place. Callers may also determine, + * for example, the interrupt status of the thread, or the elapsed time + * upon return. + * + * @param nanos the maximum number of nanoseconds to wait + */ + public static void parkNanos(long nanos) { + if (nanos > 0) + unsafe.park(false, nanos); + } + + /** + * Disables the current thread for thread scheduling purposes, until + * the specified deadline, unless the permit is available. + * + *

If the permit is available then it is consumed and the call + * returns immediately; otherwise the current thread becomes disabled + * for thread scheduling purposes and lies dormant until one of four + * things happens: + * + *

    + *
  • Some other thread invokes {@link #unpark unpark} with the + * current thread as the target; or + * + *
  • Some other thread {@linkplain Thread#interrupt interrupts} + * the current thread; or + * + *
  • The specified deadline passes; or + * + *
  • The call spuriously (that is, for no reason) returns. + *
+ * + *

This method does not report which of these caused the + * method to return. Callers should re-check the conditions which caused + * the thread to park in the first place. Callers may also determine, + * for example, the interrupt status of the thread, or the current time + * upon return. + * + * @param deadline the absolute time, in milliseconds from the Epoch, + * to wait until + */ + public static void parkUntil(long deadline) { + unsafe.park(true, deadline); + } +} diff -r e1953d8b8338 -r c8af252ea9eb rt/emul/compact/src/main/java/java/util/concurrent/locks/ReadWriteLock.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/locks/ReadWriteLock.java Sat Mar 19 10:48:29 2016 +0100 @@ -0,0 +1,133 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +package java.util.concurrent.locks; + +/** + * A ReadWriteLock maintains a pair of associated {@link + * Lock locks}, one for read-only operations and one for writing. + * The {@link #readLock read lock} may be held simultaneously by + * multiple reader threads, so long as there are no writers. The + * {@link #writeLock write lock} is exclusive. + * + *

All ReadWriteLock implementations must guarantee that + * the memory synchronization effects of writeLock operations + * (as specified in the {@link Lock} interface) also hold with respect + * to the associated readLock. That is, a thread successfully + * acquiring the read lock will see all updates made upon previous + * release of the write lock. + * + *

A read-write lock allows for a greater level of concurrency in + * accessing shared data than that permitted by a mutual exclusion lock. + * It exploits the fact that while only a single thread at a time (a + * writer thread) can modify the shared data, in many cases any + * number of threads can concurrently read the data (hence reader + * threads). + * In theory, the increase in concurrency permitted by the use of a read-write + * lock will lead to performance improvements over the use of a mutual + * exclusion lock. In practice this increase in concurrency will only be fully + * realized on a multi-processor, and then only if the access patterns for + * the shared data are suitable. + * + *

Whether or not a read-write lock will improve performance over the use + * of a mutual exclusion lock depends on the frequency that the data is + * read compared to being modified, the duration of the read and write + * operations, and the contention for the data - that is, the number of + * threads that will try to read or write the data at the same time. + * For example, a collection that is initially populated with data and + * thereafter infrequently modified, while being frequently searched + * (such as a directory of some kind) is an ideal candidate for the use of + * a read-write lock. However, if updates become frequent then the data + * spends most of its time being exclusively locked and there is little, if any + * increase in concurrency. Further, if the read operations are too short + * the overhead of the read-write lock implementation (which is inherently + * more complex than a mutual exclusion lock) can dominate the execution + * cost, particularly as many read-write lock implementations still serialize + * all threads through a small section of code. Ultimately, only profiling + * and measurement will establish whether the use of a read-write lock is + * suitable for your application. + * + * + *

Although the basic operation of a read-write lock is straight-forward, + * there are many policy decisions that an implementation must make, which + * may affect the effectiveness of the read-write lock in a given application. + * Examples of these policies include: + *

    + *
  • Determining whether to grant the read lock or the write lock, when + * both readers and writers are waiting, at the time that a writer releases + * the write lock. Writer preference is common, as writes are expected to be + * short and infrequent. Reader preference is less common as it can lead to + * lengthy delays for a write if the readers are frequent and long-lived as + * expected. Fair, or "in-order" implementations are also possible. + * + *
  • Determining whether readers that request the read lock while a + * reader is active and a writer is waiting, are granted the read lock. + * Preference to the reader can delay the writer indefinitely, while + * preference to the writer can reduce the potential for concurrency. + * + *
  • Determining whether the locks are reentrant: can a thread with the + * write lock reacquire it? Can it acquire a read lock while holding the + * write lock? Is the read lock itself reentrant? + * + *
  • Can the write lock be downgraded to a read lock without allowing + * an intervening writer? Can a read lock be upgraded to a write lock, + * in preference to other waiting readers or writers? + * + *
+ * You should consider all of these things when evaluating the suitability + * of a given implementation for your application. + * + * @see ReentrantReadWriteLock + * @see Lock + * @see ReentrantLock + * + * @since 1.5 + * @author Doug Lea + */ +public interface ReadWriteLock { + /** + * Returns the lock used for reading. + * + * @return the lock used for reading. + */ + Lock readLock(); + + /** + * Returns the lock used for writing. + * + * @return the lock used for writing. + */ + Lock writeLock(); +} diff -r e1953d8b8338 -r c8af252ea9eb rt/emul/compact/src/main/java/java/util/concurrent/locks/ReentrantLock.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/locks/ReentrantLock.java Sat Mar 19 10:48:29 2016 +0100 @@ -0,0 +1,770 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +package java.util.concurrent.locks; +import java.util.*; +import java.util.concurrent.*; +import java.util.concurrent.atomic.*; + +/** + * A reentrant mutual exclusion {@link Lock} with the same basic + * behavior and semantics as the implicit monitor lock accessed using + * {@code synchronized} methods and statements, but with extended + * capabilities. + * + *

A {@code ReentrantLock} is owned by the thread last + * successfully locking, but not yet unlocking it. A thread invoking + * {@code lock} will return, successfully acquiring the lock, when + * the lock is not owned by another thread. The method will return + * immediately if the current thread already owns the lock. This can + * be checked using methods {@link #isHeldByCurrentThread}, and {@link + * #getHoldCount}. + * + *

The constructor for this class accepts an optional + * fairness parameter. When set {@code true}, under + * contention, locks favor granting access to the longest-waiting + * thread. Otherwise this lock does not guarantee any particular + * access order. Programs using fair locks accessed by many threads + * may display lower overall throughput (i.e., are slower; often much + * slower) than those using the default setting, but have smaller + * variances in times to obtain locks and guarantee lack of + * starvation. Note however, that fairness of locks does not guarantee + * fairness of thread scheduling. Thus, one of many threads using a + * fair lock may obtain it multiple times in succession while other + * active threads are not progressing and not currently holding the + * lock. + * Also note that the untimed {@link #tryLock() tryLock} method does not + * honor the fairness setting. It will succeed if the lock + * is available even if other threads are waiting. + * + *

It is recommended practice to always immediately + * follow a call to {@code lock} with a {@code try} block, most + * typically in a before/after construction such as: + * + *

+ * class X {
+ *   private final ReentrantLock lock = new ReentrantLock();
+ *   // ...
+ *
+ *   public void m() {
+ *     lock.lock();  // block until condition holds
+ *     try {
+ *       // ... method body
+ *     } finally {
+ *       lock.unlock()
+ *     }
+ *   }
+ * }
+ * 
+ * + *

In addition to implementing the {@link Lock} interface, this + * class defines methods {@code isLocked} and + * {@code getLockQueueLength}, as well as some associated + * {@code protected} access methods that may be useful for + * instrumentation and monitoring. + * + *

Serialization of this class behaves in the same way as built-in + * locks: a deserialized lock is in the unlocked state, regardless of + * its state when serialized. + * + *

This lock supports a maximum of 2147483647 recursive locks by + * the same thread. Attempts to exceed this limit result in + * {@link Error} throws from locking methods. + * + * @since 1.5 + * @author Doug Lea + */ +public class ReentrantLock implements Lock, java.io.Serializable { + private static final long serialVersionUID = 7373984872572414699L; + /** Synchronizer providing all implementation mechanics */ + private final Sync sync; + + /** + * Base of synchronization control for this lock. Subclassed + * into fair and nonfair versions below. Uses AQS state to + * represent the number of holds on the lock. + */ + abstract static class Sync extends AbstractQueuedSynchronizer { + private static final long serialVersionUID = -5179523762034025860L; + + /** + * Performs {@link Lock#lock}. The main reason for subclassing + * is to allow fast path for nonfair version. + */ + abstract void lock(); + + /** + * Performs non-fair tryLock. tryAcquire is + * implemented in subclasses, but both need nonfair + * try for trylock method. + */ + final boolean nonfairTryAcquire(int acquires) { + final Thread current = Thread.currentThread(); + int c = getState(); + if (c == 0) { + if (compareAndSetState(0, acquires)) { + setExclusiveOwnerThread(current); + return true; + } + } + else if (current == getExclusiveOwnerThread()) { + int nextc = c + acquires; + if (nextc < 0) // overflow + throw new Error("Maximum lock count exceeded"); + setState(nextc); + return true; + } + return false; + } + + protected final boolean tryRelease(int releases) { + int c = getState() - releases; + if (Thread.currentThread() != getExclusiveOwnerThread()) + throw new IllegalMonitorStateException(); + boolean free = false; + if (c == 0) { + free = true; + setExclusiveOwnerThread(null); + } + setState(c); + return free; + } + + protected final boolean isHeldExclusively() { + // While we must in general read state before owner, + // we don't need to do so to check if current thread is owner + return getExclusiveOwnerThread() == Thread.currentThread(); + } + + final ConditionObject newCondition() { + return new ConditionObject(); + } + + // Methods relayed from outer class + + final Thread getOwner() { + return getState() == 0 ? null : getExclusiveOwnerThread(); + } + + final int getHoldCount() { + return isHeldExclusively() ? getState() : 0; + } + + final boolean isLocked() { + return getState() != 0; + } + + /** + * Reconstitutes this lock instance from a stream. + * @param s the stream + */ + private void readObject(java.io.ObjectInputStream s) + throws java.io.IOException, ClassNotFoundException { + s.defaultReadObject(); + setState(0); // reset to unlocked state + } + } + + /** + * Sync object for non-fair locks + */ + static final class NonfairSync extends Sync { + private static final long serialVersionUID = 7316153563782823691L; + + /** + * Performs lock. Try immediate barge, backing up to normal + * acquire on failure. + */ + final void lock() { + if (compareAndSetState(0, 1)) + setExclusiveOwnerThread(Thread.currentThread()); + else + acquire(1); + } + + protected final boolean tryAcquire(int acquires) { + return nonfairTryAcquire(acquires); + } + } + + /** + * Sync object for fair locks + */ + static final class FairSync extends Sync { + private static final long serialVersionUID = -3000897897090466540L; + + final void lock() { + acquire(1); + } + + /** + * Fair version of tryAcquire. Don't grant access unless + * recursive call or no waiters or is first. + */ + protected final boolean tryAcquire(int acquires) { + final Thread current = Thread.currentThread(); + int c = getState(); + if (c == 0) { + if (!hasQueuedPredecessors() && + compareAndSetState(0, acquires)) { + setExclusiveOwnerThread(current); + return true; + } + } + else if (current == getExclusiveOwnerThread()) { + int nextc = c + acquires; + if (nextc < 0) + throw new Error("Maximum lock count exceeded"); + setState(nextc); + return true; + } + return false; + } + } + + /** + * Creates an instance of {@code ReentrantLock}. + * This is equivalent to using {@code ReentrantLock(false)}. + */ + public ReentrantLock() { + sync = new NonfairSync(); + } + + /** + * Creates an instance of {@code ReentrantLock} with the + * given fairness policy. + * + * @param fair {@code true} if this lock should use a fair ordering policy + */ + public ReentrantLock(boolean fair) { + sync = fair ? new FairSync() : new NonfairSync(); + } + + /** + * Acquires the lock. + * + *

Acquires the lock if it is not held by another thread and returns + * immediately, setting the lock hold count to one. + * + *

If the current thread already holds the lock then the hold + * count is incremented by one and the method returns immediately. + * + *

If the lock is held by another thread then the + * current thread becomes disabled for thread scheduling + * purposes and lies dormant until the lock has been acquired, + * at which time the lock hold count is set to one. + */ + public void lock() { + sync.lock(); + } + + /** + * Acquires the lock unless the current thread is + * {@linkplain Thread#interrupt interrupted}. + * + *

Acquires the lock if it is not held by another thread and returns + * immediately, setting the lock hold count to one. + * + *

If the current thread already holds this lock then the hold count + * is incremented by one and the method returns immediately. + * + *

If the lock is held by another thread then the + * current thread becomes disabled for thread scheduling + * purposes and lies dormant until one of two things happens: + * + *

    + * + *
  • The lock is acquired by the current thread; or + * + *
  • Some other thread {@linkplain Thread#interrupt interrupts} the + * current thread. + * + *
+ * + *

If the lock is acquired by the current thread then the lock hold + * count is set to one. + * + *

If the current thread: + * + *

    + * + *
  • has its interrupted status set on entry to this method; or + * + *
  • is {@linkplain Thread#interrupt interrupted} while acquiring + * the lock, + * + *
+ * + * then {@link InterruptedException} is thrown and the current thread's + * interrupted status is cleared. + * + *

In this implementation, as this method is an explicit + * interruption point, preference is given to responding to the + * interrupt over normal or reentrant acquisition of the lock. + * + * @throws InterruptedException if the current thread is interrupted + */ + public void lockInterruptibly() throws InterruptedException { + sync.acquireInterruptibly(1); + } + + /** + * Acquires the lock only if it is not held by another thread at the time + * of invocation. + * + *

Acquires the lock if it is not held by another thread and + * returns immediately with the value {@code true}, setting the + * lock hold count to one. Even when this lock has been set to use a + * fair ordering policy, a call to {@code tryLock()} will + * immediately acquire the lock if it is available, whether or not + * other threads are currently waiting for the lock. + * This "barging" behavior can be useful in certain + * circumstances, even though it breaks fairness. If you want to honor + * the fairness setting for this lock, then use + * {@link #tryLock(long, TimeUnit) tryLock(0, TimeUnit.SECONDS) } + * which is almost equivalent (it also detects interruption). + * + *

If the current thread already holds this lock then the hold + * count is incremented by one and the method returns {@code true}. + * + *

If the lock is held by another thread then this method will return + * immediately with the value {@code false}. + * + * @return {@code true} if the lock was free and was acquired by the + * current thread, or the lock was already held by the current + * thread; and {@code false} otherwise + */ + public boolean tryLock() { + return sync.nonfairTryAcquire(1); + } + + /** + * Acquires the lock if it is not held by another thread within the given + * waiting time and the current thread has not been + * {@linkplain Thread#interrupt interrupted}. + * + *

Acquires the lock if it is not held by another thread and returns + * immediately with the value {@code true}, setting the lock hold count + * to one. If this lock has been set to use a fair ordering policy then + * an available lock will not be acquired if any other threads + * are waiting for the lock. This is in contrast to the {@link #tryLock()} + * method. If you want a timed {@code tryLock} that does permit barging on + * a fair lock then combine the timed and un-timed forms together: + * + *

if (lock.tryLock() || lock.tryLock(timeout, unit) ) { ... }
+     * 
+ * + *

If the current thread + * already holds this lock then the hold count is incremented by one and + * the method returns {@code true}. + * + *

If the lock is held by another thread then the + * current thread becomes disabled for thread scheduling + * purposes and lies dormant until one of three things happens: + * + *

    + * + *
  • The lock is acquired by the current thread; or + * + *
  • Some other thread {@linkplain Thread#interrupt interrupts} + * the current thread; or + * + *
  • The specified waiting time elapses + * + *
+ * + *

If the lock is acquired then the value {@code true} is returned and + * the lock hold count is set to one. + * + *

If the current thread: + * + *

    + * + *
  • has its interrupted status set on entry to this method; or + * + *
  • is {@linkplain Thread#interrupt interrupted} while + * acquiring the lock, + * + *
+ * then {@link InterruptedException} is thrown and the current thread's + * interrupted status is cleared. + * + *

If the specified waiting time elapses then the value {@code false} + * is returned. If the time is less than or equal to zero, the method + * will not wait at all. + * + *

In this implementation, as this method is an explicit + * interruption point, preference is given to responding to the + * interrupt over normal or reentrant acquisition of the lock, and + * over reporting the elapse of the waiting time. + * + * @param timeout the time to wait for the lock + * @param unit the time unit of the timeout argument + * @return {@code true} if the lock was free and was acquired by the + * current thread, or the lock was already held by the current + * thread; and {@code false} if the waiting time elapsed before + * the lock could be acquired + * @throws InterruptedException if the current thread is interrupted + * @throws NullPointerException if the time unit is null + * + */ + public boolean tryLock(long timeout, TimeUnit unit) + throws InterruptedException { + return sync.tryAcquireNanos(1, unit.toNanos(timeout)); + } + + /** + * Attempts to release this lock. + * + *

If the current thread is the holder of this lock then the hold + * count is decremented. If the hold count is now zero then the lock + * is released. If the current thread is not the holder of this + * lock then {@link IllegalMonitorStateException} is thrown. + * + * @throws IllegalMonitorStateException if the current thread does not + * hold this lock + */ + public void unlock() { + sync.release(1); + } + + /** + * Returns a {@link Condition} instance for use with this + * {@link Lock} instance. + * + *

The returned {@link Condition} instance supports the same + * usages as do the {@link Object} monitor methods ({@link + * Object#wait() wait}, {@link Object#notify notify}, and {@link + * Object#notifyAll notifyAll}) when used with the built-in + * monitor lock. + * + *

    + * + *
  • If this lock is not held when any of the {@link Condition} + * {@linkplain Condition#await() waiting} or {@linkplain + * Condition#signal signalling} methods are called, then an {@link + * IllegalMonitorStateException} is thrown. + * + *
  • When the condition {@linkplain Condition#await() waiting} + * methods are called the lock is released and, before they + * return, the lock is reacquired and the lock hold count restored + * to what it was when the method was called. + * + *
  • If a thread is {@linkplain Thread#interrupt interrupted} + * while waiting then the wait will terminate, an {@link + * InterruptedException} will be thrown, and the thread's + * interrupted status will be cleared. + * + *
  • Waiting threads are signalled in FIFO order. + * + *
  • The ordering of lock reacquisition for threads returning + * from waiting methods is the same as for threads initially + * acquiring the lock, which is in the default case not specified, + * but for fair locks favors those threads that have been + * waiting the longest. + * + *
+ * + * @return the Condition object + */ + public Condition newCondition() { + return sync.newCondition(); + } + + /** + * Queries the number of holds on this lock by the current thread. + * + *

A thread has a hold on a lock for each lock action that is not + * matched by an unlock action. + * + *

The hold count information is typically only used for testing and + * debugging purposes. For example, if a certain section of code should + * not be entered with the lock already held then we can assert that + * fact: + * + *

+     * class X {
+     *   ReentrantLock lock = new ReentrantLock();
+     *   // ...
+     *   public void m() {
+     *     assert lock.getHoldCount() == 0;
+     *     lock.lock();
+     *     try {
+     *       // ... method body
+     *     } finally {
+     *       lock.unlock();
+     *     }
+     *   }
+     * }
+     * 
+ * + * @return the number of holds on this lock by the current thread, + * or zero if this lock is not held by the current thread + */ + public int getHoldCount() { + return sync.getHoldCount(); + } + + /** + * Queries if this lock is held by the current thread. + * + *

Analogous to the {@link Thread#holdsLock} method for built-in + * monitor locks, this method is typically used for debugging and + * testing. For example, a method that should only be called while + * a lock is held can assert that this is the case: + * + *

+     * class X {
+     *   ReentrantLock lock = new ReentrantLock();
+     *   // ...
+     *
+     *   public void m() {
+     *       assert lock.isHeldByCurrentThread();
+     *       // ... method body
+     *   }
+     * }
+     * 
+ * + *

It can also be used to ensure that a reentrant lock is used + * in a non-reentrant manner, for example: + * + *

+     * class X {
+     *   ReentrantLock lock = new ReentrantLock();
+     *   // ...
+     *
+     *   public void m() {
+     *       assert !lock.isHeldByCurrentThread();
+     *       lock.lock();
+     *       try {
+     *           // ... method body
+     *       } finally {
+     *           lock.unlock();
+     *       }
+     *   }
+     * }
+     * 
+ * + * @return {@code true} if current thread holds this lock and + * {@code false} otherwise + */ + public boolean isHeldByCurrentThread() { + return sync.isHeldExclusively(); + } + + /** + * Queries if this lock is held by any thread. This method is + * designed for use in monitoring of the system state, + * not for synchronization control. + * + * @return {@code true} if any thread holds this lock and + * {@code false} otherwise + */ + public boolean isLocked() { + return sync.isLocked(); + } + + /** + * Returns {@code true} if this lock has fairness set true. + * + * @return {@code true} if this lock has fairness set true + */ + public final boolean isFair() { + return sync instanceof FairSync; + } + + /** + * Returns the thread that currently owns this lock, or + * {@code null} if not owned. When this method is called by a + * thread that is not the owner, the return value reflects a + * best-effort approximation of current lock status. For example, + * the owner may be momentarily {@code null} even if there are + * threads trying to acquire the lock but have not yet done so. + * This method is designed to facilitate construction of + * subclasses that provide more extensive lock monitoring + * facilities. + * + * @return the owner, or {@code null} if not owned + */ + protected Thread getOwner() { + return sync.getOwner(); + } + + /** + * Queries whether any threads are waiting to acquire this lock. Note that + * because cancellations may occur at any time, a {@code true} + * return does not guarantee that any other thread will ever + * acquire this lock. This method is designed primarily for use in + * monitoring of the system state. + * + * @return {@code true} if there may be other threads waiting to + * acquire the lock + */ + public final boolean hasQueuedThreads() { + return sync.hasQueuedThreads(); + } + + + /** + * Queries whether the given thread is waiting to acquire this + * lock. Note that because cancellations may occur at any time, a + * {@code true} return does not guarantee that this thread + * will ever acquire this lock. This method is designed primarily for use + * in monitoring of the system state. + * + * @param thread the thread + * @return {@code true} if the given thread is queued waiting for this lock + * @throws NullPointerException if the thread is null + */ + public final boolean hasQueuedThread(Thread thread) { + return sync.isQueued(thread); + } + + + /** + * Returns an estimate of the number of threads waiting to + * acquire this lock. The value is only an estimate because the number of + * threads may change dynamically while this method traverses + * internal data structures. This method is designed for use in + * monitoring of the system state, not for synchronization + * control. + * + * @return the estimated number of threads waiting for this lock + */ + public final int getQueueLength() { + return sync.getQueueLength(); + } + + /** + * Returns a collection containing threads that may be waiting to + * acquire this lock. Because the actual set of threads may change + * dynamically while constructing this result, the returned + * collection is only a best-effort estimate. The elements of the + * returned collection are in no particular order. This method is + * designed to facilitate construction of subclasses that provide + * more extensive monitoring facilities. + * + * @return the collection of threads + */ + protected Collection getQueuedThreads() { + return sync.getQueuedThreads(); + } + + /** + * Queries whether any threads are waiting on the given condition + * associated with this lock. Note that because timeouts and + * interrupts may occur at any time, a {@code true} return does + * not guarantee that a future {@code signal} will awaken any + * threads. This method is designed primarily for use in + * monitoring of the system state. + * + * @param condition the condition + * @return {@code true} if there are any waiting threads + * @throws IllegalMonitorStateException if this lock is not held + * @throws IllegalArgumentException if the given condition is + * not associated with this lock + * @throws NullPointerException if the condition is null + */ + public boolean hasWaiters(Condition condition) { + if (condition == null) + throw new NullPointerException(); + if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject)) + throw new IllegalArgumentException("not owner"); + return sync.hasWaiters((AbstractQueuedSynchronizer.ConditionObject)condition); + } + + /** + * Returns an estimate of the number of threads waiting on the + * given condition associated with this lock. Note that because + * timeouts and interrupts may occur at any time, the estimate + * serves only as an upper bound on the actual number of waiters. + * This method is designed for use in monitoring of the system + * state, not for synchronization control. + * + * @param condition the condition + * @return the estimated number of waiting threads + * @throws IllegalMonitorStateException if this lock is not held + * @throws IllegalArgumentException if the given condition is + * not associated with this lock + * @throws NullPointerException if the condition is null + */ + public int getWaitQueueLength(Condition condition) { + if (condition == null) + throw new NullPointerException(); + if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject)) + throw new IllegalArgumentException("not owner"); + return sync.getWaitQueueLength((AbstractQueuedSynchronizer.ConditionObject)condition); + } + + /** + * Returns a collection containing those threads that may be + * waiting on the given condition associated with this lock. + * Because the actual set of threads may change dynamically while + * constructing this result, the returned collection is only a + * best-effort estimate. The elements of the returned collection + * are in no particular order. This method is designed to + * facilitate construction of subclasses that provide more + * extensive condition monitoring facilities. + * + * @param condition the condition + * @return the collection of threads + * @throws IllegalMonitorStateException if this lock is not held + * @throws IllegalArgumentException if the given condition is + * not associated with this lock + * @throws NullPointerException if the condition is null + */ + protected Collection getWaitingThreads(Condition condition) { + if (condition == null) + throw new NullPointerException(); + if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject)) + throw new IllegalArgumentException("not owner"); + return sync.getWaitingThreads((AbstractQueuedSynchronizer.ConditionObject)condition); + } + + /** + * Returns a string identifying this lock, as well as its lock state. + * The state, in brackets, includes either the String {@code "Unlocked"} + * or the String {@code "Locked by"} followed by the + * {@linkplain Thread#getName name} of the owning thread. + * + * @return a string identifying this lock, as well as its lock state + */ + public String toString() { + Thread o = sync.getOwner(); + return super.toString() + ((o == null) ? + "[Unlocked]" : + "[Locked by thread " + o.getName() + "]"); + } +} diff -r e1953d8b8338 -r c8af252ea9eb rt/emul/compact/src/main/java/java/util/concurrent/locks/ReentrantReadWriteLock.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/locks/ReentrantReadWriteLock.java Sat Mar 19 10:48:29 2016 +0100 @@ -0,0 +1,1486 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +package java.util.concurrent.locks; +import java.util.concurrent.*; +import java.util.concurrent.atomic.*; +import java.util.*; + +/** + * An implementation of {@link ReadWriteLock} supporting similar + * semantics to {@link ReentrantLock}. + *

This class has the following properties: + * + *

    + *
  • Acquisition order + * + *

    This class does not impose a reader or writer preference + * ordering for lock access. However, it does support an optional + * fairness policy. + * + *

    + *
    Non-fair mode (default) + *
    When constructed as non-fair (the default), the order of entry + * to the read and write lock is unspecified, subject to reentrancy + * constraints. A nonfair lock that is continuously contended may + * indefinitely postpone one or more reader or writer threads, but + * will normally have higher throughput than a fair lock. + *

    + * + *

    Fair mode + *
    When constructed as fair, threads contend for entry using an + * approximately arrival-order policy. When the currently held lock + * is released either the longest-waiting single writer thread will + * be assigned the write lock, or if there is a group of reader threads + * waiting longer than all waiting writer threads, that group will be + * assigned the read lock. + * + *

    A thread that tries to acquire a fair read lock (non-reentrantly) + * will block if either the write lock is held, or there is a waiting + * writer thread. The thread will not acquire the read lock until + * after the oldest currently waiting writer thread has acquired and + * released the write lock. Of course, if a waiting writer abandons + * its wait, leaving one or more reader threads as the longest waiters + * in the queue with the write lock free, then those readers will be + * assigned the read lock. + * + *

    A thread that tries to acquire a fair write lock (non-reentrantly) + * will block unless both the read lock and write lock are free (which + * implies there are no waiting threads). (Note that the non-blocking + * {@link ReadLock#tryLock()} and {@link WriteLock#tryLock()} methods + * do not honor this fair setting and will acquire the lock if it is + * possible, regardless of waiting threads.) + *

    + *

    + * + *
  • Reentrancy + * + *

    This lock allows both readers and writers to reacquire read or + * write locks in the style of a {@link ReentrantLock}. Non-reentrant + * readers are not allowed until all write locks held by the writing + * thread have been released. + * + *

    Additionally, a writer can acquire the read lock, but not + * vice-versa. Among other applications, reentrancy can be useful + * when write locks are held during calls or callbacks to methods that + * perform reads under read locks. If a reader tries to acquire the + * write lock it will never succeed. + * + *

  • Lock downgrading + *

    Reentrancy also allows downgrading from the write lock to a read lock, + * by acquiring the write lock, then the read lock and then releasing the + * write lock. However, upgrading from a read lock to the write lock is + * not possible. + * + *

  • Interruption of lock acquisition + *

    The read lock and write lock both support interruption during lock + * acquisition. + * + *

  • {@link Condition} support + *

    The write lock provides a {@link Condition} implementation that + * behaves in the same way, with respect to the write lock, as the + * {@link Condition} implementation provided by + * {@link ReentrantLock#newCondition} does for {@link ReentrantLock}. + * This {@link Condition} can, of course, only be used with the write lock. + * + *

    The read lock does not support a {@link Condition} and + * {@code readLock().newCondition()} throws + * {@code UnsupportedOperationException}. + * + *

  • Instrumentation + *

    This class supports methods to determine whether locks + * are held or contended. These methods are designed for monitoring + * system state, not for synchronization control. + *

+ * + *

Serialization of this class behaves in the same way as built-in + * locks: a deserialized lock is in the unlocked state, regardless of + * its state when serialized. + * + *

Sample usages. Here is a code sketch showing how to perform + * lock downgrading after updating a cache (exception handling is + * particularly tricky when handling multiple locks in a non-nested + * fashion): + * + *

 {@code
+ * class CachedData {
+ *   Object data;
+ *   volatile boolean cacheValid;
+ *   final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
+ *
+ *   void processCachedData() {
+ *     rwl.readLock().lock();
+ *     if (!cacheValid) {
+ *        // Must release read lock before acquiring write lock
+ *        rwl.readLock().unlock();
+ *        rwl.writeLock().lock();
+ *        try {
+ *          // Recheck state because another thread might have
+ *          // acquired write lock and changed state before we did.
+ *          if (!cacheValid) {
+ *            data = ...
+ *            cacheValid = true;
+ *          }
+ *          // Downgrade by acquiring read lock before releasing write lock
+ *          rwl.readLock().lock();
+ *        } finally {
+ *          rwl.writeLock().unlock(); // Unlock write, still hold read
+ *        }
+ *     }
+ *
+ *     try {
+ *       use(data);
+ *     } finally {
+ *       rwl.readLock().unlock();
+ *     }
+ *   }
+ * }}
+ * + * ReentrantReadWriteLocks can be used to improve concurrency in some + * uses of some kinds of Collections. This is typically worthwhile + * only when the collections are expected to be large, accessed by + * more reader threads than writer threads, and entail operations with + * overhead that outweighs synchronization overhead. For example, here + * is a class using a TreeMap that is expected to be large and + * concurrently accessed. + * + *
{@code
+ * class RWDictionary {
+ *    private final Map m = new TreeMap();
+ *    private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
+ *    private final Lock r = rwl.readLock();
+ *    private final Lock w = rwl.writeLock();
+ *
+ *    public Data get(String key) {
+ *        r.lock();
+ *        try { return m.get(key); }
+ *        finally { r.unlock(); }
+ *    }
+ *    public String[] allKeys() {
+ *        r.lock();
+ *        try { return m.keySet().toArray(); }
+ *        finally { r.unlock(); }
+ *    }
+ *    public Data put(String key, Data value) {
+ *        w.lock();
+ *        try { return m.put(key, value); }
+ *        finally { w.unlock(); }
+ *    }
+ *    public void clear() {
+ *        w.lock();
+ *        try { m.clear(); }
+ *        finally { w.unlock(); }
+ *    }
+ * }}
+ * + *

Implementation Notes

+ * + *

This lock supports a maximum of 65535 recursive write locks + * and 65535 read locks. Attempts to exceed these limits result in + * {@link Error} throws from locking methods. + * + * @since 1.5 + * @author Doug Lea + * + */ +public class ReentrantReadWriteLock + implements ReadWriteLock, java.io.Serializable { + private static final long serialVersionUID = -6992448646407690164L; + /** Inner class providing readlock */ + private final ReentrantReadWriteLock.ReadLock readerLock; + /** Inner class providing writelock */ + private final ReentrantReadWriteLock.WriteLock writerLock; + /** Performs all synchronization mechanics */ + final Sync sync; + + /** + * Creates a new {@code ReentrantReadWriteLock} with + * default (nonfair) ordering properties. + */ + public ReentrantReadWriteLock() { + this(false); + } + + /** + * Creates a new {@code ReentrantReadWriteLock} with + * the given fairness policy. + * + * @param fair {@code true} if this lock should use a fair ordering policy + */ + public ReentrantReadWriteLock(boolean fair) { + sync = fair ? new FairSync() : new NonfairSync(); + readerLock = new ReadLock(this); + writerLock = new WriteLock(this); + } + + public ReentrantReadWriteLock.WriteLock writeLock() { return writerLock; } + public ReentrantReadWriteLock.ReadLock readLock() { return readerLock; } + + /** + * Synchronization implementation for ReentrantReadWriteLock. + * Subclassed into fair and nonfair versions. + */ + abstract static class Sync extends AbstractQueuedSynchronizer { + private static final long serialVersionUID = 6317671515068378041L; + + /* + * Read vs write count extraction constants and functions. + * Lock state is logically divided into two unsigned shorts: + * The lower one representing the exclusive (writer) lock hold count, + * and the upper the shared (reader) hold count. + */ + + static final int SHARED_SHIFT = 16; + static final int SHARED_UNIT = (1 << SHARED_SHIFT); + static final int MAX_COUNT = (1 << SHARED_SHIFT) - 1; + static final int EXCLUSIVE_MASK = (1 << SHARED_SHIFT) - 1; + + /** Returns the number of shared holds represented in count */ + static int sharedCount(int c) { return c >>> SHARED_SHIFT; } + /** Returns the number of exclusive holds represented in count */ + static int exclusiveCount(int c) { return c & EXCLUSIVE_MASK; } + + /** + * A counter for per-thread read hold counts. + * Maintained as a ThreadLocal; cached in cachedHoldCounter + */ + static final class HoldCounter { + int count = 0; + // Use id, not reference, to avoid garbage retention + final long tid = Thread.currentThread().getId(); + } + + /** + * ThreadLocal subclass. Easiest to explicitly define for sake + * of deserialization mechanics. + */ + static final class ThreadLocalHoldCounter + extends ThreadLocal { + public HoldCounter initialValue() { + return new HoldCounter(); + } + } + + /** + * The number of reentrant read locks held by current thread. + * Initialized only in constructor and readObject. + * Removed whenever a thread's read hold count drops to 0. + */ + private transient ThreadLocalHoldCounter readHolds; + + /** + * The hold count of the last thread to successfully acquire + * readLock. This saves ThreadLocal lookup in the common case + * where the next thread to release is the last one to + * acquire. This is non-volatile since it is just used + * as a heuristic, and would be great for threads to cache. + * + *

Can outlive the Thread for which it is caching the read + * hold count, but avoids garbage retention by not retaining a + * reference to the Thread. + * + *

Accessed via a benign data race; relies on the memory + * model's final field and out-of-thin-air guarantees. + */ + private transient HoldCounter cachedHoldCounter; + + /** + * firstReader is the first thread to have acquired the read lock. + * firstReaderHoldCount is firstReader's hold count. + * + *

More precisely, firstReader is the unique thread that last + * changed the shared count from 0 to 1, and has not released the + * read lock since then; null if there is no such thread. + * + *

Cannot cause garbage retention unless the thread terminated + * without relinquishing its read locks, since tryReleaseShared + * sets it to null. + * + *

Accessed via a benign data race; relies on the memory + * model's out-of-thin-air guarantees for references. + * + *

This allows tracking of read holds for uncontended read + * locks to be very cheap. + */ + private transient Thread firstReader = null; + private transient int firstReaderHoldCount; + + Sync() { + readHolds = new ThreadLocalHoldCounter(); + setState(getState()); // ensures visibility of readHolds + } + + /* + * Acquires and releases use the same code for fair and + * nonfair locks, but differ in whether/how they allow barging + * when queues are non-empty. + */ + + /** + * Returns true if the current thread, when trying to acquire + * the read lock, and otherwise eligible to do so, should block + * because of policy for overtaking other waiting threads. + */ + abstract boolean readerShouldBlock(); + + /** + * Returns true if the current thread, when trying to acquire + * the write lock, and otherwise eligible to do so, should block + * because of policy for overtaking other waiting threads. + */ + abstract boolean writerShouldBlock(); + + /* + * Note that tryRelease and tryAcquire can be called by + * Conditions. So it is possible that their arguments contain + * both read and write holds that are all released during a + * condition wait and re-established in tryAcquire. + */ + + protected final boolean tryRelease(int releases) { + if (!isHeldExclusively()) + throw new IllegalMonitorStateException(); + int nextc = getState() - releases; + boolean free = exclusiveCount(nextc) == 0; + if (free) + setExclusiveOwnerThread(null); + setState(nextc); + return free; + } + + protected final boolean tryAcquire(int acquires) { + /* + * Walkthrough: + * 1. If read count nonzero or write count nonzero + * and owner is a different thread, fail. + * 2. If count would saturate, fail. (This can only + * happen if count is already nonzero.) + * 3. Otherwise, this thread is eligible for lock if + * it is either a reentrant acquire or + * queue policy allows it. If so, update state + * and set owner. + */ + Thread current = Thread.currentThread(); + int c = getState(); + int w = exclusiveCount(c); + if (c != 0) { + // (Note: if c != 0 and w == 0 then shared count != 0) + if (w == 0 || current != getExclusiveOwnerThread()) + return false; + if (w + exclusiveCount(acquires) > MAX_COUNT) + throw new Error("Maximum lock count exceeded"); + // Reentrant acquire + setState(c + acquires); + return true; + } + if (writerShouldBlock() || + !compareAndSetState(c, c + acquires)) + return false; + setExclusiveOwnerThread(current); + return true; + } + + protected final boolean tryReleaseShared(int unused) { + Thread current = Thread.currentThread(); + if (firstReader == current) { + // assert firstReaderHoldCount > 0; + if (firstReaderHoldCount == 1) + firstReader = null; + else + firstReaderHoldCount--; + } else { + HoldCounter rh = cachedHoldCounter; + if (rh == null || rh.tid != current.getId()) + rh = readHolds.get(); + int count = rh.count; + if (count <= 1) { + readHolds.remove(); + if (count <= 0) + throw unmatchedUnlockException(); + } + --rh.count; + } + for (;;) { + int c = getState(); + int nextc = c - SHARED_UNIT; + if (compareAndSetState(c, nextc)) + // Releasing the read lock has no effect on readers, + // but it may allow waiting writers to proceed if + // both read and write locks are now free. + return nextc == 0; + } + } + + private IllegalMonitorStateException unmatchedUnlockException() { + return new IllegalMonitorStateException( + "attempt to unlock read lock, not locked by current thread"); + } + + protected final int tryAcquireShared(int unused) { + /* + * Walkthrough: + * 1. If write lock held by another thread, fail. + * 2. Otherwise, this thread is eligible for + * lock wrt state, so ask if it should block + * because of queue policy. If not, try + * to grant by CASing state and updating count. + * Note that step does not check for reentrant + * acquires, which is postponed to full version + * to avoid having to check hold count in + * the more typical non-reentrant case. + * 3. If step 2 fails either because thread + * apparently not eligible or CAS fails or count + * saturated, chain to version with full retry loop. + */ + Thread current = Thread.currentThread(); + int c = getState(); + if (exclusiveCount(c) != 0 && + getExclusiveOwnerThread() != current) + return -1; + int r = sharedCount(c); + if (!readerShouldBlock() && + r < MAX_COUNT && + compareAndSetState(c, c + SHARED_UNIT)) { + if (r == 0) { + firstReader = current; + firstReaderHoldCount = 1; + } else if (firstReader == current) { + firstReaderHoldCount++; + } else { + HoldCounter rh = cachedHoldCounter; + if (rh == null || rh.tid != current.getId()) + cachedHoldCounter = rh = readHolds.get(); + else if (rh.count == 0) + readHolds.set(rh); + rh.count++; + } + return 1; + } + return fullTryAcquireShared(current); + } + + /** + * Full version of acquire for reads, that handles CAS misses + * and reentrant reads not dealt with in tryAcquireShared. + */ + final int fullTryAcquireShared(Thread current) { + /* + * This code is in part redundant with that in + * tryAcquireShared but is simpler overall by not + * complicating tryAcquireShared with interactions between + * retries and lazily reading hold counts. + */ + HoldCounter rh = null; + for (;;) { + int c = getState(); + if (exclusiveCount(c) != 0) { + if (getExclusiveOwnerThread() != current) + return -1; + // else we hold the exclusive lock; blocking here + // would cause deadlock. + } else if (readerShouldBlock()) { + // Make sure we're not acquiring read lock reentrantly + if (firstReader == current) { + // assert firstReaderHoldCount > 0; + } else { + if (rh == null) { + rh = cachedHoldCounter; + if (rh == null || rh.tid != current.getId()) { + rh = readHolds.get(); + if (rh.count == 0) + readHolds.remove(); + } + } + if (rh.count == 0) + return -1; + } + } + if (sharedCount(c) == MAX_COUNT) + throw new Error("Maximum lock count exceeded"); + if (compareAndSetState(c, c + SHARED_UNIT)) { + if (sharedCount(c) == 0) { + firstReader = current; + firstReaderHoldCount = 1; + } else if (firstReader == current) { + firstReaderHoldCount++; + } else { + if (rh == null) + rh = cachedHoldCounter; + if (rh == null || rh.tid != current.getId()) + rh = readHolds.get(); + else if (rh.count == 0) + readHolds.set(rh); + rh.count++; + cachedHoldCounter = rh; // cache for release + } + return 1; + } + } + } + + /** + * Performs tryLock for write, enabling barging in both modes. + * This is identical in effect to tryAcquire except for lack + * of calls to writerShouldBlock. + */ + final boolean tryWriteLock() { + Thread current = Thread.currentThread(); + int c = getState(); + if (c != 0) { + int w = exclusiveCount(c); + if (w == 0 || current != getExclusiveOwnerThread()) + return false; + if (w == MAX_COUNT) + throw new Error("Maximum lock count exceeded"); + } + if (!compareAndSetState(c, c + 1)) + return false; + setExclusiveOwnerThread(current); + return true; + } + + /** + * Performs tryLock for read, enabling barging in both modes. + * This is identical in effect to tryAcquireShared except for + * lack of calls to readerShouldBlock. + */ + final boolean tryReadLock() { + Thread current = Thread.currentThread(); + for (;;) { + int c = getState(); + if (exclusiveCount(c) != 0 && + getExclusiveOwnerThread() != current) + return false; + int r = sharedCount(c); + if (r == MAX_COUNT) + throw new Error("Maximum lock count exceeded"); + if (compareAndSetState(c, c + SHARED_UNIT)) { + if (r == 0) { + firstReader = current; + firstReaderHoldCount = 1; + } else if (firstReader == current) { + firstReaderHoldCount++; + } else { + HoldCounter rh = cachedHoldCounter; + if (rh == null || rh.tid != current.getId()) + cachedHoldCounter = rh = readHolds.get(); + else if (rh.count == 0) + readHolds.set(rh); + rh.count++; + } + return true; + } + } + } + + protected final boolean isHeldExclusively() { + // While we must in general read state before owner, + // we don't need to do so to check if current thread is owner + return getExclusiveOwnerThread() == Thread.currentThread(); + } + + // Methods relayed to outer class + + final ConditionObject newCondition() { + return new ConditionObject(); + } + + final Thread getOwner() { + // Must read state before owner to ensure memory consistency + return ((exclusiveCount(getState()) == 0) ? + null : + getExclusiveOwnerThread()); + } + + final int getReadLockCount() { + return sharedCount(getState()); + } + + final boolean isWriteLocked() { + return exclusiveCount(getState()) != 0; + } + + final int getWriteHoldCount() { + return isHeldExclusively() ? exclusiveCount(getState()) : 0; + } + + final int getReadHoldCount() { + if (getReadLockCount() == 0) + return 0; + + Thread current = Thread.currentThread(); + if (firstReader == current) + return firstReaderHoldCount; + + HoldCounter rh = cachedHoldCounter; + if (rh != null && rh.tid == current.getId()) + return rh.count; + + int count = readHolds.get().count; + if (count == 0) readHolds.remove(); + return count; + } + + /** + * Reconstitute this lock instance from a stream + * @param s the stream + */ + private void readObject(java.io.ObjectInputStream s) + throws java.io.IOException, ClassNotFoundException { + s.defaultReadObject(); + readHolds = new ThreadLocalHoldCounter(); + setState(0); // reset to unlocked state + } + + final int getCount() { return getState(); } + } + + /** + * Nonfair version of Sync + */ + static final class NonfairSync extends Sync { + private static final long serialVersionUID = -8159625535654395037L; + final boolean writerShouldBlock() { + return false; // writers can always barge + } + final boolean readerShouldBlock() { + /* As a heuristic to avoid indefinite writer starvation, + * block if the thread that momentarily appears to be head + * of queue, if one exists, is a waiting writer. This is + * only a probabilistic effect since a new reader will not + * block if there is a waiting writer behind other enabled + * readers that have not yet drained from the queue. + */ + return apparentlyFirstQueuedIsExclusive(); + } + } + + /** + * Fair version of Sync + */ + static final class FairSync extends Sync { + private static final long serialVersionUID = -2274990926593161451L; + final boolean writerShouldBlock() { + return hasQueuedPredecessors(); + } + final boolean readerShouldBlock() { + return hasQueuedPredecessors(); + } + } + + /** + * The lock returned by method {@link ReentrantReadWriteLock#readLock}. + */ + public static class ReadLock implements Lock, java.io.Serializable { + private static final long serialVersionUID = -5992448646407690164L; + private final Sync sync; + + /** + * Constructor for use by subclasses + * + * @param lock the outer lock object + * @throws NullPointerException if the lock is null + */ + protected ReadLock(ReentrantReadWriteLock lock) { + sync = lock.sync; + } + + /** + * Acquires the read lock. + * + *

Acquires the read lock if the write lock is not held by + * another thread and returns immediately. + * + *

If the write lock is held by another thread then + * the current thread becomes disabled for thread scheduling + * purposes and lies dormant until the read lock has been acquired. + */ + public void lock() { + sync.acquireShared(1); + } + + /** + * Acquires the read lock unless the current thread is + * {@linkplain Thread#interrupt interrupted}. + * + *

Acquires the read lock if the write lock is not held + * by another thread and returns immediately. + * + *

If the write lock is held by another thread then the + * current thread becomes disabled for thread scheduling + * purposes and lies dormant until one of two things happens: + * + *

    + * + *
  • The read lock is acquired by the current thread; or + * + *
  • Some other thread {@linkplain Thread#interrupt interrupts} + * the current thread. + * + *
+ * + *

If the current thread: + * + *

    + * + *
  • has its interrupted status set on entry to this method; or + * + *
  • is {@linkplain Thread#interrupt interrupted} while + * acquiring the read lock, + * + *
+ * + * then {@link InterruptedException} is thrown and the current + * thread's interrupted status is cleared. + * + *

In this implementation, as this method is an explicit + * interruption point, preference is given to responding to + * the interrupt over normal or reentrant acquisition of the + * lock. + * + * @throws InterruptedException if the current thread is interrupted + */ + public void lockInterruptibly() throws InterruptedException { + sync.acquireSharedInterruptibly(1); + } + + /** + * Acquires the read lock only if the write lock is not held by + * another thread at the time of invocation. + * + *

Acquires the read lock if the write lock is not held by + * another thread and returns immediately with the value + * {@code true}. Even when this lock has been set to use a + * fair ordering policy, a call to {@code tryLock()} + * will immediately acquire the read lock if it is + * available, whether or not other threads are currently + * waiting for the read lock. This "barging" behavior + * can be useful in certain circumstances, even though it + * breaks fairness. If you want to honor the fairness setting + * for this lock, then use {@link #tryLock(long, TimeUnit) + * tryLock(0, TimeUnit.SECONDS) } which is almost equivalent + * (it also detects interruption). + * + *

If the write lock is held by another thread then + * this method will return immediately with the value + * {@code false}. + * + * @return {@code true} if the read lock was acquired + */ + public boolean tryLock() { + return sync.tryReadLock(); + } + + /** + * Acquires the read lock if the write lock is not held by + * another thread within the given waiting time and the + * current thread has not been {@linkplain Thread#interrupt + * interrupted}. + * + *

Acquires the read lock if the write lock is not held by + * another thread and returns immediately with the value + * {@code true}. If this lock has been set to use a fair + * ordering policy then an available lock will not be + * acquired if any other threads are waiting for the + * lock. This is in contrast to the {@link #tryLock()} + * method. If you want a timed {@code tryLock} that does + * permit barging on a fair lock then combine the timed and + * un-timed forms together: + * + *

if (lock.tryLock() || lock.tryLock(timeout, unit) ) { ... }
+         * 
+ * + *

If the write lock is held by another thread then the + * current thread becomes disabled for thread scheduling + * purposes and lies dormant until one of three things happens: + * + *

    + * + *
  • The read lock is acquired by the current thread; or + * + *
  • Some other thread {@linkplain Thread#interrupt interrupts} + * the current thread; or + * + *
  • The specified waiting time elapses. + * + *
+ * + *

If the read lock is acquired then the value {@code true} is + * returned. + * + *

If the current thread: + * + *

    + * + *
  • has its interrupted status set on entry to this method; or + * + *
  • is {@linkplain Thread#interrupt interrupted} while + * acquiring the read lock, + * + *
then {@link InterruptedException} is thrown and the + * current thread's interrupted status is cleared. + * + *

If the specified waiting time elapses then the value + * {@code false} is returned. If the time is less than or + * equal to zero, the method will not wait at all. + * + *

In this implementation, as this method is an explicit + * interruption point, preference is given to responding to + * the interrupt over normal or reentrant acquisition of the + * lock, and over reporting the elapse of the waiting time. + * + * @param timeout the time to wait for the read lock + * @param unit the time unit of the timeout argument + * @return {@code true} if the read lock was acquired + * @throws InterruptedException if the current thread is interrupted + * @throws NullPointerException if the time unit is null + * + */ + public boolean tryLock(long timeout, TimeUnit unit) + throws InterruptedException { + return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout)); + } + + /** + * Attempts to release this lock. + * + *

If the number of readers is now zero then the lock + * is made available for write lock attempts. + */ + public void unlock() { + sync.releaseShared(1); + } + + /** + * Throws {@code UnsupportedOperationException} because + * {@code ReadLocks} do not support conditions. + * + * @throws UnsupportedOperationException always + */ + public Condition newCondition() { + throw new UnsupportedOperationException(); + } + + /** + * Returns a string identifying this lock, as well as its lock state. + * The state, in brackets, includes the String {@code "Read locks ="} + * followed by the number of held read locks. + * + * @return a string identifying this lock, as well as its lock state + */ + public String toString() { + int r = sync.getReadLockCount(); + return super.toString() + + "[Read locks = " + r + "]"; + } + } + + /** + * The lock returned by method {@link ReentrantReadWriteLock#writeLock}. + */ + public static class WriteLock implements Lock, java.io.Serializable { + private static final long serialVersionUID = -4992448646407690164L; + private final Sync sync; + + /** + * Constructor for use by subclasses + * + * @param lock the outer lock object + * @throws NullPointerException if the lock is null + */ + protected WriteLock(ReentrantReadWriteLock lock) { + sync = lock.sync; + } + + /** + * Acquires the write lock. + * + *

Acquires the write lock if neither the read nor write lock + * are held by another thread + * and returns immediately, setting the write lock hold count to + * one. + * + *

If the current thread already holds the write lock then the + * hold count is incremented by one and the method returns + * immediately. + * + *

If the lock is held by another thread then the current + * thread becomes disabled for thread scheduling purposes and + * lies dormant until the write lock has been acquired, at which + * time the write lock hold count is set to one. + */ + public void lock() { + sync.acquire(1); + } + + /** + * Acquires the write lock unless the current thread is + * {@linkplain Thread#interrupt interrupted}. + * + *

Acquires the write lock if neither the read nor write lock + * are held by another thread + * and returns immediately, setting the write lock hold count to + * one. + * + *

If the current thread already holds this lock then the + * hold count is incremented by one and the method returns + * immediately. + * + *

If the lock is held by another thread then the current + * thread becomes disabled for thread scheduling purposes and + * lies dormant until one of two things happens: + * + *

    + * + *
  • The write lock is acquired by the current thread; or + * + *
  • Some other thread {@linkplain Thread#interrupt interrupts} + * the current thread. + * + *
+ * + *

If the write lock is acquired by the current thread then the + * lock hold count is set to one. + * + *

If the current thread: + * + *

    + * + *
  • has its interrupted status set on entry to this method; + * or + * + *
  • is {@linkplain Thread#interrupt interrupted} while + * acquiring the write lock, + * + *
+ * + * then {@link InterruptedException} is thrown and the current + * thread's interrupted status is cleared. + * + *

In this implementation, as this method is an explicit + * interruption point, preference is given to responding to + * the interrupt over normal or reentrant acquisition of the + * lock. + * + * @throws InterruptedException if the current thread is interrupted + */ + public void lockInterruptibly() throws InterruptedException { + sync.acquireInterruptibly(1); + } + + /** + * Acquires the write lock only if it is not held by another thread + * at the time of invocation. + * + *

Acquires the write lock if neither the read nor write lock + * are held by another thread + * and returns immediately with the value {@code true}, + * setting the write lock hold count to one. Even when this lock has + * been set to use a fair ordering policy, a call to + * {@code tryLock()} will immediately acquire the + * lock if it is available, whether or not other threads are + * currently waiting for the write lock. This "barging" + * behavior can be useful in certain circumstances, even + * though it breaks fairness. If you want to honor the + * fairness setting for this lock, then use {@link + * #tryLock(long, TimeUnit) tryLock(0, TimeUnit.SECONDS) } + * which is almost equivalent (it also detects interruption). + * + *

If the current thread already holds this lock then the + * hold count is incremented by one and the method returns + * {@code true}. + * + *

If the lock is held by another thread then this method + * will return immediately with the value {@code false}. + * + * @return {@code true} if the lock was free and was acquired + * by the current thread, or the write lock was already held + * by the current thread; and {@code false} otherwise. + */ + public boolean tryLock( ) { + return sync.tryWriteLock(); + } + + /** + * Acquires the write lock if it is not held by another thread + * within the given waiting time and the current thread has + * not been {@linkplain Thread#interrupt interrupted}. + * + *

Acquires the write lock if neither the read nor write lock + * are held by another thread + * and returns immediately with the value {@code true}, + * setting the write lock hold count to one. If this lock has been + * set to use a fair ordering policy then an available lock + * will not be acquired if any other threads are + * waiting for the write lock. This is in contrast to the {@link + * #tryLock()} method. If you want a timed {@code tryLock} + * that does permit barging on a fair lock then combine the + * timed and un-timed forms together: + * + *

if (lock.tryLock() || lock.tryLock(timeout, unit) ) { ... }
+         * 
+ * + *

If the current thread already holds this lock then the + * hold count is incremented by one and the method returns + * {@code true}. + * + *

If the lock is held by another thread then the current + * thread becomes disabled for thread scheduling purposes and + * lies dormant until one of three things happens: + * + *

    + * + *
  • The write lock is acquired by the current thread; or + * + *
  • Some other thread {@linkplain Thread#interrupt interrupts} + * the current thread; or + * + *
  • The specified waiting time elapses + * + *
+ * + *

If the write lock is acquired then the value {@code true} is + * returned and the write lock hold count is set to one. + * + *

If the current thread: + * + *

    + * + *
  • has its interrupted status set on entry to this method; + * or + * + *
  • is {@linkplain Thread#interrupt interrupted} while + * acquiring the write lock, + * + *
+ * + * then {@link InterruptedException} is thrown and the current + * thread's interrupted status is cleared. + * + *

If the specified waiting time elapses then the value + * {@code false} is returned. If the time is less than or + * equal to zero, the method will not wait at all. + * + *

In this implementation, as this method is an explicit + * interruption point, preference is given to responding to + * the interrupt over normal or reentrant acquisition of the + * lock, and over reporting the elapse of the waiting time. + * + * @param timeout the time to wait for the write lock + * @param unit the time unit of the timeout argument + * + * @return {@code true} if the lock was free and was acquired + * by the current thread, or the write lock was already held by the + * current thread; and {@code false} if the waiting time + * elapsed before the lock could be acquired. + * + * @throws InterruptedException if the current thread is interrupted + * @throws NullPointerException if the time unit is null + * + */ + public boolean tryLock(long timeout, TimeUnit unit) + throws InterruptedException { + return sync.tryAcquireNanos(1, unit.toNanos(timeout)); + } + + /** + * Attempts to release this lock. + * + *

If the current thread is the holder of this lock then + * the hold count is decremented. If the hold count is now + * zero then the lock is released. If the current thread is + * not the holder of this lock then {@link + * IllegalMonitorStateException} is thrown. + * + * @throws IllegalMonitorStateException if the current thread does not + * hold this lock. + */ + public void unlock() { + sync.release(1); + } + + /** + * Returns a {@link Condition} instance for use with this + * {@link Lock} instance. + *

The returned {@link Condition} instance supports the same + * usages as do the {@link Object} monitor methods ({@link + * Object#wait() wait}, {@link Object#notify notify}, and {@link + * Object#notifyAll notifyAll}) when used with the built-in + * monitor lock. + * + *

    + * + *
  • If this write lock is not held when any {@link + * Condition} method is called then an {@link + * IllegalMonitorStateException} is thrown. (Read locks are + * held independently of write locks, so are not checked or + * affected. However it is essentially always an error to + * invoke a condition waiting method when the current thread + * has also acquired read locks, since other threads that + * could unblock it will not be able to acquire the write + * lock.) + * + *
  • When the condition {@linkplain Condition#await() waiting} + * methods are called the write lock is released and, before + * they return, the write lock is reacquired and the lock hold + * count restored to what it was when the method was called. + * + *
  • If a thread is {@linkplain Thread#interrupt interrupted} while + * waiting then the wait will terminate, an {@link + * InterruptedException} will be thrown, and the thread's + * interrupted status will be cleared. + * + *
  • Waiting threads are signalled in FIFO order. + * + *
  • The ordering of lock reacquisition for threads returning + * from waiting methods is the same as for threads initially + * acquiring the lock, which is in the default case not specified, + * but for fair locks favors those threads that have been + * waiting the longest. + * + *
+ * + * @return the Condition object + */ + public Condition newCondition() { + return sync.newCondition(); + } + + /** + * Returns a string identifying this lock, as well as its lock + * state. The state, in brackets includes either the String + * {@code "Unlocked"} or the String {@code "Locked by"} + * followed by the {@linkplain Thread#getName name} of the owning thread. + * + * @return a string identifying this lock, as well as its lock state + */ + public String toString() { + Thread o = sync.getOwner(); + return super.toString() + ((o == null) ? + "[Unlocked]" : + "[Locked by thread " + o.getName() + "]"); + } + + /** + * Queries if this write lock is held by the current thread. + * Identical in effect to {@link + * ReentrantReadWriteLock#isWriteLockedByCurrentThread}. + * + * @return {@code true} if the current thread holds this lock and + * {@code false} otherwise + * @since 1.6 + */ + public boolean isHeldByCurrentThread() { + return sync.isHeldExclusively(); + } + + /** + * Queries the number of holds on this write lock by the current + * thread. A thread has a hold on a lock for each lock action + * that is not matched by an unlock action. Identical in effect + * to {@link ReentrantReadWriteLock#getWriteHoldCount}. + * + * @return the number of holds on this lock by the current thread, + * or zero if this lock is not held by the current thread + * @since 1.6 + */ + public int getHoldCount() { + return sync.getWriteHoldCount(); + } + } + + // Instrumentation and status + + /** + * Returns {@code true} if this lock has fairness set true. + * + * @return {@code true} if this lock has fairness set true + */ + public final boolean isFair() { + return sync instanceof FairSync; + } + + /** + * Returns the thread that currently owns the write lock, or + * {@code null} if not owned. When this method is called by a + * thread that is not the owner, the return value reflects a + * best-effort approximation of current lock status. For example, + * the owner may be momentarily {@code null} even if there are + * threads trying to acquire the lock but have not yet done so. + * This method is designed to facilitate construction of + * subclasses that provide more extensive lock monitoring + * facilities. + * + * @return the owner, or {@code null} if not owned + */ + protected Thread getOwner() { + return sync.getOwner(); + } + + /** + * Queries the number of read locks held for this lock. This + * method is designed for use in monitoring system state, not for + * synchronization control. + * @return the number of read locks held. + */ + public int getReadLockCount() { + return sync.getReadLockCount(); + } + + /** + * Queries if the write lock is held by any thread. This method is + * designed for use in monitoring system state, not for + * synchronization control. + * + * @return {@code true} if any thread holds the write lock and + * {@code false} otherwise + */ + public boolean isWriteLocked() { + return sync.isWriteLocked(); + } + + /** + * Queries if the write lock is held by the current thread. + * + * @return {@code true} if the current thread holds the write lock and + * {@code false} otherwise + */ + public boolean isWriteLockedByCurrentThread() { + return sync.isHeldExclusively(); + } + + /** + * Queries the number of reentrant write holds on this lock by the + * current thread. A writer thread has a hold on a lock for + * each lock action that is not matched by an unlock action. + * + * @return the number of holds on the write lock by the current thread, + * or zero if the write lock is not held by the current thread + */ + public int getWriteHoldCount() { + return sync.getWriteHoldCount(); + } + + /** + * Queries the number of reentrant read holds on this lock by the + * current thread. A reader thread has a hold on a lock for + * each lock action that is not matched by an unlock action. + * + * @return the number of holds on the read lock by the current thread, + * or zero if the read lock is not held by the current thread + * @since 1.6 + */ + public int getReadHoldCount() { + return sync.getReadHoldCount(); + } + + /** + * Returns a collection containing threads that may be waiting to + * acquire the write lock. Because the actual set of threads may + * change dynamically while constructing this result, the returned + * collection is only a best-effort estimate. The elements of the + * returned collection are in no particular order. This method is + * designed to facilitate construction of subclasses that provide + * more extensive lock monitoring facilities. + * + * @return the collection of threads + */ + protected Collection getQueuedWriterThreads() { + return sync.getExclusiveQueuedThreads(); + } + + /** + * Returns a collection containing threads that may be waiting to + * acquire the read lock. Because the actual set of threads may + * change dynamically while constructing this result, the returned + * collection is only a best-effort estimate. The elements of the + * returned collection are in no particular order. This method is + * designed to facilitate construction of subclasses that provide + * more extensive lock monitoring facilities. + * + * @return the collection of threads + */ + protected Collection getQueuedReaderThreads() { + return sync.getSharedQueuedThreads(); + } + + /** + * Queries whether any threads are waiting to acquire the read or + * write lock. Note that because cancellations may occur at any + * time, a {@code true} return does not guarantee that any other + * thread will ever acquire a lock. This method is designed + * primarily for use in monitoring of the system state. + * + * @return {@code true} if there may be other threads waiting to + * acquire the lock + */ + public final boolean hasQueuedThreads() { + return sync.hasQueuedThreads(); + } + + /** + * Queries whether the given thread is waiting to acquire either + * the read or write lock. Note that because cancellations may + * occur at any time, a {@code true} return does not guarantee + * that this thread will ever acquire a lock. This method is + * designed primarily for use in monitoring of the system state. + * + * @param thread the thread + * @return {@code true} if the given thread is queued waiting for this lock + * @throws NullPointerException if the thread is null + */ + public final boolean hasQueuedThread(Thread thread) { + return sync.isQueued(thread); + } + + /** + * Returns an estimate of the number of threads waiting to acquire + * either the read or write lock. The value is only an estimate + * because the number of threads may change dynamically while this + * method traverses internal data structures. This method is + * designed for use in monitoring of the system state, not for + * synchronization control. + * + * @return the estimated number of threads waiting for this lock + */ + public final int getQueueLength() { + return sync.getQueueLength(); + } + + /** + * Returns a collection containing threads that may be waiting to + * acquire either the read or write lock. Because the actual set + * of threads may change dynamically while constructing this + * result, the returned collection is only a best-effort estimate. + * The elements of the returned collection are in no particular + * order. This method is designed to facilitate construction of + * subclasses that provide more extensive monitoring facilities. + * + * @return the collection of threads + */ + protected Collection getQueuedThreads() { + return sync.getQueuedThreads(); + } + + /** + * Queries whether any threads are waiting on the given condition + * associated with the write lock. Note that because timeouts and + * interrupts may occur at any time, a {@code true} return does + * not guarantee that a future {@code signal} will awaken any + * threads. This method is designed primarily for use in + * monitoring of the system state. + * + * @param condition the condition + * @return {@code true} if there are any waiting threads + * @throws IllegalMonitorStateException if this lock is not held + * @throws IllegalArgumentException if the given condition is + * not associated with this lock + * @throws NullPointerException if the condition is null + */ + public boolean hasWaiters(Condition condition) { + if (condition == null) + throw new NullPointerException(); + if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject)) + throw new IllegalArgumentException("not owner"); + return sync.hasWaiters((AbstractQueuedSynchronizer.ConditionObject)condition); + } + + /** + * Returns an estimate of the number of threads waiting on the + * given condition associated with the write lock. Note that because + * timeouts and interrupts may occur at any time, the estimate + * serves only as an upper bound on the actual number of waiters. + * This method is designed for use in monitoring of the system + * state, not for synchronization control. + * + * @param condition the condition + * @return the estimated number of waiting threads + * @throws IllegalMonitorStateException if this lock is not held + * @throws IllegalArgumentException if the given condition is + * not associated with this lock + * @throws NullPointerException if the condition is null + */ + public int getWaitQueueLength(Condition condition) { + if (condition == null) + throw new NullPointerException(); + if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject)) + throw new IllegalArgumentException("not owner"); + return sync.getWaitQueueLength((AbstractQueuedSynchronizer.ConditionObject)condition); + } + + /** + * Returns a collection containing those threads that may be + * waiting on the given condition associated with the write lock. + * Because the actual set of threads may change dynamically while + * constructing this result, the returned collection is only a + * best-effort estimate. The elements of the returned collection + * are in no particular order. This method is designed to + * facilitate construction of subclasses that provide more + * extensive condition monitoring facilities. + * + * @param condition the condition + * @return the collection of threads + * @throws IllegalMonitorStateException if this lock is not held + * @throws IllegalArgumentException if the given condition is + * not associated with this lock + * @throws NullPointerException if the condition is null + */ + protected Collection getWaitingThreads(Condition condition) { + if (condition == null) + throw new NullPointerException(); + if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject)) + throw new IllegalArgumentException("not owner"); + return sync.getWaitingThreads((AbstractQueuedSynchronizer.ConditionObject)condition); + } + + /** + * Returns a string identifying this lock, as well as its lock state. + * The state, in brackets, includes the String {@code "Write locks ="} + * followed by the number of reentrantly held write locks, and the + * String {@code "Read locks ="} followed by the number of held + * read locks. + * + * @return a string identifying this lock, as well as its lock state + */ + public String toString() { + int c = sync.getCount(); + int w = Sync.exclusiveCount(c); + int r = Sync.sharedCount(c); + + return super.toString() + + "[Write locks = " + w + ", Read locks = " + r + "]"; + } + +} diff -r e1953d8b8338 -r c8af252ea9eb rt/emul/compact/src/main/java/java/util/concurrent/locks/package-info.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/locks/package-info.java Sat Mar 19 10:48:29 2016 +0100 @@ -0,0 +1,79 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +/** + * Interfaces and classes providing a framework for locking and waiting + * for conditions that is distinct from built-in synchronization and + * monitors. The framework permits much greater flexibility in the use of + * locks and conditions, at the expense of more awkward syntax. + * + *

The {@link java.util.concurrent.locks.Lock} interface supports + * locking disciplines that differ in semantics (reentrant, fair, etc), + * and that can be used in non-block-structured contexts including + * hand-over-hand and lock reordering algorithms. The main implementation + * is {@link java.util.concurrent.locks.ReentrantLock}. + * + *

The {@link java.util.concurrent.locks.ReadWriteLock} interface + * similarly defines locks that may be shared among readers but are + * exclusive to writers. Only a single implementation, {@link + * java.util.concurrent.locks.ReentrantReadWriteLock}, is provided, since + * it covers most standard usage contexts. But programmers may create + * their own implementations to cover nonstandard requirements. + * + *

The {@link java.util.concurrent.locks.Condition} interface + * describes condition variables that may be associated with Locks. + * These are similar in usage to the implicit monitors accessed using + * {@code Object.wait}, but offer extended capabilities. + * In particular, multiple {@code Condition} objects may be associated + * with a single {@code Lock}. To avoid compatibility issues, the + * names of {@code Condition} methods are different from the + * corresponding {@code Object} versions. + * + *

The {@link java.util.concurrent.locks.AbstractQueuedSynchronizer} + * class serves as a useful superclass for defining locks and other + * synchronizers that rely on queuing blocked threads. The {@link + * java.util.concurrent.locks.AbstractQueuedLongSynchronizer} class + * provides the same functionality but extends support to 64 bits of + * synchronization state. Both extend class {@link + * java.util.concurrent.locks.AbstractOwnableSynchronizer}, a simple + * class that helps record the thread currently holding exclusive + * synchronization. The {@link java.util.concurrent.locks.LockSupport} + * class provides lower-level blocking and unblocking support that is + * useful for those developers implementing their own customized lock + * classes. + * + * @since 1.5 + */ +package java.util.concurrent.locks; diff -r e1953d8b8338 -r c8af252ea9eb rt/emul/compact/src/main/java/java/util/concurrent/package-info.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/package-info.java Sat Mar 19 10:48:29 2016 +0100 @@ -0,0 +1,300 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +/** + * Utility classes commonly useful in concurrent programming. This + * package includes a few small standardized extensible frameworks, as + * well as some classes that provide useful functionality and are + * otherwise tedious or difficult to implement. Here are brief + * descriptions of the main components. See also the + * {@link java.util.concurrent.locks} and + * {@link java.util.concurrent.atomic} packages. + * + *

Executors

+ * + * Interfaces. + * + * {@link java.util.concurrent.Executor} is a simple standardized + * interface for defining custom thread-like subsystems, including + * thread pools, asynchronous IO, and lightweight task frameworks. + * Depending on which concrete Executor class is being used, tasks may + * execute in a newly created thread, an existing task-execution thread, + * or the thread calling {@link java.util.concurrent.Executor#execute + * execute}, and may execute sequentially or concurrently. + * + * {@link java.util.concurrent.ExecutorService} provides a more + * complete asynchronous task execution framework. An + * ExecutorService manages queuing and scheduling of tasks, + * and allows controlled shutdown. + * + * The {@link java.util.concurrent.ScheduledExecutorService} + * subinterface and associated interfaces add support for + * delayed and periodic task execution. ExecutorServices + * provide methods arranging asynchronous execution of any + * function expressed as {@link java.util.concurrent.Callable}, + * the result-bearing analog of {@link java.lang.Runnable}. + * + * A {@link java.util.concurrent.Future} returns the results of + * a function, allows determination of whether execution has + * completed, and provides a means to cancel execution. + * + * A {@link java.util.concurrent.RunnableFuture} is a {@code Future} + * that possesses a {@code run} method that upon execution, + * sets its results. + * + *

+ * + * Implementations. + * + * Classes {@link java.util.concurrent.ThreadPoolExecutor} and + * {@link java.util.concurrent.ScheduledThreadPoolExecutor} + * provide tunable, flexible thread pools. + * + * The {@link java.util.concurrent.Executors} class provides + * factory methods for the most common kinds and configurations + * of Executors, as well as a few utility methods for using + * them. Other utilities based on {@code Executors} include the + * concrete class {@link java.util.concurrent.FutureTask} + * providing a common extensible implementation of Futures, and + * {@link java.util.concurrent.ExecutorCompletionService}, that + * assists in coordinating the processing of groups of + * asynchronous tasks. + * + *

Class {@link java.util.concurrent.ForkJoinPool} provides an + * Executor primarily designed for processing instances of {@link + * java.util.concurrent.ForkJoinTask} and its subclasses. These + * classes employ a work-stealing scheduler that attains high + * throughput for tasks conforming to restrictions that often hold in + * computation-intensive parallel processing. + * + *

Queues

+ * + * The {@link java.util.concurrent.ConcurrentLinkedQueue} class + * supplies an efficient scalable thread-safe non-blocking FIFO + * queue. + * + *

Five implementations in {@code java.util.concurrent} support + * the extended {@link java.util.concurrent.BlockingQueue} + * interface, that defines blocking versions of put and take: + * {@link java.util.concurrent.LinkedBlockingQueue}, + * {@link java.util.concurrent.ArrayBlockingQueue}, + * {@link java.util.concurrent.SynchronousQueue}, + * {@link java.util.concurrent.PriorityBlockingQueue}, and + * {@link java.util.concurrent.DelayQueue}. + * The different classes cover the most common usage contexts + * for producer-consumer, messaging, parallel tasking, and + * related concurrent designs. + * + *

Extended interface {@link java.util.concurrent.TransferQueue}, + * and implementation {@link java.util.concurrent.LinkedTransferQueue} + * introduce a synchronous {@code transfer} method (along with related + * features) in which a producer may optionally block awaiting its + * consumer. + * + *

The {@link java.util.concurrent.BlockingDeque} interface + * extends {@code BlockingQueue} to support both FIFO and LIFO + * (stack-based) operations. + * Class {@link java.util.concurrent.LinkedBlockingDeque} + * provides an implementation. + * + *

Timing

+ * + * The {@link java.util.concurrent.TimeUnit} class provides + * multiple granularities (including nanoseconds) for + * specifying and controlling time-out based operations. Most + * classes in the package contain operations based on time-outs + * in addition to indefinite waits. In all cases that + * time-outs are used, the time-out specifies the minimum time + * that the method should wait before indicating that it + * timed-out. Implementations make a "best effort" + * to detect time-outs as soon as possible after they occur. + * However, an indefinite amount of time may elapse between a + * time-out being detected and a thread actually executing + * again after that time-out. All methods that accept timeout + * parameters treat values less than or equal to zero to mean + * not to wait at all. To wait "forever", you can use a value + * of {@code Long.MAX_VALUE}. + * + *

Synchronizers

+ * + * Five classes aid common special-purpose synchronization idioms. + *
    + * + *
  • {@link java.util.concurrent.Semaphore} is a classic concurrency tool. + * + *
  • {@link java.util.concurrent.CountDownLatch} is a very simple yet + * very common utility for blocking until a given number of signals, + * events, or conditions hold. + * + *
  • A {@link java.util.concurrent.CyclicBarrier} is a resettable + * multiway synchronization point useful in some styles of parallel + * programming. + * + *
  • A {@link java.util.concurrent.Phaser} provides + * a more flexible form of barrier that may be used to control phased + * computation among multiple threads. + * + *
  • An {@link java.util.concurrent.Exchanger} allows two threads to + * exchange objects at a rendezvous point, and is useful in several + * pipeline designs. + * + *
+ * + *

Concurrent Collections

+ * + * Besides Queues, this package supplies Collection implementations + * designed for use in multithreaded contexts: + * {@link java.util.concurrent.ConcurrentHashMap}, + * {@link java.util.concurrent.ConcurrentSkipListMap}, + * {@link java.util.concurrent.ConcurrentSkipListSet}, + * {@link java.util.concurrent.CopyOnWriteArrayList}, and + * {@link java.util.concurrent.CopyOnWriteArraySet}. + * When many threads are expected to access a given collection, a + * {@code ConcurrentHashMap} is normally preferable to a synchronized + * {@code HashMap}, and a {@code ConcurrentSkipListMap} is normally + * preferable to a synchronized {@code TreeMap}. + * A {@code CopyOnWriteArrayList} is preferable to a synchronized + * {@code ArrayList} when the expected number of reads and traversals + * greatly outnumber the number of updates to a list. + + *

The "Concurrent" prefix used with some classes in this package + * is a shorthand indicating several differences from similar + * "synchronized" classes. For example {@code java.util.Hashtable} and + * {@code Collections.synchronizedMap(new HashMap())} are + * synchronized. But {@link + * java.util.concurrent.ConcurrentHashMap} is "concurrent". A + * concurrent collection is thread-safe, but not governed by a + * single exclusion lock. In the particular case of + * ConcurrentHashMap, it safely permits any number of + * concurrent reads as well as a tunable number of concurrent + * writes. "Synchronized" classes can be useful when you need + * to prevent all access to a collection via a single lock, at + * the expense of poorer scalability. In other cases in which + * multiple threads are expected to access a common collection, + * "concurrent" versions are normally preferable. And + * unsynchronized collections are preferable when either + * collections are unshared, or are accessible only when + * holding other locks. + * + *

Most concurrent Collection implementations (including most + * Queues) also differ from the usual java.util conventions in that + * their Iterators provide weakly consistent rather than + * fast-fail traversal. A weakly consistent iterator is thread-safe, + * but does not necessarily freeze the collection while iterating, so + * it may (or may not) reflect any updates since the iterator was + * created. + * + *

Memory Consistency Properties

+ * + * Chapter 17 of + * The Java™ Language Specification + * defines the + * happens-before relation on memory operations such as reads and + * writes of shared variables. The results of a write by one thread are + * guaranteed to be visible to a read by another thread only if the write + * operation happens-before the read operation. The + * {@code synchronized} and {@code volatile} constructs, as well as the + * {@code Thread.start()} and {@code Thread.join()} methods, can form + * happens-before relationships. In particular: + * + *
    + *
  • Each action in a thread happens-before every action in that + * thread that comes later in the program's order. + * + *
  • An unlock ({@code synchronized} block or method exit) of a + * monitor happens-before every subsequent lock ({@code synchronized} + * block or method entry) of that same monitor. And because + * the happens-before relation is transitive, all actions + * of a thread prior to unlocking happen-before all actions + * subsequent to any thread locking that monitor. + * + *
  • A write to a {@code volatile} field happens-before every + * subsequent read of that same field. Writes and reads of + * {@code volatile} fields have similar memory consistency effects + * as entering and exiting monitors, but do not entail + * mutual exclusion locking. + * + *
  • A call to {@code start} on a thread happens-before any + * action in the started thread. + * + *
  • All actions in a thread happen-before any other thread + * successfully returns from a {@code join} on that thread. + * + *
+ * + * + * The methods of all classes in {@code java.util.concurrent} and its + * subpackages extend these guarantees to higher-level + * synchronization. In particular: + * + *
    + * + *
  • Actions in a thread prior to placing an object into any concurrent + * collection happen-before actions subsequent to the access or + * removal of that element from the collection in another thread. + * + *
  • Actions in a thread prior to the submission of a {@code Runnable} + * to an {@code Executor} happen-before its execution begins. + * Similarly for {@code Callables} submitted to an {@code ExecutorService}. + * + *
  • Actions taken by the asynchronous computation represented by a + * {@code Future} happen-before actions subsequent to the + * retrieval of the result via {@code Future.get()} in another thread. + * + *
  • Actions prior to "releasing" synchronizer methods such as + * {@code Lock.unlock}, {@code Semaphore.release}, and + * {@code CountDownLatch.countDown} happen-before actions + * subsequent to a successful "acquiring" method such as + * {@code Lock.lock}, {@code Semaphore.acquire}, + * {@code Condition.await}, and {@code CountDownLatch.await} on the + * same synchronizer object in another thread. + * + *
  • For each pair of threads that successfully exchange objects via + * an {@code Exchanger}, actions prior to the {@code exchange()} + * in each thread happen-before those subsequent to the + * corresponding {@code exchange()} in another thread. + * + *
  • Actions prior to calling {@code CyclicBarrier.await} and + * {@code Phaser.awaitAdvance} (as well as its variants) + * happen-before actions performed by the barrier action, and + * actions performed by the barrier action happen-before actions + * subsequent to a successful return from the corresponding {@code await} + * in other threads. + * + *
+ * + * @since 1.5 + */ +package java.util.concurrent;