diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2008-10-21 07:00:00 -0700 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2008-10-21 07:00:00 -0700 |
commit | fdb2704414a9ed92394ada0d1395e4db86889465 (patch) | |
tree | 9b591a4a50054274a197f02b3ccb51313681879f /concurrent/src | |
download | libcore-fdb2704414a9ed92394ada0d1395e4db86889465.zip libcore-fdb2704414a9ed92394ada0d1395e4db86889465.tar.gz libcore-fdb2704414a9ed92394ada0d1395e4db86889465.tar.bz2 |
Initial Contribution
Diffstat (limited to 'concurrent/src')
61 files changed, 20537 insertions, 0 deletions
diff --git a/concurrent/src/main/java/java/util/concurrent/AbstractExecutorService.java b/concurrent/src/main/java/java/util/concurrent/AbstractExecutorService.java new file mode 100644 index 0000000..ed4ce4f --- /dev/null +++ b/concurrent/src/main/java/java/util/concurrent/AbstractExecutorService.java @@ -0,0 +1,223 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent; + +import java.util.*; + +/** + * Provides default implementation of {@link ExecutorService} + * execution methods. This class implements the <tt>submit</tt>, + * <tt>invokeAny</tt> and <tt>invokeAll</tt> methods using the default + * {@link FutureTask} class provided in this package. For example, + * the implementation of <tt>submit(Runnable)</tt> creates an + * associated <tt>FutureTask</tt> that is executed and + * returned. Subclasses overriding these methods to use different + * {@link Future} implementations should do so consistently for each + * of these methods. + * + * @since 1.5 + * @author Doug Lea + */ +public abstract class AbstractExecutorService implements ExecutorService { + + public Future<?> submit(Runnable task) { + if (task == null) throw new NullPointerException(); + FutureTask<Object> ftask = new FutureTask<Object>(task, null); + execute(ftask); + return ftask; + } + + public <T> Future<T> submit(Runnable task, T result) { + if (task == null) throw new NullPointerException(); + FutureTask<T> ftask = new FutureTask<T>(task, result); + execute(ftask); + return ftask; + } + + public <T> Future<T> submit(Callable<T> task) { + if (task == null) throw new NullPointerException(); + FutureTask<T> ftask = new FutureTask<T>(task); + execute(ftask); + return ftask; + } + + /** + * the main mechanics of invokeAny. + */ + private <T> T doInvokeAny(Collection<Callable<T>> 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<Future<T>> futures= new ArrayList<Future<T>>(ntasks); + ExecutorCompletionService<T> ecs = + new ExecutorCompletionService<T>(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<Callable<T>> it = tasks.iterator(); + + // Start one task for sure; the rest incrementally + futures.add(ecs.submit(it.next())); + --ntasks; + int active = 1; + + for (;;) { + Future<T> 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(InterruptedException ie) { + throw ie; + } catch(ExecutionException eex) { + ee = eex; + } catch(RuntimeException rex) { + ee = new ExecutionException(rex); + } + } + } + + if (ee == null) + ee = new ExecutionException(); + throw ee; + + } finally { + for (Future<T> f : futures) + f.cancel(true); + } + } + + public <T> T invokeAny(Collection<Callable<T>> tasks) + throws InterruptedException, ExecutionException { + try { + return doInvokeAny(tasks, false, 0); + } catch (TimeoutException cannotHappen) { + assert false; + return null; + } + } + + public <T> T invokeAny(Collection<Callable<T>> tasks, + long timeout, TimeUnit unit) + throws InterruptedException, ExecutionException, TimeoutException { + return doInvokeAny(tasks, true, unit.toNanos(timeout)); + } + + public <T> List<Future<T>> invokeAll(Collection<Callable<T>> tasks) + throws InterruptedException { + if (tasks == null) + throw new NullPointerException(); + List<Future<T>> futures = new ArrayList<Future<T>>(tasks.size()); + boolean done = false; + try { + for (Callable<T> t : tasks) { + FutureTask<T> f = new FutureTask<T>(t); + futures.add(f); + execute(f); + } + for (Future<T> f : futures) { + if (!f.isDone()) { + try { + f.get(); + } catch(CancellationException ignore) { + } catch(ExecutionException ignore) { + } + } + } + done = true; + return futures; + } finally { + if (!done) + for (Future<T> f : futures) + f.cancel(true); + } + } + + public <T> List<Future<T>> invokeAll(Collection<Callable<T>> tasks, + long timeout, TimeUnit unit) + throws InterruptedException { + if (tasks == null || unit == null) + throw new NullPointerException(); + long nanos = unit.toNanos(timeout); + List<Future<T>> futures = new ArrayList<Future<T>>(tasks.size()); + boolean done = false; + try { + for (Callable<T> t : tasks) + futures.add(new FutureTask<T>(t)); + + long lastTime = System.nanoTime(); + + // Interleave time checks and calls to execute in case + // executor doesn't have any/much parallelism. + Iterator<Future<T>> 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<T> 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<T> f : futures) + f.cancel(true); + } + } + +} diff --git a/concurrent/src/main/java/java/util/concurrent/ArrayBlockingQueue.java b/concurrent/src/main/java/java/util/concurrent/ArrayBlockingQueue.java new file mode 100644 index 0000000..88a0858 --- /dev/null +++ b/concurrent/src/main/java/java/util/concurrent/ArrayBlockingQueue.java @@ -0,0 +1,682 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent; +import java.util.concurrent.locks.*; +import java.util.*; + +// BEGIN android-note +// removed link to collections framework docs +// END android-note + +/** + * A bounded {@linkplain BlockingQueue blocking queue} backed by an + * array. This queue orders elements FIFO (first-in-first-out). The + * <em>head</em> of the queue is that element that has been on the + * queue the longest time. The <em>tail</em> 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. + * + * <p>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 + * increased. Attempts to offer an element to a full queue will + * result in the offer operation blocking; attempts to retrieve an + * element from an empty queue will similarly block. + * + * <p> 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 <tt>true</tt> grants threads access in FIFO order. Fairness + * generally decreases throughput but reduces variability and avoids + * starvation. + * + * <p>This class implements all of the <em>optional</em> methods + * of the {@link Collection} and {@link Iterator} interfaces. + * + * @since 1.5 + * @author Doug Lea + * @param <E> the type of elements held in this collection + */ +public class ArrayBlockingQueue<E> extends AbstractQueue<E> + implements BlockingQueue<E>, 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 */ + private final E[] items; + /** items index for next take, poll or remove */ + private transient int takeIndex; + /** items index for next put, offer, or add. */ + private transient int putIndex; + /** Number of items in the queue */ + private int count; + + /* + * Concurrency control uses the classic two-condition algorithm + * found in any textbook. + */ + + /** Main lock guarding all access */ + private 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; + } + + /** + * Insert element at current put position, advance, and signal. + * Call only when holding lock. + */ + private void insert(E x) { + items[putIndex] = x; + putIndex = inc(putIndex); + ++count; + notEmpty.signal(); + } + + /** + * Extract element at current take position, advance, and signal. + * Call only when holding lock. + */ + private E extract() { + final E[] items = this.items; + E x = items[takeIndex]; + items[takeIndex] = null; + takeIndex = inc(takeIndex); + --count; + notFull.signal(); + return x; + } + + /** + * Utility for remove and iterator.remove: Delete item at position i. + * Call only when holding lock. + */ + void removeAt(int i) { + final E[] 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 <tt>ArrayBlockingQueue</tt> with the given (fixed) + * capacity and default access policy. + * @param capacity the capacity of this queue + * @throws IllegalArgumentException if <tt>capacity</tt> is less than 1 + */ + public ArrayBlockingQueue(int capacity) { + this(capacity, false); + } + + /** + * Creates an <tt>ArrayBlockingQueue</tt> with the given (fixed) + * capacity and the specified access policy. + * @param capacity the capacity of this queue + * @param fair if <tt>true</tt> then queue accesses for threads blocked + * on insertion or removal, are processed in FIFO order; if <tt>false</tt> + * the access order is unspecified. + * @throws IllegalArgumentException if <tt>capacity</tt> is less than 1 + */ + public ArrayBlockingQueue(int capacity, boolean fair) { + if (capacity <= 0) + throw new IllegalArgumentException(); + this.items = (E[]) new Object[capacity]; + lock = new ReentrantLock(fair); + notEmpty = lock.newCondition(); + notFull = lock.newCondition(); + } + + /** + * Creates an <tt>ArrayBlockingQueue</tt> 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 <tt>true</tt> then queue accesses for threads blocked + * on insertion or removal, are processed in FIFO order; if <tt>false</tt> + * the access order is unspecified. + * @param c the collection of elements to initially contain + * @throws IllegalArgumentException if <tt>capacity</tt> is less than + * <tt>c.size()</tt>, or less than 1. + * @throws NullPointerException if <tt>c</tt> or any element within it + * is <tt>null</tt> + */ + public ArrayBlockingQueue(int capacity, boolean fair, + Collection<? extends E> c) { + this(capacity, fair); + if (capacity < c.size()) + throw new IllegalArgumentException(); + + for (Iterator<? extends E> it = c.iterator(); it.hasNext();) + add(it.next()); + } + + /** + * Inserts the specified element at the tail of this queue if possible, + * returning immediately if this queue is full. + * + * @param o the element to add. + * @return <tt>true</tt> if it was possible to add the element to + * this queue, else <tt>false</tt> + * @throws NullPointerException if the specified element is <tt>null</tt> + */ + public boolean offer(E o) { + if (o == null) throw new NullPointerException(); + final ReentrantLock lock = this.lock; + lock.lock(); + try { + if (count == items.length) + return false; + else { + insert(o); + return true; + } + } finally { + lock.unlock(); + } + } + + /** + * Inserts the specified element at the tail of this queue, waiting if + * necessary up to the specified wait time for space to become available. + * @param o the element to add + * @param timeout how long to wait before giving up, in units of + * <tt>unit</tt> + * @param unit a <tt>TimeUnit</tt> determining how to interpret the + * <tt>timeout</tt> parameter + * @return <tt>true</tt> if successful, or <tt>false</tt> if + * the specified waiting time elapses before space is available. + * @throws InterruptedException if interrupted while waiting. + * @throws NullPointerException if the specified element is <tt>null</tt>. + */ + public boolean offer(E o, long timeout, TimeUnit unit) + throws InterruptedException { + + if (o == null) throw new NullPointerException(); + final ReentrantLock lock = this.lock; + lock.lockInterruptibly(); + try { + long nanos = unit.toNanos(timeout); + for (;;) { + if (count != items.length) { + insert(o); + return true; + } + if (nanos <= 0) + return false; + try { + nanos = notFull.awaitNanos(nanos); + } catch (InterruptedException ie) { + notFull.signal(); // propagate to non-interrupted thread + throw ie; + } + } + } finally { + lock.unlock(); + } + } + + public E poll() { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + if (count == 0) + return null; + E x = extract(); + return x; + } finally { + lock.unlock(); + } + } + + public E poll(long timeout, TimeUnit unit) throws InterruptedException { + final ReentrantLock lock = this.lock; + lock.lockInterruptibly(); + try { + long nanos = unit.toNanos(timeout); + for (;;) { + if (count != 0) { + E x = extract(); + return x; + } + if (nanos <= 0) + return null; + try { + nanos = notEmpty.awaitNanos(nanos); + } catch (InterruptedException ie) { + notEmpty.signal(); // propagate to non-interrupted thread + throw ie; + } + + } + } finally { + lock.unlock(); + } + } + + public boolean remove(Object o) { + if (o == null) return false; + final E[] items = this.items; + final ReentrantLock lock = this.lock; + lock.lock(); + try { + int i = takeIndex; + int k = 0; + for (;;) { + if (k++ >= count) + return false; + if (o.equals(items[i])) { + removeAt(i); + return true; + } + i = inc(i); + } + + } finally { + lock.unlock(); + } + } + + public E peek() { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + return (count == 0) ? null : items[takeIndex]; + } finally { + lock.unlock(); + } + } + + public E take() throws InterruptedException { + final ReentrantLock lock = this.lock; + lock.lockInterruptibly(); + try { + try { + while (count == 0) + notEmpty.await(); + } catch (InterruptedException ie) { + notEmpty.signal(); // propagate to non-interrupted thread + throw ie; + } + E x = extract(); + return x; + } finally { + lock.unlock(); + } + } + + /** + * Adds the specified element to the tail of this queue, waiting if + * necessary for space to become available. + * @param o the element to add + * @throws InterruptedException if interrupted while waiting. + * @throws NullPointerException if the specified element is <tt>null</tt>. + */ + public void put(E o) throws InterruptedException { + if (o == null) throw new NullPointerException(); + final E[] items = this.items; + final ReentrantLock lock = this.lock; + lock.lockInterruptibly(); + try { + try { + while (count == items.length) + notFull.await(); + } catch (InterruptedException ie) { + notFull.signal(); // propagate to non-interrupted thread + throw ie; + } + insert(o); + } 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 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 <tt>size</tt> of this queue. + * <p>Note that you <em>cannot</em> always tell if + * an attempt to <tt>add</tt> an element will succeed by + * inspecting <tt>remainingCapacity</tt> because it may be the + * case that a waiting consumer is ready to <tt>take</tt> an + * element out of an otherwise full queue. + * + * @return the remaining capacity + */ + public int remainingCapacity() { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + return items.length - count; + } finally { + lock.unlock(); + } + } + + public boolean contains(Object o) { + if (o == null) return false; + final E[] items = this.items; + final ReentrantLock lock = this.lock; + lock.lock(); + try { + int i = takeIndex; + int k = 0; + while (k++ < count) { + if (o.equals(items[i])) + return true; + i = inc(i); + } + return false; + } finally { + lock.unlock(); + } + } + + public Object[] toArray() { + final E[] items = this.items; + final ReentrantLock lock = this.lock; + lock.lock(); + try { + Object[] a = new Object[count]; + int k = 0; + int i = takeIndex; + while (k < count) { + a[k++] = items[i]; + i = inc(i); + } + return a; + } finally { + lock.unlock(); + } + } + + public <T> T[] toArray(T[] a) { + final E[] items = this.items; + 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; + int i = takeIndex; + while (k < count) { + a[k++] = (T)items[i]; + i = inc(i); + } + if (a.length > count) + a[count] = null; + return a; + } finally { + lock.unlock(); + } + } + + public String toString() { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + return super.toString(); + } finally { + lock.unlock(); + } + } + + public void clear() { + final E[] items = this.items; + final ReentrantLock lock = this.lock; + lock.lock(); + try { + int i = takeIndex; + int k = count; + while (k-- > 0) { + items[i] = null; + i = inc(i); + } + count = 0; + putIndex = 0; + takeIndex = 0; + notFull.signalAll(); + } finally { + lock.unlock(); + } + } + + public int drainTo(Collection<? super E> c) { + if (c == null) + throw new NullPointerException(); + if (c == this) + throw new IllegalArgumentException(); + final E[] 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(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(); + } + } + + public int drainTo(Collection<? super E> c, int maxElements) { + if (c == null) + throw new NullPointerException(); + if (c == this) + throw new IllegalArgumentException(); + if (maxElements <= 0) + return 0; + final E[] items = this.items; + final ReentrantLock lock = this.lock; + lock.lock(); + try { + int i = takeIndex; + int n = 0; + int sz = count; + int max = (maxElements < count)? maxElements : count; + while (n < max) { + c.add(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 returned <tt>Iterator</tt> is a "weakly consistent" iterator that + * will never throw {@link java.util.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<E> iterator() { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + return new Itr(); + } finally { + lock.unlock(); + } + } + + /** + * Iterator for ArrayBlockingQueue + */ + private class Itr implements Iterator<E> { + /** + * Index of element to be returned by next, + * or a negative number if no such. + */ + private int nextIndex; + + /** + * 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; + + /** + * Index of element returned by most recent call to next. + * Reset to -1 if this element is deleted by a call to remove. + */ + private int lastRet; + + Itr() { + lastRet = -1; + if (count == 0) + nextIndex = -1; + else { + nextIndex = takeIndex; + nextItem = items[takeIndex]; + } + } + + public boolean hasNext() { + /* + * No sync. We can return true by mistake here + * only if this iterator passed across threads, + * which we don't support anyway. + */ + return nextIndex >= 0; + } + + /** + * Check whether nextIndex is valid; if so setting nextItem. + * Stops iterator when either hits putIndex or sees null item. + */ + private void checkNext() { + if (nextIndex == putIndex) { + nextIndex = -1; + nextItem = null; + } else { + nextItem = items[nextIndex]; + if (nextItem == null) + nextIndex = -1; + } + } + + public E next() { + final ReentrantLock lock = ArrayBlockingQueue.this.lock; + lock.lock(); + try { + if (nextIndex < 0) + throw new NoSuchElementException(); + lastRet = nextIndex; + E x = nextItem; + nextIndex = inc(nextIndex); + checkNext(); + 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; + + int ti = takeIndex; + removeAt(i); + // back up cursor (reset to front if was first element) + nextIndex = (i == ti) ? takeIndex : i; + checkNext(); + } finally { + lock.unlock(); + } + } + } +} diff --git a/concurrent/src/main/java/java/util/concurrent/BlockingQueue.java b/concurrent/src/main/java/java/util/concurrent/BlockingQueue.java new file mode 100644 index 0000000..ddb7d77 --- /dev/null +++ b/concurrent/src/main/java/java/util/concurrent/BlockingQueue.java @@ -0,0 +1,227 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent; + +import java.util.Collection; +import java.util.Queue; + +// BEGIN android-note +// removed link to collections framework docs +// END android-note + +/** + * 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. + * + * <p>A <tt>BlockingQueue</tt> does not accept <tt>null</tt> elements. + * Implementations throw <tt>NullPointerException</tt> on attempts + * to <tt>add</tt>, <tt>put</tt> or <tt>offer</tt> a <tt>null</tt>. A + * <tt>null</tt> is used as a sentinel value to indicate failure of + * <tt>poll</tt> operations. + * + * <p>A <tt>BlockingQueue</tt> may be capacity bounded. At any given + * time it may have a <tt>remainingCapacity</tt> beyond which no + * additional elements can be <tt>put</tt> without blocking. + * A <tt>BlockingQueue</tt> without any intrinsic capacity constraints always + * reports a remaining capacity of <tt>Integer.MAX_VALUE</tt>. + * + * <p> While <tt>BlockingQueue</tt> is designed to be used primarily + * for producer-consumer queues, it additionally supports the {@link + * java.util.Collection} interface. So, for example, it is possible + * to remove an arbitrary element from a queue using + * <tt>remove(x)</tt>. However, such operations are in general + * <em>not</em> performed very efficiently, and are intended for only + * occasional use, such as when a queued message is cancelled. Also, + * the bulk Collection operations, most notably <tt>addAll</tt>, are + * <em>not</em> necessarily performed atomically, so it is possible + * for <tt>addAll(c)</tt> to fail (throwing an exception) after adding + * only some of the elements in <tt>c</tt>. + * + * <p>A <tt>BlockingQueue</tt> does <em>not</em> 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 + * <em>end-of-stream</em> or <em>poison</em> objects, that are + * interpreted accordingly when taken by consumers. + * + * <p> + * Usage example, based on a typical producer-consumer scenario. + * Note that a <tt>BlockingQueue</tt> can safely be used with multiple + * producers and multiple consumers. + * <pre> + * 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(); + * } + * } + * </pre> + * + * @since 1.5 + * @author Doug Lea + * @param <E> the type of elements held in this collection + */ +public interface BlockingQueue<E> extends Queue<E> { + + /** + * Inserts the specified element into this queue, if possible. When + * using queues that may impose insertion restrictions (for + * example capacity bounds), method <tt>offer</tt> is generally + * preferable to method {@link Collection#add}, which can fail to + * insert an element only by throwing an exception. + * + * @param o the element to add. + * @return <tt>true</tt> if it was possible to add the element to + * this queue, else <tt>false</tt> + * @throws NullPointerException if the specified element is <tt>null</tt> + */ + boolean offer(E o); + + /** + * Inserts the specified element into this queue, waiting if necessary + * up to the specified wait time for space to become available. + * @param o the element to add + * @param timeout how long to wait before giving up, in units of + * <tt>unit</tt> + * @param unit a <tt>TimeUnit</tt> determining how to interpret the + * <tt>timeout</tt> parameter + * @return <tt>true</tt> if successful, or <tt>false</tt> if + * the specified waiting time elapses before space is available. + * @throws InterruptedException if interrupted while waiting. + * @throws NullPointerException if the specified element is <tt>null</tt>. + */ + boolean offer(E o, long timeout, TimeUnit unit) + throws InterruptedException; + + /** + * Retrieves and removes the head of this queue, waiting + * if necessary up to the specified wait time if no elements are + * present on this queue. + * @param timeout how long to wait before giving up, in units of + * <tt>unit</tt> + * @param unit a <tt>TimeUnit</tt> determining how to interpret the + * <tt>timeout</tt> parameter + * @return the head of this queue, or <tt>null</tt> if the + * specified waiting time elapses before an element is present. + * @throws InterruptedException if interrupted while waiting. + */ + E poll(long timeout, TimeUnit unit) + throws InterruptedException; + + /** + * Retrieves and removes the head of this queue, waiting + * if no elements are present on this queue. + * @return the head of this queue + * @throws InterruptedException if interrupted while waiting. + */ + E take() throws InterruptedException; + + /** + * Adds the specified element to this queue, waiting if necessary for + * space to become available. + * @param o the element to add + * @throws InterruptedException if interrupted while waiting. + * @throws NullPointerException if the specified element is <tt>null</tt>. + */ + void put(E o) throws InterruptedException; + + /** + * Returns the number of elements that this queue can ideally (in + * the absence of memory or resource constraints) accept without + * blocking, or <tt>Integer.MAX_VALUE</tt> if there is no + * intrinsic limit. + * <p>Note that you <em>cannot</em> always tell if + * an attempt to <tt>add</tt> an element will succeed by + * inspecting <tt>remainingCapacity</tt> because it may be the + * case that a waiting consumer is ready to <tt>take</tt> an + * element out of an otherwise full queue. + * @return the remaining capacity + */ + int remainingCapacity(); + + /** + * Adds the specified element to this queue if it is possible to + * do so immediately, returning <tt>true</tt> upon success, else + * throwing an IllegalStateException. + * @param o the element + * @return <tt>true</tt> (as per the general contract of + * <tt>Collection.add</tt>). + * + * @throws NullPointerException if the specified element is <tt>null</tt> + * @throws IllegalStateException if element cannot be added + */ + boolean add(E o); + + /** + * Removes all available elements from this queue and adds them + * into the given collection. This operation may be more + * efficient than repeatedly polling this queue. A failure + * encountered while attempting to <tt>add</tt> elements to + * collection <tt>c</tt> 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 + * <tt>IllegalArgumentException</tt>. 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 NullPointerException if c is null + * @throws IllegalArgumentException if c is this queue + * + */ + int drainTo(Collection<? super E> c); + + /** + * Removes at most the given number of available elements from + * this queue and adds them into the given collection. A failure + * encountered while attempting to <tt>add</tt> elements to + * collection <tt>c</tt> 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 + * <tt>IllegalArgumentException</tt>. 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 NullPointerException if c is null + * @throws IllegalArgumentException if c is this queue + */ + int drainTo(Collection<? super E> c, int maxElements); +} diff --git a/concurrent/src/main/java/java/util/concurrent/BrokenBarrierException.java b/concurrent/src/main/java/java/util/concurrent/BrokenBarrierException.java new file mode 100644 index 0000000..3f93fbb --- /dev/null +++ b/concurrent/src/main/java/java/util/concurrent/BrokenBarrierException.java @@ -0,0 +1,38 @@ +/* + * 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/licenses/publicdomain + */ + +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 <tt>BrokenBarrierException</tt> with no specified detail + * message. + */ + public BrokenBarrierException() {} + + /** + * Constructs a <tt>BrokenBarrierException</tt> with the specified + * detail message. + * + * @param message the detail message + */ + public BrokenBarrierException(String message) { + super(message); + } +} diff --git a/concurrent/src/main/java/java/util/concurrent/Callable.java b/concurrent/src/main/java/java/util/concurrent/Callable.java new file mode 100644 index 0000000..abc4d04 --- /dev/null +++ b/concurrent/src/main/java/java/util/concurrent/Callable.java @@ -0,0 +1,36 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent; + +/** + * A task that returns a result and may throw an exception. + * Implementors define a single method with no arguments called + * <tt>call</tt>. + * + * <p>The <tt>Callable</tt> interface is similar to {@link + * java.lang.Runnable}, in that both are designed for classes whose + * instances are potentially executed by another thread. A + * <tt>Runnable</tt>, however, does not return a result and cannot + * throw a checked exception. + * + * <p> The {@link Executors} class contains utility methods to + * convert from other common forms to <tt>Callable</tt> classes. + * + * @see Executor + * @since 1.5 + * @author Doug Lea + * @param <V> the result type of method <tt>call</tt> + */ +public interface Callable<V> { + /** + * Computes a result, or throws an exception if unable to do so. + * + * @return computed result + * @throws Exception if unable to compute a result + */ + V call() throws Exception; +} diff --git a/concurrent/src/main/java/java/util/concurrent/CancellationException.java b/concurrent/src/main/java/java/util/concurrent/CancellationException.java new file mode 100644 index 0000000..2c29544 --- /dev/null +++ b/concurrent/src/main/java/java/util/concurrent/CancellationException.java @@ -0,0 +1,34 @@ +/* + * 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/licenses/publicdomain + */ + +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 <tt>CancellationException</tt> with no detail message. + */ + public CancellationException() {} + + /** + * Constructs a <tt>CancellationException</tt> with the specified detail + * message. + * + * @param message the detail message + */ + public CancellationException(String message) { + super(message); + } +} diff --git a/concurrent/src/main/java/java/util/concurrent/CompletionService.java b/concurrent/src/main/java/java/util/concurrent/CompletionService.java new file mode 100644 index 0000000..e349e5f --- /dev/null +++ b/concurrent/src/main/java/java/util/concurrent/CompletionService.java @@ -0,0 +1,92 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent; + +/** + * A service that decouples the production of new asynchronous tasks + * from the consumption of the results of completed tasks. Producers + * <tt>submit</tt> tasks for execution. Consumers <tt>take</tt> + * completed tasks and process their results in the order they + * complete. A <tt>CompletionService</tt> 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. + + * <p> + * + * Typically, a <tt>CompletionService</tt> relies on a separate {@link + * Executor} to actually execute the tasks, in which case the + * <tt>CompletionService</tt> only manages an internal completion + * queue. The {@link ExecutorCompletionService} class provides an + * implementation of this approach. + * + */ +public interface CompletionService<V> { + /** + * 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 task cannot be scheduled + * for execution + * @throws NullPointerException if task null + */ + Future<V> submit(Callable<V> 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 <tt>get()</tt> method will return the given result value + * upon completion + * @throws RejectedExecutionException if task cannot be scheduled + * for execution + * @throws NullPointerException if task null + */ + Future<V> 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<V> take() throws InterruptedException; + + + /** + * Retrieves and removes the Future representing the next + * completed task or <tt>null</tt> if none are present. + * + * @return the Future representing the next completed task, or + * <tt>null</tt> if none are present. + */ + Future<V> 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 + * <tt>unit</tt> + * @param unit a <tt>TimeUnit</tt> determining how to interpret the + * <tt>timeout</tt> parameter + * @return the Future representing the next completed task or + * <tt>null</tt> if the specified waiting time elapses before one + * is present. + * @throws InterruptedException if interrupted while waiting. + */ + Future<V> poll(long timeout, TimeUnit unit) throws InterruptedException; +} diff --git a/concurrent/src/main/java/java/util/concurrent/ConcurrentHashMap.java b/concurrent/src/main/java/java/util/concurrent/ConcurrentHashMap.java new file mode 100644 index 0000000..ce0bb19 --- /dev/null +++ b/concurrent/src/main/java/java/util/concurrent/ConcurrentHashMap.java @@ -0,0 +1,1354 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent; +import java.util.concurrent.locks.*; +import java.util.*; +import java.io.Serializable; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; + +// BEGIN android-note +// removed link to collections framework docs +// removed cloneable interface from ConcurrentMap interface +// END android-note + +/** + * A hash table supporting full concurrency of retrievals and + * adjustable expected concurrency for updates. This class obeys the + * same functional specification as {@link java.util.Hashtable}, and + * includes versions of methods corresponding to each method of + * <tt>Hashtable</tt>. However, even though all operations are + * thread-safe, retrieval operations do <em>not</em> entail locking, + * and there is <em>not</em> any support for locking the entire table + * in a way that prevents all access. This class is fully + * interoperable with <tt>Hashtable</tt> in programs that rely on its + * thread safety but not on its synchronization details. + * + * <p> Retrieval operations (including <tt>get</tt>) generally do not + * block, so may overlap with update operations (including + * <tt>put</tt> and <tt>remove</tt>). Retrievals reflect the results + * of the most recently <em>completed</em> update operations holding + * upon their onset. For aggregate operations such as <tt>putAll</tt> + * and <tt>clear</tt>, concurrent retrievals may reflect insertion or + * removal of only some entries. Similarly, Iterators and + * Enumerations return elements reflecting the state of the hash table + * at some point at or since the creation of the iterator/enumeration. + * They do <em>not</em> throw + * {@link ConcurrentModificationException}. However, iterators are + * designed to be used by only one thread at a time. + * + * <p> The allowed concurrency among update operations is guided by + * the optional <tt>concurrencyLevel</tt> constructor argument + * (default 16), which is used as a hint for internal sizing. The + * table is internally partitioned to try to permit the indicated + * number of concurrent updates without contention. Because placement + * in hash tables is essentially random, the actual concurrency will + * vary. Ideally, you should choose a value to accommodate as many + * threads as will ever concurrently modify the table. Using a + * significantly higher value than you need can waste space and time, + * and a significantly lower value can lead to thread contention. But + * overestimates and underestimates within an order of magnitude do + * not usually have much noticeable impact. A value of one is + * appropriate when it is known that only one thread will modify + * and all others will only read. + * + * <p>This class implements all of the <em>optional</em> methods + * of the {@link Map} and {@link Iterator} interfaces. + * + * <p> Like {@link java.util.Hashtable} but unlike {@link + * java.util.HashMap}, this class does NOT allow <tt>null</tt> to be + * used as a key or value. + * + * @since 1.5 + * @author Doug Lea + * @param <K> the type of keys maintained by this map + * @param <V> the type of mapped values + */ +public class ConcurrentHashMap<K, V> extends AbstractMap<K, V> + implements ConcurrentMap<K, V>, Serializable { + private static final long serialVersionUID = 7249069246763182397L; + + /* + * The basic strategy is to subdivide the table among Segments, + * each of which itself is a concurrently readable hash table. + */ + + /* ---------------- Constants -------------- */ + + /** + * The default initial number of table slots for this table. + * Used when not otherwise specified in constructor. + */ + static int DEFAULT_INITIAL_CAPACITY = 16; + + /** + * The maximum capacity, used if a higher value is implicitly + * specified by either of the constructors with arguments. MUST + * be a power of two <= 1<<30 to ensure that entries are indexible + * using ints. + */ + static final int MAXIMUM_CAPACITY = 1 << 30; + + /** + * The default load factor for this table. Used when not + * otherwise specified in constructor. + */ + static final float DEFAULT_LOAD_FACTOR = 0.75f; + + /** + * The default number of concurrency control segments. + **/ + static final int DEFAULT_SEGMENTS = 16; + + /** + * The maximum number of segments to allow; used to bound + * constructor arguments. + */ + static final int MAX_SEGMENTS = 1 << 16; // slightly conservative + + /* ---------------- Fields -------------- */ + + /** + * Mask value for indexing into segments. The upper bits of a + * key's hash code are used to choose the segment. + **/ + final int segmentMask; + + /** + * Shift value for indexing within segments. + **/ + final int segmentShift; + + /** + * The segments, each of which is a specialized hash table + */ + final Segment[] segments; + + transient Set<K> keySet; + transient Set<Map.Entry<K,V>> entrySet; + transient Collection<V> values; + + /* ---------------- Small Utilities -------------- */ + + /** + * Returns a hash code for non-null Object x. + * Uses the same hash code spreader as most other java.util hash tables. + * @param x the object serving as a key + * @return the hash code + */ + static int hash(Object x) { + int h = x.hashCode(); + h += ~(h << 9); + h ^= (h >>> 14); + h += (h << 4); + h ^= (h >>> 10); + return h; + } + + /** + * Returns the segment that should be used for key with given hash + * @param hash the hash code for the key + * @return the segment + */ + final Segment<K,V> segmentFor(int hash) { + return (Segment<K,V>) segments[(hash >>> segmentShift) & segmentMask]; + } + + /* ---------------- Inner Classes -------------- */ + + /** + * Segments are specialized versions of hash tables. This + * subclasses from ReentrantLock opportunistically, just to + * simplify some locking and avoid separate construction. + **/ + static final class Segment<K,V> extends ReentrantLock implements Serializable { + /* + * Segments maintain a table of entry lists that are ALWAYS + * kept in a consistent state, so can be read without locking. + * Next fields of nodes are immutable (final). All list + * additions are performed at the front of each bin. This + * makes it easy to check changes, and also fast to traverse. + * When nodes would otherwise be changed, new nodes are + * created to replace them. This works well for hash tables + * since the bin lists tend to be short. (The average length + * is less than two for the default load factor threshold.) + * + * Read operations can thus proceed without locking, but rely + * on a memory barrier to ensure that completed write + * operations performed by other threads are + * noticed. Conveniently, the "count" field, tracking the + * number of elements, can also serve as the volatile variable + * providing proper read/write barriers. This is convenient + * because this field needs to be read in many read operations + * anyway. + * + * Implementors note. The basic rules for all this are: + * + * - All unsynchronized read operations must first read the + * "count" field, and should not look at table entries if + * it is 0. + * + * - All synchronized write operations should write to + * the "count" field after updating. The operations must not + * take any action that could even momentarily cause + * a concurrent read operation to see inconsistent + * data. This is made easier by the nature of the read + * operations in Map. For example, no operation + * can reveal that the table has grown but the threshold + * has not yet been updated, so there are no atomicity + * requirements for this with respect to reads. + * + * As a guide, all critical volatile reads and writes are marked + * in code comments. + */ + + private static final long serialVersionUID = 2249069246763182397L; + + /** + * The number of elements in this segment's region. + **/ + transient volatile int count; + + /** + * Number of updates; used for checking lack of modifications + * in bulk-read methods. + */ + transient int modCount; + + /** + * The table is rehashed when its size exceeds this threshold. + * (The value of this field is always (int)(capacity * + * loadFactor).) + */ + transient int threshold; + + /** + * The per-segment table + */ + transient HashEntry[] table; + + /** + * The load factor for the hash table. Even though this value + * is same for all segments, it is replicated to avoid needing + * links to outer object. + * @serial + */ + final float loadFactor; + + Segment(int initialCapacity, float lf) { + loadFactor = lf; + setTable(new HashEntry[initialCapacity]); + } + + /** + * Set table to new HashEntry array. + * Call only while holding lock or in constructor. + **/ + void setTable(HashEntry[] newTable) { + table = newTable; + threshold = (int)(newTable.length * loadFactor); + count = count; // write-volatile + } + + /* Specialized implementations of map methods */ + + V get(Object key, int hash) { + if (count != 0) { // read-volatile + HashEntry[] tab = table; + int index = hash & (tab.length - 1); + HashEntry<K,V> e = (HashEntry<K,V>) tab[index]; + while (e != null) { + if (e.hash == hash && key.equals(e.key)) + return e.value; + e = e.next; + } + } + return null; + } + + boolean containsKey(Object key, int hash) { + if (count != 0) { // read-volatile + HashEntry[] tab = table; + int index = hash & (tab.length - 1); + HashEntry<K,V> e = (HashEntry<K,V>) tab[index]; + while (e != null) { + if (e.hash == hash && key.equals(e.key)) + return true; + e = e.next; + } + } + return false; + } + + boolean containsValue(Object value) { + if (count != 0) { // read-volatile + HashEntry[] tab = table; + int len = tab.length; + for (int i = 0 ; i < len; i++) + for (HashEntry<K,V> e = (HashEntry<K,V>)tab[i] ; e != null ; e = e.next) + if (value.equals(e.value)) + return true; + } + return false; + } + + boolean replace(K key, int hash, V oldValue, V newValue) { + lock(); + try { + int c = count; + HashEntry[] tab = table; + int index = hash & (tab.length - 1); + HashEntry<K,V> first = (HashEntry<K,V>) tab[index]; + HashEntry<K,V> e = first; + for (;;) { + if (e == null) + return false; + if (e.hash == hash && key.equals(e.key)) + break; + e = e.next; + } + + V v = e.value; + if (v == null || !oldValue.equals(v)) + return false; + + e.value = newValue; + count = c; // write-volatile + return true; + + } finally { + unlock(); + } + } + + V replace(K key, int hash, V newValue) { + lock(); + try { + int c = count; + HashEntry[] tab = table; + int index = hash & (tab.length - 1); + HashEntry<K,V> first = (HashEntry<K,V>) tab[index]; + HashEntry<K,V> e = first; + for (;;) { + if (e == null) + return null; + if (e.hash == hash && key.equals(e.key)) + break; + e = e.next; + } + + V v = e.value; + e.value = newValue; + count = c; // write-volatile + return v; + + } finally { + unlock(); + } + } + + + V put(K key, int hash, V value, boolean onlyIfAbsent) { + lock(); + try { + int c = count; + HashEntry[] tab = table; + int index = hash & (tab.length - 1); + HashEntry<K,V> first = (HashEntry<K,V>) tab[index]; + + for (HashEntry<K,V> e = first; e != null; e = (HashEntry<K,V>) e.next) { + if (e.hash == hash && key.equals(e.key)) { + V oldValue = e.value; + if (!onlyIfAbsent) + e.value = value; + ++modCount; + count = c; // write-volatile + return oldValue; + } + } + + tab[index] = new HashEntry<K,V>(hash, key, value, first); + ++modCount; + ++c; + count = c; // write-volatile + if (c > threshold) + setTable(rehash(tab)); + return null; + } finally { + unlock(); + } + } + + HashEntry[] rehash(HashEntry[] oldTable) { + int oldCapacity = oldTable.length; + if (oldCapacity >= MAXIMUM_CAPACITY) + return oldTable; + + /* + * Reclassify nodes in each list to new Map. Because we are + * using power-of-two expansion, the elements from each bin + * must either stay at same index, or move with a power of two + * offset. We eliminate unnecessary node creation by catching + * cases where old nodes can be reused because their next + * fields won't change. Statistically, at the default + * threshold, only about one-sixth of them need cloning when + * a table doubles. The nodes they replace will be garbage + * collectable as soon as they are no longer referenced by any + * reader thread that may be in the midst of traversing table + * right now. + */ + + HashEntry[] newTable = new HashEntry[oldCapacity << 1]; + int sizeMask = newTable.length - 1; + for (int i = 0; i < oldCapacity ; i++) { + // We need to guarantee that any existing reads of old Map can + // proceed. So we cannot yet null out each bin. + HashEntry<K,V> e = (HashEntry<K,V>)oldTable[i]; + + if (e != null) { + HashEntry<K,V> next = e.next; + int idx = e.hash & sizeMask; + + // Single node on list + if (next == null) + newTable[idx] = e; + + else { + // Reuse trailing consecutive sequence at same slot + HashEntry<K,V> lastRun = e; + int lastIdx = idx; + for (HashEntry<K,V> last = next; + last != null; + last = last.next) { + int k = last.hash & sizeMask; + if (k != lastIdx) { + lastIdx = k; + lastRun = last; + } + } + newTable[lastIdx] = lastRun; + + // Clone all remaining nodes + for (HashEntry<K,V> p = e; p != lastRun; p = p.next) { + int k = p.hash & sizeMask; + newTable[k] = new HashEntry<K,V>(p.hash, + p.key, + p.value, + (HashEntry<K,V>) newTable[k]); + } + } + } + } + return newTable; + } + + /** + * Remove; match on key only if value null, else match both. + */ + V remove(Object key, int hash, Object value) { + lock(); + try { + int c = count; + HashEntry[] tab = table; + int index = hash & (tab.length - 1); + HashEntry<K,V> first = (HashEntry<K,V>)tab[index]; + + HashEntry<K,V> e = first; + for (;;) { + if (e == null) + return null; + if (e.hash == hash && key.equals(e.key)) + break; + e = e.next; + } + + V oldValue = e.value; + if (value != null && !value.equals(oldValue)) + return null; + + // All entries following removed node can stay in list, but + // all preceding ones need to be cloned. + HashEntry<K,V> newFirst = e.next; + for (HashEntry<K,V> p = first; p != e; p = p.next) + newFirst = new HashEntry<K,V>(p.hash, p.key, + p.value, newFirst); + tab[index] = newFirst; + ++modCount; + count = c-1; // write-volatile + return oldValue; + } finally { + unlock(); + } + } + + void clear() { + lock(); + try { + HashEntry[] tab = table; + for (int i = 0; i < tab.length ; i++) + tab[i] = null; + ++modCount; + count = 0; // write-volatile + } finally { + unlock(); + } + } + } + + /** + * ConcurrentHashMap list entry. Note that this is never exported + * out as a user-visible Map.Entry + */ + static final class HashEntry<K,V> { + final K key; + V value; + final int hash; + final HashEntry<K,V> next; + + HashEntry(int hash, K key, V value, HashEntry<K,V> next) { + this.value = value; + this.hash = hash; + this.key = key; + this.next = next; + } + } + + + /* ---------------- Public operations -------------- */ + + /** + * Creates a new, empty map with the specified initial + * capacity and the specified load factor. + * + * @param initialCapacity the initial capacity. The implementation + * performs internal sizing to accommodate this many elements. + * @param loadFactor the load factor threshold, used to control resizing. + * @param concurrencyLevel the estimated number of concurrently + * updating threads. The implementation performs internal sizing + * to try to accommodate this many threads. + * @throws IllegalArgumentException if the initial capacity is + * negative or the load factor or concurrencyLevel are + * nonpositive. + */ + public ConcurrentHashMap(int initialCapacity, + float loadFactor, int concurrencyLevel) { + if (!(loadFactor > 0) || initialCapacity < 0 || concurrencyLevel <= 0) + throw new IllegalArgumentException(); + + if (concurrencyLevel > MAX_SEGMENTS) + concurrencyLevel = MAX_SEGMENTS; + + // Find power-of-two sizes best matching arguments + int sshift = 0; + int ssize = 1; + while (ssize < concurrencyLevel) { + ++sshift; + ssize <<= 1; + } + segmentShift = 32 - sshift; + segmentMask = ssize - 1; + this.segments = new Segment[ssize]; + + if (initialCapacity > MAXIMUM_CAPACITY) + initialCapacity = MAXIMUM_CAPACITY; + int c = initialCapacity / ssize; + if (c * ssize < initialCapacity) + ++c; + int cap = 1; + while (cap < c) + cap <<= 1; + + for (int i = 0; i < this.segments.length; ++i) + this.segments[i] = new Segment<K,V>(cap, loadFactor); + } + + /** + * Creates a new, empty map with the specified initial + * capacity, and with default load factor and concurrencyLevel. + * + * @param initialCapacity The implementation performs internal + * sizing to accommodate this many elements. + * @throws IllegalArgumentException if the initial capacity of + * elements is negative. + */ + public ConcurrentHashMap(int initialCapacity) { + this(initialCapacity, DEFAULT_LOAD_FACTOR, DEFAULT_SEGMENTS); + } + + /** + * Creates a new, empty map with a default initial capacity, + * load factor, and concurrencyLevel. + */ + public ConcurrentHashMap() { + this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR, DEFAULT_SEGMENTS); + } + + /** + * Creates a new map with the same mappings as the given map. The + * map is created with a capacity of twice the number of mappings in + * the given map or 11 (whichever is greater), and a default load factor. + * @param t the map + */ + public ConcurrentHashMap(Map<? extends K, ? extends V> t) { + this(Math.max((int) (t.size() / DEFAULT_LOAD_FACTOR) + 1, + 11), + DEFAULT_LOAD_FACTOR, DEFAULT_SEGMENTS); + putAll(t); + } + + public boolean isEmpty() { + final Segment[] segments = this.segments; + /* + * We need to keep track of per-segment modCounts to avoid ABA + * problems in which an element in one segment was added and + * in another removed during traversal, in which case the + * table was never actually empty at any point. Note the + * similar use of modCounts in the size() and containsValue() + * methods, which are the only other methods also susceptible + * to ABA problems. + */ + int[] mc = new int[segments.length]; + int mcsum = 0; + for (int i = 0; i < segments.length; ++i) { + if (segments[i].count != 0) + return false; + else + mcsum += mc[i] = segments[i].modCount; + } + // If mcsum happens to be zero, then we know we got a snapshot + // before any modifications at all were made. This is + // probably common enough to bother tracking. + if (mcsum != 0) { + for (int i = 0; i < segments.length; ++i) { + if (segments[i].count != 0 || + mc[i] != segments[i].modCount) + return false; + } + } + return true; + } + + public int size() { + final Segment[] segments = this.segments; + int[] mc = new int[segments.length]; + for (;;) { + long sum = 0; + int mcsum = 0; + for (int i = 0; i < segments.length; ++i) { + sum += segments[i].count; + mcsum += mc[i] = segments[i].modCount; + } + int check = 0; + if (mcsum != 0) { + for (int i = 0; i < segments.length; ++i) { + check += segments[i].count; + if (mc[i] != segments[i].modCount) { + check = -1; // force retry + break; + } + } + } + if (check == sum) { + if (sum > Integer.MAX_VALUE) + return Integer.MAX_VALUE; + else + return (int)sum; + } + } + } + + + /** + * Returns the value to which the specified key is mapped in this table. + * + * @param key a key in the table. + * @return the value to which the key is mapped in this table; + * <tt>null</tt> if the key is not mapped to any value in + * this table. + * @throws NullPointerException if the key is + * <tt>null</tt>. + */ + public V get(Object key) { + int hash = hash(key); // throws NullPointerException if key null + return segmentFor(hash).get(key, hash); + } + + /** + * Tests if the specified object is a key in this table. + * + * @param key possible key. + * @return <tt>true</tt> if and only if the specified object + * is a key in this table, as determined by the + * <tt>equals</tt> method; <tt>false</tt> otherwise. + * @throws NullPointerException if the key is + * <tt>null</tt>. + */ + public boolean containsKey(Object key) { + int hash = hash(key); // throws NullPointerException if key null + return segmentFor(hash).containsKey(key, hash); + } + + /** + * Returns <tt>true</tt> if this map maps one or more keys to the + * specified value. Note: This method requires a full internal + * traversal of the hash table, and so is much slower than + * method <tt>containsKey</tt>. + * + * @param value value whose presence in this map is to be tested. + * @return <tt>true</tt> if this map maps one or more keys to the + * specified value. + * @throws NullPointerException if the value is <tt>null</tt>. + */ + public boolean containsValue(Object value) { + if (value == null) + throw new NullPointerException(); + + final Segment[] segments = this.segments; + int[] mc = new int[segments.length]; + for (;;) { + int sum = 0; + int mcsum = 0; + for (int i = 0; i < segments.length; ++i) { + int c = segments[i].count; + mcsum += mc[i] = segments[i].modCount; + if (segments[i].containsValue(value)) + return true; + } + boolean cleanSweep = true; + if (mcsum != 0) { + for (int i = 0; i < segments.length; ++i) { + int c = segments[i].count; + if (mc[i] != segments[i].modCount) { + cleanSweep = false; + break; + } + } + } + if (cleanSweep) + return false; + } + } + + /** + * Legacy method testing if some key maps into the specified value + * in this table. This method is identical in functionality to + * {@link #containsValue}, and exists solely to ensure + * full compatibility with class {@link java.util.Hashtable}, + * which supported this method prior to introduction of the + * Java Collections framework. + + * @param value a value to search for. + * @return <tt>true</tt> if and only if some key maps to the + * <tt>value</tt> argument in this table as + * determined by the <tt>equals</tt> method; + * <tt>false</tt> otherwise. + * @throws NullPointerException if the value is <tt>null</tt>. + */ + public boolean contains(Object value) { + return containsValue(value); + } + + /** + * Maps the specified <tt>key</tt> to the specified + * <tt>value</tt> in this table. Neither the key nor the + * value can be <tt>null</tt>. + * + * <p> The value can be retrieved by calling the <tt>get</tt> method + * with a key that is equal to the original key. + * + * @param key the table key. + * @param value the value. + * @return the previous value of the specified key in this table, + * or <tt>null</tt> if it did not have one. + * @throws NullPointerException if the key or value is + * <tt>null</tt>. + */ + public V put(K key, V value) { + if (value == null) + throw new NullPointerException(); + int hash = hash(key); + return segmentFor(hash).put(key, hash, value, false); + } + + /** + * If the specified key is not already associated + * with a value, associate it with the given value. + * This is equivalent to + * <pre> + * if (!map.containsKey(key)) + * return map.put(key, value); + * else + * return map.get(key); + * </pre> + * Except that the action is performed atomically. + * @param key key with which the specified value is to be associated. + * @param value value to be associated with the specified key. + * @return previous value associated with specified key, or <tt>null</tt> + * if there was no mapping for key. A <tt>null</tt> return can + * also indicate that the map previously associated <tt>null</tt> + * with the specified key, if the implementation supports + * <tt>null</tt> values. + * + * @throws UnsupportedOperationException if the <tt>put</tt> operation is + * not supported by this map. + * @throws ClassCastException if the class of the specified key or value + * prevents it from being stored in this map. + * @throws NullPointerException if the specified key or value is + * <tt>null</tt>. + * + **/ + public V putIfAbsent(K key, V value) { + if (value == null) + throw new NullPointerException(); + int hash = hash(key); + return segmentFor(hash).put(key, hash, value, true); + } + + + /** + * Copies all of the mappings from the specified map to this one. + * + * These mappings replace any mappings that this map had for any of the + * keys currently in the specified Map. + * + * @param t Mappings to be stored in this map. + */ + public void putAll(Map<? extends K, ? extends V> t) { + for (Iterator<? extends Map.Entry<? extends K, ? extends V>> it = (Iterator<? extends Map.Entry<? extends K, ? extends V>>) t.entrySet().iterator(); it.hasNext(); ) { + Entry<? extends K, ? extends V> e = it.next(); + put(e.getKey(), e.getValue()); + } + } + + /** + * Removes the key (and its corresponding value) from this + * table. This method does nothing if the key is not in the table. + * + * @param key the key that needs to be removed. + * @return the value to which the key had been mapped in this table, + * or <tt>null</tt> if the key did not have a mapping. + * @throws NullPointerException if the key is + * <tt>null</tt>. + */ + public V remove(Object key) { + int hash = hash(key); + return segmentFor(hash).remove(key, hash, null); + } + + /** + * Remove entry for key only if currently mapped to given value. + * Acts as + * <pre> + * if (map.get(key).equals(value)) { + * map.remove(key); + * return true; + * } else return false; + * </pre> + * except that the action is performed atomically. + * @param key key with which the specified value is associated. + * @param value value associated with the specified key. + * @return true if the value was removed + * @throws NullPointerException if the specified key is + * <tt>null</tt>. + */ + public boolean remove(Object key, Object value) { + int hash = hash(key); + return segmentFor(hash).remove(key, hash, value) != null; + } + + + /** + * Replace entry for key only if currently mapped to given value. + * Acts as + * <pre> + * if (map.get(key).equals(oldValue)) { + * map.put(key, newValue); + * return true; + * } else return false; + * </pre> + * except that the action is performed atomically. + * @param key key with which the specified value is associated. + * @param oldValue value expected to be associated with the specified key. + * @param newValue value to be associated with the specified key. + * @return true if the value was replaced + * @throws NullPointerException if the specified key or values are + * <tt>null</tt>. + */ + public boolean replace(K key, V oldValue, V newValue) { + if (oldValue == null || newValue == null) + throw new NullPointerException(); + int hash = hash(key); + return segmentFor(hash).replace(key, hash, oldValue, newValue); + } + + /** + * Replace entry for key only if currently mapped to some value. + * Acts as + * <pre> + * if ((map.containsKey(key)) { + * return map.put(key, value); + * } else return null; + * </pre> + * except that the action is performed atomically. + * @param key key with which the specified value is associated. + * @param value value to be associated with the specified key. + * @return previous value associated with specified key, or <tt>null</tt> + * if there was no mapping for key. + * @throws NullPointerException if the specified key or value is + * <tt>null</tt>. + */ + public V replace(K key, V value) { + if (value == null) + throw new NullPointerException(); + int hash = hash(key); + return segmentFor(hash).replace(key, hash, value); + } + + + /** + * Removes all mappings from this map. + */ + public void clear() { + for (int i = 0; i < segments.length; ++i) + segments[i].clear(); + } + + +// BEGIN android-changed +// /** +// * Returns a shallow copy of this +// * <tt>ConcurrentHashMap</tt> instance: the keys and +// * values themselves are not cloned. +// * +// * @return a shallow copy of this map. +// */ +// public Object clone() { +// // We cannot call super.clone, since it would share final +// // segments array, and there's no way to reassign finals. +// +// float lf = segments[0].loadFactor; +// int segs = segments.length; +// int cap = (int)(size() / lf); +// if (cap < segs) cap = segs; +// ConcurrentHashMap<K,V> t = new ConcurrentHashMap<K,V>(cap, lf, segs); +// t.putAll(this); +// return t; +// } +// END android-changed + + /** + * Returns a set view of the keys contained in this map. 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 this map, via the <tt>Iterator.remove</tt>, + * <tt>Set.remove</tt>, <tt>removeAll</tt>, <tt>retainAll</tt>, and + * <tt>clear</tt> operations. It does not support the <tt>add</tt> or + * <tt>addAll</tt> operations. + * The returned <tt>iterator</tt> is a "weakly consistent" iterator that + * will never throw {@link java.util.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 set view of the keys contained in this map. + */ + public Set<K> keySet() { + Set<K> ks = keySet; + return (ks != null) ? ks : (keySet = new KeySet()); + } + + + /** + * Returns a collection view of the values contained in this map. 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 this map, via the + * <tt>Iterator.remove</tt>, <tt>Collection.remove</tt>, + * <tt>removeAll</tt>, <tt>retainAll</tt>, and <tt>clear</tt> operations. + * It does not support the <tt>add</tt> or <tt>addAll</tt> operations. + * The returned <tt>iterator</tt> is a "weakly consistent" iterator that + * will never throw {@link java.util.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 collection view of the values contained in this map. + */ + public Collection<V> values() { + Collection<V> vs = values; + return (vs != null) ? vs : (values = new Values()); + } + + + /** + * Returns a collection view of the mappings contained in this map. Each + * element in the returned collection is a <tt>Map.Entry</tt>. 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 + * <tt>Iterator.remove</tt>, <tt>Collection.remove</tt>, + * <tt>removeAll</tt>, <tt>retainAll</tt>, and <tt>clear</tt> operations. + * It does not support the <tt>add</tt> or <tt>addAll</tt> operations. + * The returned <tt>iterator</tt> is a "weakly consistent" iterator that + * will never throw {@link java.util.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 collection view of the mappings contained in this map. + */ + public Set<Map.Entry<K,V>> entrySet() { + Set<Map.Entry<K,V>> es = entrySet; + return (es != null) ? es : (entrySet = (Set<Map.Entry<K,V>>) (Set) new EntrySet()); + } + + + /** + * Returns an enumeration of the keys in this table. + * + * @return an enumeration of the keys in this table. + * @see #keySet + */ + public Enumeration<K> keys() { + return new KeyIterator(); + } + + /** + * Returns an enumeration of the values in this table. + * + * @return an enumeration of the values in this table. + * @see #values + */ + public Enumeration<V> elements() { + return new ValueIterator(); + } + + /* ---------------- Iterator Support -------------- */ + + abstract class HashIterator { + int nextSegmentIndex; + int nextTableIndex; + HashEntry[] currentTable; + HashEntry<K, V> nextEntry; + HashEntry<K, V> lastReturned; + + HashIterator() { + nextSegmentIndex = segments.length - 1; + nextTableIndex = -1; + advance(); + } + + public boolean hasMoreElements() { return hasNext(); } + + final void advance() { + if (nextEntry != null && (nextEntry = nextEntry.next) != null) + return; + + while (nextTableIndex >= 0) { + if ( (nextEntry = (HashEntry<K,V>)currentTable[nextTableIndex--]) != null) + return; + } + + while (nextSegmentIndex >= 0) { + Segment<K,V> seg = (Segment<K,V>)segments[nextSegmentIndex--]; + if (seg.count != 0) { + currentTable = seg.table; + for (int j = currentTable.length - 1; j >= 0; --j) { + if ( (nextEntry = (HashEntry<K,V>)currentTable[j]) != null) { + nextTableIndex = j - 1; + return; + } + } + } + } + } + + public boolean hasNext() { return nextEntry != null; } + + HashEntry<K,V> nextEntry() { + if (nextEntry == null) + throw new NoSuchElementException(); + lastReturned = nextEntry; + advance(); + return lastReturned; + } + + public void remove() { + if (lastReturned == null) + throw new IllegalStateException(); + ConcurrentHashMap.this.remove(lastReturned.key); + lastReturned = null; + } + } + + final class KeyIterator extends HashIterator implements Iterator<K>, Enumeration<K> { + public K next() { return super.nextEntry().key; } + public K nextElement() { return super.nextEntry().key; } + } + + final class ValueIterator extends HashIterator implements Iterator<V>, Enumeration<V> { + public V next() { return super.nextEntry().value; } + public V nextElement() { return super.nextEntry().value; } + } + + + + /** + * Entry iterator. Exported Entry objects must write-through + * changes in setValue, even if the nodes have been cloned. So we + * cannot return internal HashEntry objects. Instead, the iterator + * itself acts as a forwarding pseudo-entry. + */ + final class EntryIterator extends HashIterator implements Map.Entry<K,V>, Iterator<Entry<K,V>> { + public Map.Entry<K,V> next() { + nextEntry(); + return this; + } + + public K getKey() { + if (lastReturned == null) + throw new IllegalStateException("Entry was removed"); + return lastReturned.key; + } + + public V getValue() { + if (lastReturned == null) + throw new IllegalStateException("Entry was removed"); + return ConcurrentHashMap.this.get(lastReturned.key); + } + + public V setValue(V value) { + if (lastReturned == null) + throw new IllegalStateException("Entry was removed"); + return ConcurrentHashMap.this.put(lastReturned.key, value); + } + + public boolean equals(Object o) { + // If not acting as entry, just use default. + if (lastReturned == null) + return super.equals(o); + if (!(o instanceof Map.Entry)) + return false; + Map.Entry e = (Map.Entry)o; + return eq(getKey(), e.getKey()) && eq(getValue(), e.getValue()); + } + + public int hashCode() { + // If not acting as entry, just use default. + if (lastReturned == null) + return super.hashCode(); + + Object k = getKey(); + Object v = getValue(); + return ((k == null) ? 0 : k.hashCode()) ^ + ((v == null) ? 0 : v.hashCode()); + } + + public String toString() { + // If not acting as entry, just use default. + if (lastReturned == null) + return super.toString(); + else + return getKey() + "=" + getValue(); + } + + boolean eq(Object o1, Object o2) { + return (o1 == null ? o2 == null : o1.equals(o2)); + } + + } + + final class KeySet extends AbstractSet<K> { + public Iterator<K> iterator() { + return new KeyIterator(); + } + public int size() { + return ConcurrentHashMap.this.size(); + } + public boolean contains(Object o) { + return ConcurrentHashMap.this.containsKey(o); + } + public boolean remove(Object o) { + return ConcurrentHashMap.this.remove(o) != null; + } + public void clear() { + ConcurrentHashMap.this.clear(); + } + } + + final class Values extends AbstractCollection<V> { + public Iterator<V> iterator() { + return new ValueIterator(); + } + public int size() { + return ConcurrentHashMap.this.size(); + } + public boolean contains(Object o) { + return ConcurrentHashMap.this.containsValue(o); + } + public void clear() { + ConcurrentHashMap.this.clear(); + } + } + + final class EntrySet extends AbstractSet<Map.Entry<K,V>> { + public Iterator<Map.Entry<K,V>> iterator() { + return new EntryIterator(); + } + public boolean contains(Object o) { + if (!(o instanceof Map.Entry)) + return false; + Map.Entry<K,V> e = (Map.Entry<K,V>)o; + V v = ConcurrentHashMap.this.get(e.getKey()); + return v != null && v.equals(e.getValue()); + } + public boolean remove(Object o) { + if (!(o instanceof Map.Entry)) + return false; + Map.Entry<K,V> e = (Map.Entry<K,V>)o; + return ConcurrentHashMap.this.remove(e.getKey(), e.getValue()); + } + public int size() { + return ConcurrentHashMap.this.size(); + } + public void clear() { + ConcurrentHashMap.this.clear(); + } + public Object[] toArray() { + // Since we don't ordinarily have distinct Entry objects, we + // must pack elements using exportable SimpleEntry + Collection<Map.Entry<K,V>> c = new ArrayList<Map.Entry<K,V>>(size()); + for (Iterator<Map.Entry<K,V>> i = iterator(); i.hasNext(); ) + c.add(new SimpleEntry<K,V>(i.next())); + return c.toArray(); + } + public <T> T[] toArray(T[] a) { + Collection<Map.Entry<K,V>> c = new ArrayList<Map.Entry<K,V>>(size()); + for (Iterator<Map.Entry<K,V>> i = iterator(); i.hasNext(); ) + c.add(new SimpleEntry<K,V>(i.next())); + return c.toArray(a); + } + + } + + /** + * This duplicates java.util.AbstractMap.SimpleEntry until this class + * is made accessible. + */ + static final class SimpleEntry<K,V> implements Entry<K,V> { + K key; + V value; + + public SimpleEntry(K key, V value) { + this.key = key; + this.value = value; + } + + public SimpleEntry(Entry<K,V> e) { + this.key = e.getKey(); + this.value = e.getValue(); + } + + public K getKey() { + return key; + } + + public V getValue() { + return value; + } + + public V setValue(V value) { + V oldValue = this.value; + this.value = value; + return oldValue; + } + + public boolean equals(Object o) { + if (!(o instanceof Map.Entry)) + return false; + Map.Entry e = (Map.Entry)o; + return eq(key, e.getKey()) && eq(value, e.getValue()); + } + + public int hashCode() { + return ((key == null) ? 0 : key.hashCode()) ^ + ((value == null) ? 0 : value.hashCode()); + } + + public String toString() { + return key + "=" + value; + } + + static boolean eq(Object o1, Object o2) { + return (o1 == null ? o2 == null : o1.equals(o2)); + } + } + + /* ---------------- Serialization Support -------------- */ + + /** + * Save the state of the <tt>ConcurrentHashMap</tt> + * instance to a stream (i.e., + * serialize it). + * @param s the stream + * @serialData + * the key (Object) and value (Object) + * for each key-value mapping, followed by a null pair. + * The key-value mappings are emitted in no particular order. + */ + private void writeObject(java.io.ObjectOutputStream s) throws IOException { + s.defaultWriteObject(); + + for (int k = 0; k < segments.length; ++k) { + Segment<K,V> seg = (Segment<K,V>)segments[k]; + seg.lock(); + try { + HashEntry[] tab = seg.table; + for (int i = 0; i < tab.length; ++i) { + for (HashEntry<K,V> e = (HashEntry<K,V>)tab[i]; e != null; e = e.next) { + s.writeObject(e.key); + s.writeObject(e.value); + } + } + } finally { + seg.unlock(); + } + } + s.writeObject(null); + s.writeObject(null); + } + + /** + * Reconstitute the <tt>ConcurrentHashMap</tt> + * instance from a stream (i.e., + * deserialize it). + * @param s the stream + */ + private void readObject(java.io.ObjectInputStream s) + throws IOException, ClassNotFoundException { + s.defaultReadObject(); + + // Initialize each segment to be minimally sized, and let grow. + for (int i = 0; i < segments.length; ++i) { + segments[i].setTable(new HashEntry[1]); + } + + // Read the keys and values, and put the mappings in the table + for (;;) { + K key = (K) s.readObject(); + V value = (V) s.readObject(); + if (key == null) + break; + put(key, value); + } + } +} + + + + diff --git a/concurrent/src/main/java/java/util/concurrent/ConcurrentLinkedQueue.java b/concurrent/src/main/java/java/util/concurrent/ConcurrentLinkedQueue.java new file mode 100644 index 0000000..794142d --- /dev/null +++ b/concurrent/src/main/java/java/util/concurrent/ConcurrentLinkedQueue.java @@ -0,0 +1,481 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent; +import java.util.*; +import java.util.concurrent.atomic.*; + + +// BEGIN android-note +// removed link to collections framework docs +// END android-note + +/** + * An unbounded thread-safe {@linkplain Queue queue} based on linked nodes. + * This queue orders elements FIFO (first-in-first-out). + * The <em>head</em> of the queue is that element that has been on the + * queue the longest time. + * The <em>tail</em> 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 <tt>ConcurrentLinkedQueue</tt> is an appropriate choice when + * many threads will share access to a common collection. + * This queue does not permit <tt>null</tt> elements. + * + * <p>This implementation employs an efficient "wait-free" + * algorithm based on one described in <a + * href="http://www.cs.rochester.edu/u/michael/PODC96.html"> Simple, + * Fast, and Practical Non-Blocking and Blocking Concurrent Queue + * Algorithms</a> by Maged M. Michael and Michael L. Scott. + * + * <p>Beware that, unlike in most collections, the <tt>size</tt> method + * is <em>NOT</em> a constant-time operation. Because of the + * asynchronous nature of these queues, determining the current number + * of elements requires a traversal of the elements. + * + * <p>This class implements all of the <em>optional</em> methods + * of the {@link Collection} and {@link Iterator} interfaces. + * + * @since 1.5 + * @author Doug Lea + * @param <E> the type of elements held in this collection + * + */ +public class ConcurrentLinkedQueue<E> extends AbstractQueue<E> + implements Queue<E>, java.io.Serializable { + private static final long serialVersionUID = 196745693267521676L; + + /* + * This is a straight adaptation of Michael & Scott algorithm. + * For explanation, read the paper. The only (minor) algorithmic + * difference is that this version supports lazy deletion of + * internal nodes (method remove(Object)) -- remove CAS'es item + * fields to null. The normal queue operations unlink but then + * pass over nodes with null item fields. Similarly, iteration + * methods ignore those with nulls. + */ + + private static class Node<E> { + private volatile E item; + private volatile Node<E> next; + + private static final + AtomicReferenceFieldUpdater<Node, Node> + nextUpdater = + AtomicReferenceFieldUpdater.newUpdater + (Node.class, Node.class, "next"); + private static final + AtomicReferenceFieldUpdater<Node, Object> + itemUpdater = + AtomicReferenceFieldUpdater.newUpdater + (Node.class, Object.class, "item"); + + Node(E x) { item = x; } + + Node(E x, Node<E> n) { item = x; next = n; } + + E getItem() { + return item; + } + + boolean casItem(E cmp, E val) { + return itemUpdater.compareAndSet(this, cmp, val); + } + + void setItem(E val) { + itemUpdater.set(this, val); + } + + Node<E> getNext() { + return next; + } + + boolean casNext(Node<E> cmp, Node<E> val) { + return nextUpdater.compareAndSet(this, cmp, val); + } + + void setNext(Node<E> val) { + nextUpdater.set(this, val); + } + + } + + private static final + AtomicReferenceFieldUpdater<ConcurrentLinkedQueue, Node> + tailUpdater = + AtomicReferenceFieldUpdater.newUpdater + (ConcurrentLinkedQueue.class, Node.class, "tail"); + private static final + AtomicReferenceFieldUpdater<ConcurrentLinkedQueue, Node> + headUpdater = + AtomicReferenceFieldUpdater.newUpdater + (ConcurrentLinkedQueue.class, Node.class, "head"); + + private boolean casTail(Node<E> cmp, Node<E> val) { + return tailUpdater.compareAndSet(this, cmp, val); + } + + private boolean casHead(Node<E> cmp, Node<E> val) { + return headUpdater.compareAndSet(this, cmp, val); + } + + + /** + * Pointer to header node, initialized to a dummy node. The first + * actual node is at head.getNext(). + */ + private transient volatile Node<E> head = new Node<E>(null, null); + + /** Pointer to last node on list **/ + private transient volatile Node<E> tail = head; + + + /** + * Creates a <tt>ConcurrentLinkedQueue</tt> that is initially empty. + */ + public ConcurrentLinkedQueue() {} + + /** + * Creates a <tt>ConcurrentLinkedQueue</tt> + * 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 <tt>c</tt> or any element within it + * is <tt>null</tt> + */ + public ConcurrentLinkedQueue(Collection<? extends E> c) { + for (Iterator<? extends E> it = c.iterator(); it.hasNext();) + add(it.next()); + } + + // Have to override just to update the javadoc + + /** + * Adds the specified element to the tail of this queue. + * @param o the element to add. + * @return <tt>true</tt> (as per the general contract of + * <tt>Collection.add</tt>). + * + * @throws NullPointerException if the specified element is <tt>null</tt> + */ + public boolean add(E o) { + return offer(o); + } + + /** + * Inserts the specified element to the tail of this queue. + * + * @param o the element to add. + * @return <tt>true</tt> (as per the general contract of + * <tt>Queue.offer</tt>). + * @throws NullPointerException if the specified element is <tt>null</tt> + */ + public boolean offer(E o) { + if (o == null) throw new NullPointerException(); + Node<E> n = new Node<E>(o, null); + for(;;) { + Node<E> t = tail; + Node<E> s = t.getNext(); + if (t == tail) { + if (s == null) { + if (t.casNext(s, n)) { + casTail(t, n); + return true; + } + } else { + casTail(t, s); + } + } + } + } + + public E poll() { + for (;;) { + Node<E> h = head; + Node<E> t = tail; + Node<E> first = h.getNext(); + if (h == head) { + if (h == t) { + if (first == null) + return null; + else + casTail(t, first); + } else if (casHead(h, first)) { + E item = first.getItem(); + if (item != null) { + first.setItem(null); + return item; + } + // else skip over deleted item, continue loop, + } + } + } + } + + public E peek() { // same as poll except don't remove item + for (;;) { + Node<E> h = head; + Node<E> t = tail; + Node<E> first = h.getNext(); + if (h == head) { + if (h == t) { + if (first == null) + return null; + else + casTail(t, first); + } else { + E item = first.getItem(); + if (item != null) + return item; + else // remove deleted node and continue + casHead(h, first); + } + } + } + } + + /** + * Returns the first actual (non-header) node on list. This is yet + * another variant of poll/peek; here returning out the first + * node, not element (so we cannot collapse with peek() without + * introducing race.) + */ + Node<E> first() { + for (;;) { + Node<E> h = head; + Node<E> t = tail; + Node<E> first = h.getNext(); + if (h == head) { + if (h == t) { + if (first == null) + return null; + else + casTail(t, first); + } else { + if (first.getItem() != null) + return first; + else // remove deleted node and continue + casHead(h, first); + } + } + } + } + + + public boolean isEmpty() { + return first() == null; + } + + /** + * Returns the number of elements in this queue. If this queue + * contains more than <tt>Integer.MAX_VALUE</tt> elements, returns + * <tt>Integer.MAX_VALUE</tt>. + * + * <p>Beware that, unlike in most collections, this method is + * <em>NOT</em> 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() { + int count = 0; + for (Node<E> p = first(); p != null; p = p.getNext()) { + if (p.getItem() != null) { + // Collections.size() spec says to max out + if (++count == Integer.MAX_VALUE) + break; + } + } + return count; + } + + public boolean contains(Object o) { + if (o == null) return false; + for (Node<E> p = first(); p != null; p = p.getNext()) { + E item = p.getItem(); + if (item != null && + o.equals(item)) + return true; + } + return false; + } + + public boolean remove(Object o) { + if (o == null) return false; + for (Node<E> p = first(); p != null; p = p.getNext()) { + E item = p.getItem(); + if (item != null && + o.equals(item) && + p.casItem(item, null)) + return true; + } + return false; + } + + public Object[] toArray() { + // Use ArrayList to deal with resizing. + ArrayList<E> al = new ArrayList<E>(); + for (Node<E> p = first(); p != null; p = p.getNext()) { + E item = p.getItem(); + if (item != null) + al.add(item); + } + return al.toArray(); + } + + public <T> T[] toArray(T[] a) { + // try to use sent-in array + int k = 0; + Node<E> p; + for (p = first(); p != null && k < a.length; p = p.getNext()) { + E item = p.getItem(); + 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<E> al = new ArrayList<E>(); + for (Node<E> q = first(); q != null; q = q.getNext()) { + E item = q.getItem(); + if (item != null) + al.add(item); + } + return (T[])al.toArray(a); + } + + /** + * Returns an iterator over the elements in this queue in proper sequence. + * The returned iterator is a "weakly consistent" iterator that + * will never throw {@link java.util.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<E> iterator() { + return new Itr(); + } + + private class Itr implements Iterator<E> { + /** + * Next node to return item for. + */ + private Node<E> 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<E> 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<E> p = (nextNode == null)? first() : nextNode.getNext(); + for (;;) { + if (p == null) { + nextNode = null; + nextItem = null; + return x; + } + E item = p.getItem(); + if (item != null) { + nextNode = p; + nextItem = item; + return x; + } else // skip over nulls + p = p.getNext(); + } + } + + public boolean hasNext() { + return nextNode != null; + } + + public E next() { + if (nextNode == null) throw new NoSuchElementException(); + return advance(); + } + + public void remove() { + Node<E> l = lastRet; + if (l == null) throw new IllegalStateException(); + // rely on a future traversal to relink. + l.setItem(null); + lastRet = null; + } + } + + /** + * Save the state to a stream (that is, serialize it). + * + * @serialData All of the elements (each an <tt>E</tt>) 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<E> p = first(); p != null; p = p.getNext()) { + Object item = p.getItem(); + if (item != null) + s.writeObject(item); + } + + // Use trailing null as sentinel + s.writeObject(null); + } + + /** + * Reconstitute the 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(); + head = new Node<E>(null, null); + tail = head; + // Read in all elements and place in queue + for (;;) { + E item = (E)s.readObject(); + if (item == null) + break; + else + offer(item); + } + } + +} diff --git a/concurrent/src/main/java/java/util/concurrent/ConcurrentMap.java b/concurrent/src/main/java/java/util/concurrent/ConcurrentMap.java new file mode 100644 index 0000000..32dc000 --- /dev/null +++ b/concurrent/src/main/java/java/util/concurrent/ConcurrentMap.java @@ -0,0 +1,118 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent; +import java.util.Map; + +// BEGIN android-note +// removed link to collections framework docs +// END android-note + +/** + * A {@link java.util.Map} providing additional atomic + * <tt>putIfAbsent</tt>, <tt>remove</tt>, and <tt>replace</tt> methods. + * + * @since 1.5 + * @author Doug Lea + * @param <K> the type of keys maintained by this map + * @param <V> the type of mapped values + */ +public interface ConcurrentMap<K, V> extends Map<K, V> { + /** + * If the specified key is not already associated + * with a value, associate it with the given value. + * This is equivalent to + * <pre> + * if (!map.containsKey(key)) + * return map.put(key, value); + * else + * return map.get(key); + * </pre> + * Except that the action is performed atomically. + * @param key key with which the specified value is to be associated. + * @param value value to be associated with the specified key. + * @return previous value associated with specified key, or <tt>null</tt> + * if there was no mapping for key. A <tt>null</tt> return can + * also indicate that the map previously associated <tt>null</tt> + * with the specified key, if the implementation supports + * <tt>null</tt> values. + * + * @throws UnsupportedOperationException if the <tt>put</tt> operation is + * not supported by this map. + * @throws ClassCastException if the class of the specified key or value + * prevents it from being stored in this map. + * @throws IllegalArgumentException if some aspect of this key or value + * prevents it from being stored in this map. + * @throws NullPointerException if this map does not permit <tt>null</tt> + * keys or values, and the specified key or value is + * <tt>null</tt>. + * + */ + V putIfAbsent(K key, V value); + + /** + * Remove entry for key only if currently mapped to given value. + * Acts as + * <pre> + * if ((map.containsKey(key) && map.get(key).equals(value)) { + * map.remove(key); + * return true; + * } else return false; + * </pre> + * except that the action is performed atomically. + * @param key key with which the specified value is associated. + * @param value value associated with the specified key. + * @return true if the value was removed, false otherwise + * @throws NullPointerException if this map does not permit <tt>null</tt> + * keys or values, and the specified key or value is + * <tt>null</tt>. + */ + boolean remove(Object key, Object value); + + + /** + * Replace entry for key only if currently mapped to given value. + * Acts as + * <pre> + * if ((map.containsKey(key) && map.get(key).equals(oldValue)) { + * map.put(key, newValue); + * return true; + * } else return false; + * </pre> + * except that the action is performed atomically. + * @param key key with which the specified value is associated. + * @param oldValue value expected to be associated with the specified key. + * @param newValue value to be associated with the specified key. + * @return true if the value was replaced + * @throws NullPointerException if this map does not permit <tt>null</tt> + * keys or values, and the specified key or value is + * <tt>null</tt>. + */ + boolean replace(K key, V oldValue, V newValue); + + /** + * Replace entry for key only if currently mapped to some value. + * Acts as + * <pre> + * if ((map.containsKey(key)) { + * return map.put(key, value); + * } else return null; + * </pre> + * except that the action is performed atomically. + * @param key key with which the specified value is associated. + * @param value value to be associated with the specified key. + * @return previous value associated with specified key, or <tt>null</tt> + * if there was no mapping for key. A <tt>null</tt> return can + * also indicate that the map previously associated <tt>null</tt> + * with the specified key, if the implementation supports + * <tt>null</tt> values. + * @throws NullPointerException if this map does not permit <tt>null</tt> + * keys or values, and the specified key or value is + * <tt>null</tt>. + */ + V replace(K key, V value); + +} diff --git a/concurrent/src/main/java/java/util/concurrent/CopyOnWriteArrayList.java b/concurrent/src/main/java/java/util/concurrent/CopyOnWriteArrayList.java new file mode 100644 index 0000000..26165de --- /dev/null +++ b/concurrent/src/main/java/java/util/concurrent/CopyOnWriteArrayList.java @@ -0,0 +1,1189 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with this + * work for additional information regarding copyright ownership. The ASF + * licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package java.util.concurrent; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.lang.reflect.Array; +import java.util.Collection; +import java.util.ConcurrentModificationException; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; +import java.util.NoSuchElementException; +import java.util.RandomAccess; +import java.util.concurrent.locks.ReentrantLock; + +// BEGIN android-added +/** + * Implements a {@link java.util.ArrayList} variant that is thread-safe. All + * write operation result in a new copy of the underlying data being created. + * Iterators reflect the state of the CopyOnWriteArrayList at the time they were + * created. They are not updated to reflect subsequent changes to the list. In + * addition, these iterators cannot be used for modifying the underlying + * CopyOnWriteArrayList. + * + * @param <E> the element type + */ +// END android-added +public class CopyOnWriteArrayList<E> implements List<E>, RandomAccess, Cloneable, Serializable { + + private static final long serialVersionUID = 8673264195747942595L; + + private transient volatile E[] arr; + + /** + * Lock for the queue write methods + */ + private final transient ReentrantLock lock = new ReentrantLock(); + + // BEGIN android-added + /** + * Creates a new, empty instance of CopyOnWriteArrayList. + */ + // END android-added + public CopyOnWriteArrayList() { + } + + // BEGIN android-added + /** + * Creates a new instance of CopyOnWriteArrayList and fills it with the + * contents of a given Collection. + * + * @param c the collection the elements of which are to be copied into + * the new instance. + */ + // END android-added + public CopyOnWriteArrayList(Collection<? extends E> c) { + this((E[]) c.toArray()); + } + + // BEGIN android-added + /** + * Creates a new instance of CopyOnWriteArrayList and fills it with the + * contents of a given array. + * + * @param array the array the elements of which are to be copied into the + * new instance. + */ + // END android-added + public CopyOnWriteArrayList(E[] array) { + int size = array.length; + E[] data = newElementArray(size); + for (int i = 0; i < size; i++) { + data[i] = array[i]; + } + arr = data; + } + + public boolean add(E e) { + lock.lock(); + try { + E[] data; + E[] old = getData(); + int size = old.length; + data = newElementArray(size + 1); + System.arraycopy(old, 0, data, 0, size); + data[size] = e; + setData(data); + return true; + } finally { + lock.unlock(); + } + } + + public void add(int index, E e) { + lock.lock(); + try { + E[] data; + E[] old = getData(); + int size = old.length; + checkIndexInclusive(index, size); + data = newElementArray(size+1); + System.arraycopy(old, 0, data, 0, index); + data[index] = e; + if (size > index) { + System.arraycopy(old, index, data, index + 1, size - index); + } + setData(data); + } finally { + lock.unlock(); + } + } + + public boolean addAll(Collection<? extends E> c) { + Iterator it = c.iterator(); + int ssize = c.size(); + lock.lock(); + try { + int size = size(); + E[] data; + E[] old = getData(); + int nSize = size + ssize; + data = newElementArray(nSize); + System.arraycopy(old, 0, data, 0, size); + while (it.hasNext()) { + data[size++] = (E) it.next(); + } + setData(data); + } finally { + lock.unlock(); + } + return true; + } + + public boolean addAll(int index, Collection<? extends E> c) { + Iterator it = c.iterator(); + int ssize = c.size(); + lock.lock(); + try { + int size = size(); + checkIndexInclusive(index, size); + E[] data; + E[] old = getData(); + int nSize = size + ssize; + data = newElementArray(nSize); + System.arraycopy(old, 0, data, 0, index); + int i = index; + while (it.hasNext()) { + data[i++] = (E) it.next(); + } + if (size > index) { + System.arraycopy(old, index, data, index + ssize, size - index); + } + setData(data); + } finally { + lock.unlock(); + } + return true; + } + + // BEGIN android-added + /** + * Adds to this CopyOnWriteArrayList all those elements from a given + * collection that are not yet part of the list. + * + * @param c the collection from which the potential new elements are + * taken. + * + * @return the number of elements actually added to this list. + */ + // END android-added + public int addAllAbsent(Collection<? extends E> c) { + if (c.size() == 0) { + return 0; + } + lock.lock(); + try { + E[] old = getData(); + int size = old.length; + E[] toAdd = newElementArray(c.size()); + int i = 0; + for (Iterator it = c.iterator(); it.hasNext();) { + E o = (E) it.next(); + if (indexOf(o) < 0) { + toAdd[i++] = o; + } + } + E[] data = newElementArray(size + i); + System.arraycopy(old, 0, data, 0, size); + System.arraycopy(toAdd, 0, data, size, i); + setData(data); + return i; + } finally { + lock.unlock(); + } + } + + // BEGIN android-added + /** + * Adds to this CopyOnWriteArrayList another element, given that this + * element is not yet part of the list. + * + * @param e the potential new element. + * + * @return true if the element was added, or false otherwise. + */ + // END android-added + public boolean addIfAbsent(E e) { + lock.lock(); + try { + E[] data; + E[] old = getData(); + int size = old.length; + if (size != 0) { + if (indexOf(e) >= 0) { + return false; + } + } + data = newElementArray(size + 1); + System.arraycopy(old, 0, data, 0, size); + data[size] = e; + setData(data); + return true; + } finally { + lock.unlock(); + } + } + + public void clear() { + lock.lock(); + try { + setData(newElementArray(0)); + } finally { + lock.unlock(); + } + } + + @Override + public Object clone() { + try { + CopyOnWriteArrayList thisClone = (CopyOnWriteArrayList) super.clone(); + thisClone.setData(this.getData()); + return thisClone; + } catch (CloneNotSupportedException e) { + throw new RuntimeException("CloneNotSupportedException is not expected here"); + } + } + + public boolean contains(Object o) { + return indexOf(o) >= 0; + } + + public boolean containsAll(Collection<?> c) { + E[] data = getData(); + return containsAll(c, data, 0, data.length); + } + + public boolean equals(Object o) { + if (o == this) { + return true; + } + if (!(o instanceof List)) { + return false; + } + List l = (List) o; + Iterator it = l.listIterator(); + Iterator ourIt = listIterator(); + while (it.hasNext()) { + if (!ourIt.hasNext()) { + return false; + } + Object thisListElem = it.next(); + Object anotherListElem = ourIt.next(); + if (!(thisListElem == null ? anotherListElem == null : thisListElem + .equals(anotherListElem))) { + return false; + } + } + if (ourIt.hasNext()) { + return false; + } + return true; + } + + public E get(int index) { + E[] data = getData(); + return data[index]; + } + + public int hashCode() { + int hashCode = 1; + Iterator it = listIterator(); + while (it.hasNext()) { + Object obj = it.next(); + hashCode = 31 * hashCode + (obj == null ? 0 : obj.hashCode()); + } + return hashCode; + } + + // BEGIN android-added + /** + * Returns the index of a given element, starting the search from a given + * position in the list. + * + * @param e the element to search. + * @param index the index at which to start the search. + * + * @return the index of the element or null, if the element has not been + * found at or beyond the given start index. + */ + // END android-added + public int indexOf(E e, int index) { + E[] data = getData(); + return indexOf(e, data, index, data.length - index); + } + + public int indexOf(Object o) { + E[] data = getData(); + return indexOf(o, data, 0, data.length); + } + + public boolean isEmpty() { + return size() == 0; + } + + public Iterator<E> iterator() { + return new ListIteratorImpl(getData(), 0); + } + + // BEGIN android-added + /** + * Returns the last index of a given element, starting the search from + * a given position in the list and going backwards. + * + * @param e the element to search. + * @param index the index at which to start the search. + * + * @return the index of the element or null, if the element has not been + * found at or before the given start index. + */ + // END android-added + public int lastIndexOf(E e, int index) { + E[] data = getData(); + return lastIndexOf(e, data, 0, index); + } + + public int lastIndexOf(Object o) { + E[] data = getData(); + return lastIndexOf(o, data, 0, data.length); + } + + public ListIterator<E> listIterator() { + return new ListIteratorImpl(getData(), 0); + } + + public ListIterator<E> listIterator(int index) { + E[] data = getData(); + checkIndexInclusive(index, data.length); + return new ListIteratorImpl(data, index); + } + + public E remove(int index) { + return removeRange(index, 1); + } + + public boolean remove(Object o) { + lock.lock(); + try { + int index = indexOf(o); + if (index == -1) { + return false; + } + remove(index); + return true; + } finally { + lock.unlock(); + } + } + + public boolean removeAll(Collection<?> c) { + lock.lock(); + try { + return removeAll(c, 0, getData().length) != 0; + } finally { + lock.unlock(); + } + } + + public boolean retainAll(Collection<?> c) { + if (c == null) { + throw new NullPointerException(); + } + lock.lock(); + try { + return retainAll(c, 0, getData().length) != 0; + } finally { + lock.unlock(); + } + } + + public E set(int index, E e) { + lock.lock(); + try { + int size = size(); + checkIndexExlusive(index, size); + E[] data; + data = newElementArray(size); + E[] oldArr = getData(); + System.arraycopy(oldArr, 0, data, 0, size); + E old = data[index]; + data[index] = e; + setData(data); + return old; + } finally { + lock.unlock(); + } + } + + public int size() { + return getData().length; + } + + public List<E> subList(int fromIndex, int toIndex) { + return new SubList(this, fromIndex, toIndex); + } + + public Object[] toArray() { + E[] data = getData(); + return toArray(data, 0, data.length); + } + + public <T> T[] toArray(T[] a) { + E[] data = getData(); + return (T[]) toArray(a, data, 0, data.length); + } + + public String toString() { + StringBuffer sb = new StringBuffer("["); + + Iterator it = listIterator(); + while (it.hasNext()) { + sb.append(String.valueOf(it.next())); + sb.append(", "); + } + if (sb.length() > 1) { + sb.setLength(sb.length() - 2); + } + sb.append("]"); + return sb.toString(); + } + + // private and package private methods + + @SuppressWarnings("unchecked") + private final E[] newElementArray(int size) { + return (E[])new Object[size]; + } + + /** + * sets the internal data array + * + * @param data array to set + */ + private final void setData(E[] data) { + arr = data; + } + + /** + * gets the internal data array + * + * @return the data array + */ + final E[] getData() { + if (arr == null) { + return newElementArray(0); + } + return arr; + } + + /** + * Removes from the specified range of this list + * all the elements that are contained in the specified collection + * <p/> + * !should be called under lock + * + * @return Returns the number of removed elements + */ + final int removeAll(Collection c, int start, int size) { + int ssize = c.size(); + if (ssize == 0) { + return 0; + } + Object[] old = getData(); + int arrsize = old.length; + if (arrsize == 0) { + return 0; + } + Object[] data = new Object[size]; + int j = 0; + for (int i = start; i < (start + size); i++) { + if (!c.contains(old[i])) { + data[j++] = old[i]; + } + } + if (j != size) { + E[] result = newElementArray(arrsize - (size - j)); + System.arraycopy(old, 0, result, 0, start); + System.arraycopy(data, 0, result, start, j); + System.arraycopy(old, start + size, result, start + j, arrsize + - (start + size)); + setData(result); + return (size - j); + } + return 0; + } + + /** + * Retains only the elements in the specified range of this list + * that are contained in the specified collection + * + * @return Returns the number of removed elements + */ + // should be called under lock + int retainAll(Collection c, int start, int size) { + Object[] old = getData(); + if (size == 0) { + return 0; + } + if (c.size() == 0) { + E[] data; + if (size == old.length) { + data = newElementArray(0); + } else { + data = newElementArray(old.length - size); + System.arraycopy(old, 0, data, 0, start); + System.arraycopy(old, start + size, data, start, old.length + - start - size); + } + setData(data); + return size; + } + Object[] temp = new Object[size]; + int pos = 0; + for (int i = start; i < (start + size); i++) { + if (c.contains(old[i])) { + temp[pos++] = old[i]; + } + } + if (pos == size) { + return 0; + } + E[] data = newElementArray(pos + old.length - size); + System.arraycopy(old, 0, data, 0, start); + System.arraycopy(temp, 0, data, start, pos); + System.arraycopy(old, start + size, data, start + pos, old.length + - start - size); + setData(data); + return (size - pos); + } + + /** + * Removes specified range from this list + */ + E removeRange(int start, int size) { + lock.lock(); + try { + int sizeArr = size(); + checkIndexExlusive(start, sizeArr); + checkIndexInclusive(start + size, sizeArr); + E[] data; + data = newElementArray(sizeArr - size); + E[] oldArr = getData(); + System.arraycopy(oldArr, 0, data, 0, start); + E old = oldArr[start]; + if (sizeArr > (start + size)) { + System.arraycopy(oldArr, start + size, data, start, sizeArr + - (start + size)); + } + setData(data); + return old; + } finally { + lock.unlock(); + } + } + + // some util static functions to use by iterators and methods + /** + * Returns an array containing all of the elements + * in the specified range of the array in proper sequence + */ + static Object[] toArray(Object[] data, int start, int size) { + Object[] result = new Object[size]; + System.arraycopy(data, start, result, 0, size); + return result; + } + + /** + * Returns an array containing all of the elements + * in the specified range of the array in proper sequence, + * stores the result in the array, specified by first parameter + * (as for public instance method toArray(Object[] to) + */ + static Object[] toArray(Object[] to, Object[] data, int start, int size) { + int l = data.length; + if (to.length < l) { + to = (Object[]) Array.newInstance(to.getClass().getComponentType(), + l); + } else { + if (to.length > l) { + to[l] = null; + } + } + System.arraycopy(data, start, to, 0, size); + return to; + } + + /** + * Checks if the specified range of the + * array contains all of the elements in the collection + * + * @param c collection with elements + * @param data array where to search the elements + * @param start start index + * @param size size of the range + */ + static final boolean containsAll(Collection c, Object[] data, int start, + int size) { + if (size == 0) { + return false; + } + Iterator it = c.iterator(); + while (it.hasNext()) { + Object next = it.next(); + if (indexOf(next, data, start, size) < 0) { + return false; + } + } + return true; + } + + /** + * Returns the index in the specified range of the data array + * of the last occurrence of the specified element + * + * @param o element to search + * @param data array where to search + * @param start start index + * @param size size of the range + * @return + */ + static final int lastIndexOf(Object o, Object[] data, int start, int size) { + if (size == 0) { + return -1; + } + if (o != null) { + for (int i = start + size - 1; i > start - 1; i--) { + if (o.equals(data[i])) { + return i; + } + } + } else { + for (int i = start + size - 1; i > start - 1; i--) { + if (data[i] == null) { + return i; + } + } + } + return -1; + } + + /** + * Returns the index in the specified range of the data array + * of the first occurrence of the specified element + * + * @param o element to search + * @param data array where to search + * @param start start index + * @param size end index + * @return + */ + static final int indexOf(Object o, Object[] data, int start, int size) { + if (size == 0) { + return -1; + } + if (o == null) { + for (int i = start; i < start + size; i++) { + if (data[i] == null) { + return i; + } + } + } else { + for (int i = start; i < start + size; i++) { + if (o.equals(data[i])) { + return i; + } + } + } + return -1; + } + + /** + * Throws <code>IndexOutOfBoundsException</code> if <code>index</code> + * is out of the list bounds. + * + * @param index element index to check. + */ + static final void checkIndexInclusive(int index, int size) { + if (index < 0 || index > size) { + throw new IndexOutOfBoundsException("Index is " + index + ", size is " + size); + } + } + + /** + * Throws <code>IndexOutOfBoundsException</code> if <code>index</code> + * is out of the list bounds. Excluding the last element. + * + * @param index element index to check. + */ + static final void checkIndexExlusive(int index, int size) { + if (index < 0 || index >= size) { + throw new IndexOutOfBoundsException("Index is " + index + ", size is " + size); + } + } + + /** + * list iterator implementation, + * when created gets snapshot of the list, + * so never throws ConcurrentModificationException + */ + private static class ListIteratorImpl implements ListIterator { + private final Object[] arr; + + private int current; + + private final int size; + + final int size() { + return size; + } + + public ListIteratorImpl(Object[] data, int current) { + this.current = current; + arr = data; + size = data.length; + } + + public void add(Object o) { + throw new UnsupportedOperationException("Unsupported operation add"); + } + + public boolean hasNext() { + if (current < size) { + return true; + } + return false; + } + + public boolean hasPrevious() { + return current > 0; + } + + public Object next() { + if (hasNext()) { + return arr[current++]; + } + throw new NoSuchElementException("pos is " + current + ", size is " + size); + } + + public int nextIndex() { + return current; + } + + public Object previous() { + if (hasPrevious()) { + return arr[--current]; + } + throw new NoSuchElementException("pos is " + (current-1) + ", size is " + size); + } + + public int previousIndex() { + return current - 1; + } + + public void remove() { + throw new UnsupportedOperationException("Unsupported operation remove"); + } + + public void set(Object o) { + throw new UnsupportedOperationException("Unsupported operation set"); + } + + } + + /** + * Keeps a state of sublist implementation, + * size and array declared as final, + * so we'll never get the unconsistent state + */ + static final class SubListReadData { + final int size; + + final Object[] data; + + SubListReadData(int size, Object[] data) { + this.size = size; + this.data = data; + } + } + + /** + * Represents a list returned by <code>sublist()</code>. + */ + static class SubList implements List { + private final CopyOnWriteArrayList list; + + private volatile SubListReadData read; + + private final int start; + + /** + * Sublist constructor. + * + * @param list backing list. + * @param fromIdx startingIndex, inclusive + * @param toIdx endIndex, exclusive + */ + public SubList(CopyOnWriteArrayList list, int fromIdx, int toIdx) { + this.list = list; + Object[] data = list.getData(); + int size = toIdx - fromIdx; + checkIndexExlusive(fromIdx, data.length); + checkIndexInclusive(toIdx, data.length); + read = new SubListReadData(size, list.getData()); + start = fromIdx; + } + + /** + * throws ConcurrentModificationException when the list + * is structurally modified in the other way other than via this subList + * <p/> + * Should be called under lock! + */ + private void checkModifications() { + if (read.data != list.getData()) { + throw new ConcurrentModificationException(); + } + } + + /** + * @see java.util.List#listIterator(int) + */ + public ListIterator listIterator(int startIdx) { + return new SubListIterator(startIdx, read); + } + + /** + * @see java.util.List#set(int, java.lang.Object) + */ + public Object set(int index, Object obj) { + list.lock.lock(); + try { + checkIndexExlusive(index, read.size); + checkModifications(); + Object result = list.set(index + start, obj); + read = new SubListReadData(read.size, list.getData()); + return result; + } finally { + list.lock.unlock(); + } + } + + /** + * @see java.util.List#get(int) + */ + public Object get(int index) { + SubListReadData data = read; + if (data.data != list.getData()) { + list.lock.lock(); + try { + data = read; + if (data.data != list.getData()) { + throw new ConcurrentModificationException(); + } + } finally { + list.lock.unlock(); + } + } + checkIndexExlusive(index, data.size); + return data.data[index + start]; + } + + /** + * @see java.util.Collection#size() + */ + public int size() { + return read.size; + } + + /** + * @see java.util.List#remove(int) + */ + public Object remove(int index) { + list.lock.lock(); + try { + checkIndexExlusive(index, read.size); + checkModifications(); + Object obj = list.remove(index + start); + read = new SubListReadData(read.size - 1, list.getData()); + return obj; + } finally { + list.lock.unlock(); + } + } + + /** + * @see java.util.List#add(int, java.lang.Object) + */ + public void add(int index, Object object) { + list.lock.lock(); + try { + checkIndexInclusive(index, read.size); + checkModifications(); + list.add(index + start, object); + read = new SubListReadData(read.size + 1, list.getData()); + } finally { + list.lock.unlock(); + } + } + + public boolean add(Object o) { + list.lock.lock(); + try { + checkModifications(); + list.add(start + read.size, o); + read = new SubListReadData(read.size + 1, list.getData()); + return true; + } finally { + list.lock.unlock(); + } + } + + public boolean addAll(Collection c) { + list.lock.lock(); + try { + checkModifications(); + int d = list.size(); + list.addAll(start + read.size, c); + read = new SubListReadData(read.size + (list.size() - d), list + .getData()); + return true; + } finally { + list.lock.unlock(); + } + } + + public void clear() { + list.lock.lock(); + try { + checkModifications(); + list.removeRange(start, read.size); + read = new SubListReadData(0, list.getData()); + } finally { + list.lock.unlock(); + } + } + + public boolean contains(Object o) { + return indexOf(o) != -1; + } + + public boolean containsAll(Collection c) { + SubListReadData b = read; + return CopyOnWriteArrayList.containsAll(c, b.data, start, b.size); + } + + public int indexOf(Object o) { + SubListReadData b = read; + int ind = CopyOnWriteArrayList.indexOf(o, b.data, start, b.size) + - start; + return ind < 0 ? -1 : ind; + } + + public boolean isEmpty() { + return read.size == 0; + } + + public Iterator iterator() { + return new SubListIterator(0, read); + } + + public int lastIndexOf(Object o) { + SubListReadData b = read; + int ind = CopyOnWriteArrayList + .lastIndexOf(o, b.data, start, b.size) + - start; + return ind < 0 ? -1 : ind; + } + + public ListIterator listIterator() { + return new SubListIterator(0, read); + } + + public boolean remove(Object o) { + list.lock.lock(); + try { + checkModifications(); + int i = indexOf(o); + if (i == -1) { + return false; + } + boolean result = list.remove(i + start) != null; + if (result) { + read = new SubListReadData(read.size - 1, list.getData()); + } + return result; + } finally { + list.lock.unlock(); + } + } + + public boolean removeAll(Collection c) { + list.lock.lock(); + try { + checkModifications(); + int removed = list.removeAll(c, start, read.size); + if (removed > 0) { + read = new SubListReadData(read.size - removed, list + .getData()); + return true; + } + } finally { + list.lock.unlock(); + } + return false; + } + + public boolean retainAll(Collection c) { + list.lock.lock(); + try { + checkModifications(); + int removed = list.retainAll(c, start, read.size); + if (removed > 0) { + read = new SubListReadData(read.size - removed, list + .getData()); + return true; + } + return false; + } finally { + list.lock.unlock(); + } + } + + public List subList(int fromIndex, int toIndex) { + return new SubList(list, start + fromIndex, start + toIndex); + } + + public Object[] toArray() { + SubListReadData r = read; + return CopyOnWriteArrayList.toArray(r.data, start, r.size); + } + + public Object[] toArray(Object[] a) { + SubListReadData r = read; + return CopyOnWriteArrayList.toArray(a, r.data, start, r.size); + } + + /** + * @see java.util.List#addAll(int, java.util.Collection) + */ + public boolean addAll(int index, Collection collection) { + list.lock.lock(); + try { + checkIndexInclusive(index, read.size); + checkModifications(); + int d = list.size(); + boolean rt = list.addAll(index + start, collection); + read = new SubListReadData(read.size + list.size() - d, list + .getData()); + return rt; + } finally { + list.lock.unlock(); + } + } + + /** + * Implementation of <code>ListIterator</code> for the + * <code>SubList</code> + * gets a snapshot of the sublist, + * never throws ConcurrentModificationException + */ + private class SubListIterator extends ListIteratorImpl { + private final SubListReadData dataR; + + /** + * Constructs an iterator starting with the given index + * + * @param index index of the first element to iterate. + */ + private SubListIterator(int index, SubListReadData d) { + super(d.data, index + start); + this.dataR = d; + } + + /** + * @see java.util.ListIterator#nextIndex() + */ + public int nextIndex() { + return super.nextIndex() - start; + } + + /** + * @see java.util.ListIterator#previousIndex() + */ + public int previousIndex() { + return super.previousIndex() - start; + } + + /** + * @see java.util.Iterator#hasNext() + */ + public boolean hasNext() { + return nextIndex() < dataR.size; + } + + /** + * @see java.util.ListIterator#hasPrevious() + */ + public boolean hasPrevious() { + return previousIndex() > -1; + } + } + + } + + //serialization support + /** + * Writes the object state to the ObjectOutputStream. + * + * @param oos ObjectOutputStream to write object to. + * @throws IOException if an I/O error occur. + */ + private void writeObject(ObjectOutputStream oos) throws IOException { + E[] back = getData(); + int size = back.length; + oos.defaultWriteObject(); + oos.writeInt(size); + for (int i = 0; i < size; i++) { + oos.writeObject(back[i]); + } + } + + /** + * Reads the object state from the ObjectOutputStream. + * + * @param ois ObjectInputStream to read object from. + * @throws IOException if an I/O error occur. + */ + private void readObject(ObjectInputStream ois) throws IOException, + ClassNotFoundException { + ois.defaultReadObject(); + int length = ois.readInt(); + if (length == 0) { + setData(newElementArray(0)); + } else { + E[] back = newElementArray(length); + for (int i = 0; i < back.length; i++) { + back[i] = (E) ois.readObject(); + } + setData(back); + } + } +} diff --git a/concurrent/src/main/java/java/util/concurrent/CopyOnWriteArraySet.java b/concurrent/src/main/java/java/util/concurrent/CopyOnWriteArraySet.java new file mode 100644 index 0000000..23b228b --- /dev/null +++ b/concurrent/src/main/java/java/util/concurrent/CopyOnWriteArraySet.java @@ -0,0 +1,105 @@ +/* + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain. Use, modify, and + * redistribute this code in any way without acknowledgement. + */ + +package java.util.concurrent; +import java.util.*; + +// BEGIN android-note +// removed link to collections framework docs +// Removed clonable interface to be closer to the RI. +// END android-note + +/** + * A {@link java.util.Set} that uses {@link + * java.util.concurrent.CopyOnWriteArrayList} for all of its + * operations. Thus, it shares the same basic properties: + * <ul> + * <li>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. + * <li>Mutative operations(add, set, remove, etc) are expensive + * since they usually entail copying the entire underlying array. + * <li>Iterators do not support the mutative remove operation + * <li>Traversal via iterators is very fast and cannot ever encounter + * interference from other threads. Iterators rely on + * unchanging snapshots of the array at the time the iterators were + * constructed. + * </ul> + * <p> + * <b>Sample Usage.</b> Probably the main application + * of copy-on-write sets are classes that maintain + * sets of Handler objects + * that must be multicasted to upon an update command. This + * is a classic case where you do not want to be holding a + * lock while sending a message, and where traversals normally + * vastly overwhelm additions. + * <pre> + * class Handler { void handle(); ... } + * + * class X { + * private final CopyOnWriteArraySet<Handler> handlers = new CopyOnWriteArraySet<Handler>(); + * public void addHandler(Handler h) { handlers.add(h); } + * + * private long internalState; + * private synchronized void changeState() { internalState = ...; } + * + * public void update() { + * changeState(); + * Iterator it = handlers.iterator(); + * while (it.hasNext()) + * it.next().handle(); + * } + * } + * </pre> + * @see CopyOnWriteArrayList + * + * @since 1.5 + * @author Doug Lea + * @param <E> the type of elements held in this collection + */ +public class CopyOnWriteArraySet<E> extends AbstractSet<E> + // BEGIN android-changed + // removed Cloneable from list of implemented interfaces + // implements Cloneable, java.io.Serializable { + implements java.io.Serializable { + // END android-changed + private static final long serialVersionUID = 5457747651344034263L; + + private final CopyOnWriteArrayList<E> al; + + /** + * Creates an empty set. + */ + public CopyOnWriteArraySet() { + al = new CopyOnWriteArrayList<E>(); + } + + /** + * Creates a set containing all of the elements of the specified + * Collection. + * @param c the collection + */ + public CopyOnWriteArraySet(Collection<? extends E> c) { + al = new CopyOnWriteArrayList<E>(); + al.addAllAbsent(c); + } + + public int size() { return al.size(); } + public boolean isEmpty() { return al.isEmpty(); } + public boolean contains(Object o) { return al.contains(o); } + public Object[] toArray() { return al.toArray(); } + public <T> T[] toArray(T[] a) { return al.toArray(a); } + public void clear() { al.clear(); } + public Iterator<E> iterator() { return al.iterator(); } + public boolean remove(Object o) { return al.remove(o); } + public boolean add(E o) { return al.addIfAbsent(o); } + public boolean containsAll(Collection<?> c) { return al.containsAll(c); } + public boolean addAll(Collection<? extends E> c) { return al.addAllAbsent(c) > 0; } + public boolean removeAll(Collection<?> c) { return al.removeAll(c); } + public boolean retainAll(Collection<?> c) { return al.retainAll(c); } + +} diff --git a/concurrent/src/main/java/java/util/concurrent/CountDownLatch.java b/concurrent/src/main/java/java/util/concurrent/CountDownLatch.java new file mode 100644 index 0000000..721744c --- /dev/null +++ b/concurrent/src/main/java/java/util/concurrent/CountDownLatch.java @@ -0,0 +1,280 @@ +/* + * 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/licenses/publicdomain + */ + +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. + * + * <p>A <tt>CountDownLatch</tt> is initialized with a given + * <em>count</em>. The {@link #await await} methods block until the current + * {@link #getCount 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}. + * + * <p>A <tt>CountDownLatch</tt> is a versatile synchronization tool + * and can be used for a number of purposes. A + * <tt>CountDownLatch</tt> 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 <tt>CountDownLatch</tt> initialized to <em>N</em> + * can be used to make one thread wait until <em>N</em> threads have + * completed some action, or some action has been completed N times. + * <p>A useful property of a <tt>CountDownLatch</tt> is that it + * doesn't require that threads calling <tt>countDown</tt> 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. + * + * <p><b>Sample usage:</b> Here is a pair of classes in which a group + * of worker threads use two countdown latches: + * <ul> + * <li>The first is a start signal that prevents any worker from proceeding + * until the driver is ready for them to proceed; + * <li>The second is a completion signal that allows the driver to wait + * until all workers have completed. + * </ul> + * + * <pre> + * 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() { ... } + * } + * + * </pre> + * + * <p>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}.) + * + * <pre> + * 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() { ... } + * } + * + * </pre> + * + * @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 { + Sync(int count) { + setState(count); + } + + int getCount() { + return getState(); + } + + public int tryAcquireShared(int acquires) { + return getState() == 0? 1 : -1; + } + + public 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 <tt>CountDownLatch</tt> 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 <tt>count</tt> is less than zero. + */ + 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 {@link Thread#interrupt interrupted}. + * + * <p>If the current {@link #getCount count} is zero then this method + * returns immediately. + * <p>If the current {@link #getCount count} is greater than zero then + * the current thread becomes disabled for thread scheduling + * purposes and lies dormant until one of two things happen: + * <ul> + * <li>The count reaches zero due to invocations of the + * {@link #countDown} method; or + * <li>Some other thread {@link Thread#interrupt interrupts} the current + * thread. + * </ul> + * <p>If the current thread: + * <ul> + * <li>has its interrupted status set on entry to this method; or + * <li>is {@link Thread#interrupt interrupted} while waiting, + * </ul> + * 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 {@link Thread#interrupt interrupted}, + * or the specified waiting time elapses. + * + * <p>If the current {@link #getCount count} is zero then this method + * returns immediately with the value <tt>true</tt>. + * + * <p>If the current {@link #getCount count} is greater than zero then + * the current thread becomes disabled for thread scheduling + * purposes and lies dormant until one of three things happen: + * <ul> + * <li>The count reaches zero due to invocations of the + * {@link #countDown} method; or + * <li>Some other thread {@link Thread#interrupt interrupts} the current + * thread; or + * <li>The specified waiting time elapses. + * </ul> + * <p>If the count reaches zero then the method returns with the + * value <tt>true</tt>. + * <p>If the current thread: + * <ul> + * <li>has its interrupted status set on entry to this method; or + * <li>is {@link Thread#interrupt interrupted} while waiting, + * </ul> + * then {@link InterruptedException} is thrown and the current thread's + * interrupted status is cleared. + * + * <p>If the specified waiting time elapses then the value <tt>false</tt> + * 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 <tt>timeout</tt> argument. + * @return <tt>true</tt> if the count reached zero and <tt>false</tt> + * 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. + * <p>If the current {@link #getCount 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. + * <p>If the current {@link #getCount count} equals zero then nothing + * happens. + */ + public void countDown() { + sync.releaseShared(1); + } + + /** + * Returns the current count. + * <p>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 + * "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 --git a/concurrent/src/main/java/java/util/concurrent/CyclicBarrier.java b/concurrent/src/main/java/java/util/concurrent/CyclicBarrier.java new file mode 100644 index 0000000..d70c4c7 --- /dev/null +++ b/concurrent/src/main/java/java/util/concurrent/CyclicBarrier.java @@ -0,0 +1,430 @@ +/* + * 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/licenses/publicdomain + */ + +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 + * <em>cyclic</em> because it can be re-used after the waiting threads + * are released. + * + * <p>A <tt>CyclicBarrier</tt> 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 <em>barrier action</em> is useful + * for updating shared-state before any of the parties continue. + * + * <p><b>Sample usage:</b> Here is an example of + * using a barrier in a parallel decomposition design: + * <pre> + * 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(); + * } + * } + * </pre> + * 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 <tt>done()</tt> will return + * <tt>true</tt> and each worker will terminate. + * + * <p>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: + * <pre> if (barrier.await() == 0) { + * // log the completion of this iteration + * }</pre> + * + * <p>The <tt>CyclicBarrier</tt> uses a fast-fail 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, even those that have not yet resumed + * from a previous {@link #await}. will also leave abnormally via + * {@link BrokenBarrierException} (or <tt>InterruptedException</tt> if + * they too were interrupted at about the same time). + * + * @since 1.5 + * @see CountDownLatch + * + * @author Doug Lea + */ +public class CyclicBarrier { + /** 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 generation number. Incremented upon barrier trip. + * Retracted upon reset. + */ + private long generation; + + /** + * Breakage indicator. + */ + private boolean broken; + + /** + * Number of parties still waiting. Counts down from parties to 0 + * on each cycle. + */ + private int count; + + /** + * Updates state on barrier trip and wake up everyone. + */ + private void nextGeneration() { + count = parties; + ++generation; + trip.signalAll(); + } + + /** + * Sets barrier as broken and wake up everyone + */ + private void breakBarrier() { + broken = true; + 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 { + int index = --count; + long g = generation; + + if (broken) + throw new BrokenBarrierException(); + + if (Thread.interrupted()) { + breakBarrier(); + throw new InterruptedException(); + } + + if (index == 0) { // tripped + nextGeneration(); + boolean ranAction = false; + try { + Runnable command = barrierCommand; + if (command != null) + command.run(); + ranAction = true; + return 0; + } finally { + if (!ranAction) + breakBarrier(); + } + } + + for (;;) { + try { + if (!timed) + trip.await(); + else if (nanos > 0L) + nanos = trip.awaitNanos(nanos); + } catch (InterruptedException ie) { + breakBarrier(); + throw ie; + } + + if (broken || + g > generation) // true if a reset occurred while waiting + throw new BrokenBarrierException(); + + if (g < generation) + return index; + + if (timed && nanos <= 0L) { + breakBarrier(); + throw new TimeoutException(); + } + } + + } finally { + lock.unlock(); + } + } + + /** + * Creates a new <tt>CyclicBarrier</tt> 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 <tt>null</tt> if there is no action. + * + * @throws IllegalArgumentException if <tt>parties</tt> 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 <tt>CyclicBarrier</tt> that will trip when the + * given number of parties (threads) are waiting upon it, and + * does not perform a predefined action upon each barrier. + * + * @param parties the number of threads that must invoke {@link #await} + * before the barrier is tripped. + * + * @throws IllegalArgumentException if <tt>parties</tt> 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 {@link #getParties parties} have invoked <tt>await</tt> + * on this barrier. + * + * <p>If the current thread is not the last to arrive then it is + * disabled for thread scheduling purposes and lies dormant until + * one of following things happens: + * <ul> + * <li>The last thread arrives; or + * <li>Some other thread {@link Thread#interrupt interrupts} the current + * thread; or + * <li>Some other thread {@link Thread#interrupt interrupts} one of the + * other waiting threads; or + * <li>Some other thread times out while waiting for barrier; or + * <li>Some other thread invokes {@link #reset} on this barrier. + * </ul> + * <p>If the current thread: + * <ul> + * <li>has its interrupted status set on entry to this method; or + * <li>is {@link Thread#interrupt interrupted} while waiting + * </ul> + * then {@link InterruptedException} is thrown and the current thread's + * interrupted status is cleared. + * + * <p>If the barrier is {@link #reset} while any thread is waiting, or if + * the barrier {@link #isBroken is broken} when <tt>await</tt> is invoked, + * or while any thread is waiting, + * then {@link BrokenBarrierException} is thrown. + * + * <p>If any thread is {@link Thread#interrupt interrupted} while waiting, + * then all other waiting threads will throw + * {@link BrokenBarrierException} and the barrier is placed in the broken + * state. + * + * <p>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 + * <tt>{@link #getParties()} - 1</tt> 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 <em>another</em> thread was + * interrupted while the current thread was waiting, or the barrier was + * reset, or the barrier was broken when <tt>await</tt> 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 {@link #getParties parties} have invoked <tt>await</tt> + * on this barrier. + * + * <p>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: + * <ul> + * <li>The last thread arrives; or + * <li>The specified timeout elapses; or + * <li>Some other thread {@link Thread#interrupt interrupts} the current + * thread; or + * <li>Some other thread {@link Thread#interrupt interrupts} one of the + * other waiting threads; or + * <li>Some other thread times out while waiting for barrier; or + * <li>Some other thread invokes {@link #reset} on this barrier. + * </ul> + * <p>If the current thread: + * <ul> + * <li>has its interrupted status set on entry to this method; or + * <li>is {@link Thread#interrupt interrupted} while waiting + * </ul> + * then {@link InterruptedException} is thrown and the current thread's + * interrupted status is cleared. + * + * <p>If the barrier is {@link #reset} while any thread is waiting, or if + * the barrier {@link #isBroken is broken} when <tt>await</tt> is invoked, + * or while any thread is waiting, + * then {@link BrokenBarrierException} is thrown. + * + * <p>If any thread is {@link Thread#interrupt interrupted} while waiting, + * then all other waiting threads will throw + * {@link BrokenBarrierException} and the barrier is placed in the broken + * state. + * + * <p>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 + * <tt>{@link #getParties()} - 1</tt> 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 <em>another</em> thread was + * interrupted while the current thread was waiting, or the barrier was + * reset, or the barrier was broken when <tt>await</tt> 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 <tt>true</tt> 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; + * and <tt>false</tt> otherwise. + */ + public boolean isBroken() { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + return 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 <em>after</em> + * 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 { + /* + * Retract generation number enough to cover threads + * currently waiting on current and still resuming from + * previous generation, plus similarly accommodating spans + * after the reset. + */ + generation -= 4; + broken = false; + trip.signalAll(); + } 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 --git a/concurrent/src/main/java/java/util/concurrent/DelayQueue.java b/concurrent/src/main/java/java/util/concurrent/DelayQueue.java new file mode 100644 index 0000000..88c4280 --- /dev/null +++ b/concurrent/src/main/java/java/util/concurrent/DelayQueue.java @@ -0,0 +1,365 @@ +/* + * 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/licenses/publicdomain + */ + + +package java.util.concurrent; +import java.util.concurrent.locks.*; +import java.util.*; + +// BEGIN android-note +// removed link to collections framework docs +// END android-note + +/** + * An unbounded {@linkplain BlockingQueue blocking queue} of <tt>Delayed</tt> + * elements, in which an element can only be taken when its delay has expired. + * The <em>head</em> of the queue is that <tt>Delayed</tt> element whose delay + * expired furthest in the past - if no delay has expired there is no head and + * <tt>poll</tt> will return <tt>null</tt>. + * This queue does not permit <tt>null</tt> elements. + * <p>This class implements all of the <em>optional</em> methods + * of the {@link Collection} and {@link Iterator} interfaces. + * + * @since 1.5 + * @author Doug Lea + * @param <E> the type of elements held in this collection + */ + +public class DelayQueue<E extends Delayed> extends AbstractQueue<E> + implements BlockingQueue<E> { + + private transient final ReentrantLock lock = new ReentrantLock(); + private transient final Condition available = lock.newCondition(); + private final PriorityQueue<E> q = new PriorityQueue<E>(); + + /** + * Creates a new <tt>DelayQueue</tt> that is initially empty. + */ + public DelayQueue() {} + + /** + * Creates a <tt>DelayQueue</tt> initially containing the elements of the + * given collection of {@link Delayed} instances. + * + * @param c the collection + * @throws NullPointerException if <tt>c</tt> or any element within it + * is <tt>null</tt> + * + */ + public DelayQueue(Collection<? extends E> c) { + this.addAll(c); + } + + /** + * Inserts the specified element into this delay queue. + * + * @param o the element to add + * @return <tt>true</tt> + * @throws NullPointerException if the specified element is <tt>null</tt>. + */ + public boolean offer(E o) { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + E first = q.peek(); + q.offer(o); + if (first == null || o.compareTo(first) < 0) + available.signalAll(); + return true; + } finally { + lock.unlock(); + } + } + + + /** + * Adds the specified element to this delay queue. As the queue is + * unbounded this method will never block. + * @param o the element to add + * @throws NullPointerException if the specified element is <tt>null</tt>. + */ + public void put(E o) { + offer(o); + } + + /** + * Inserts the specified element into this delay queue. As the queue is + * unbounded this method will never block. + * @param o 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 <tt>true</tt> + * @throws NullPointerException if the specified element is <tt>null</tt>. + */ + public boolean offer(E o, long timeout, TimeUnit unit) { + return offer(o); + } + + /** + * Adds the specified element to this queue. + * @param o the element to add + * @return <tt>true</tt> (as per the general contract of + * <tt>Collection.add</tt>). + * + * @throws NullPointerException if the specified element is <tt>null</tt>. + */ + public boolean add(E o) { + return offer(o); + } + + 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) { + long tl = available.awaitNanos(delay); + } else { + E x = q.poll(); + assert x != null; + if (q.size() != 0) + available.signalAll(); // wake up other takers + return x; + + } + } + } + } finally { + lock.unlock(); + } + } + + public E poll(long time, TimeUnit unit) throws InterruptedException { + final ReentrantLock lock = this.lock; + lock.lockInterruptibly(); + long nanos = unit.toNanos(time); + 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) { + if (delay > nanos) + delay = nanos; + long timeLeft = available.awaitNanos(delay); + nanos -= delay - timeLeft; + } else { + E x = q.poll(); + assert x != null; + if (q.size() != 0) + available.signalAll(); + return x; + } + } + } + } finally { + lock.unlock(); + } + } + + 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 { + E x = q.poll(); + assert x != null; + if (q.size() != 0) + available.signalAll(); + return x; + } + } finally { + lock.unlock(); + } + } + + 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(); + } + } + + public int drainTo(Collection<? super E> 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; + } + if (n > 0) + available.signalAll(); + return n; + } finally { + lock.unlock(); + } + } + + public int drainTo(Collection<? super E> 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; + } + if (n > 0) + available.signalAll(); + return n; + } finally { + lock.unlock(); + } + } + + /** + * Atomically removes all of the elements from this delay queue. + * The queue will be empty after this call returns. + */ + public void clear() { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + q.clear(); + } finally { + lock.unlock(); + } + } + + /** + * Always returns <tt>Integer.MAX_VALUE</tt> because + * a <tt>DelayQueue</tt> is not capacity constrained. + * @return <tt>Integer.MAX_VALUE</tt> + */ + public int remainingCapacity() { + return Integer.MAX_VALUE; + } + + public Object[] toArray() { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + return q.toArray(); + } finally { + lock.unlock(); + } + } + + public <T> T[] toArray(T[] array) { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + return q.toArray(array); + } finally { + lock.unlock(); + } + } + + public boolean remove(Object o) { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + return q.remove(o); + } 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 thread-safe "fast-fail" iterator that will + * throw {@link java.util.ConcurrentModificationException} + * upon detected interference. + * + * @return an iterator over the elements in this queue. + */ + public Iterator<E> iterator() { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + return new Itr(q.iterator()); + } finally { + lock.unlock(); + } + } + + private class Itr<E> implements Iterator<E> { + private final Iterator<E> iter; + Itr(Iterator<E> i) { + iter = i; + } + + public boolean hasNext() { + return iter.hasNext(); + } + + public E next() { + final ReentrantLock lock = DelayQueue.this.lock; + lock.lock(); + try { + return iter.next(); + } finally { + lock.unlock(); + } + } + + public void remove() { + final ReentrantLock lock = DelayQueue.this.lock; + lock.lock(); + try { + iter.remove(); + } finally { + lock.unlock(); + } + } + } + +} diff --git a/concurrent/src/main/java/java/util/concurrent/Delayed.java b/concurrent/src/main/java/java/util/concurrent/Delayed.java new file mode 100644 index 0000000..62f7568 --- /dev/null +++ b/concurrent/src/main/java/java/util/concurrent/Delayed.java @@ -0,0 +1,32 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent; + +import java.util.*; + +/** + * A mix-in style interface for marking objects that should be + * acted upon after a given delay. + * + * <p>An implementation of this interface must define a + * <tt>compareTo</tt> method that provides an ordering consistent with + * its <tt>getDelay</tt> method. + * + * @since 1.5 + * @author Doug Lea + */ +public interface Delayed extends Comparable<Delayed> { + + /** + * Returns the delay associated with this object, in the given time unit. + * + * @param unit the time unit + * @return the delay; zero or negative values indicate that the + * delay has already elapsed + */ + long getDelay(TimeUnit unit); +} diff --git a/concurrent/src/main/java/java/util/concurrent/Exchanger.java b/concurrent/src/main/java/java/util/concurrent/Exchanger.java new file mode 100644 index 0000000..da8c815 --- /dev/null +++ b/concurrent/src/main/java/java/util/concurrent/Exchanger.java @@ -0,0 +1,247 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent; +import java.util.concurrent.locks.*; + +/** + * A synchronization point at which two threads can exchange objects. + * Each thread presents some object on entry to the {@link #exchange + * exchange} method, and receives the object presented by the other + * thread on return. + * + * <p><b>Sample Usage:</b> + * Here are the highlights of a class that uses an <tt>Exchanger</tt> 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. + * <pre> + * class FillAndEmpty { + * Exchanger<DataBuffer> 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.full()) + * 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.empty()) + * currentBuffer = exchanger.exchange(currentBuffer); + * } + * } catch (InterruptedException ex) { ... handle ...} + * } + * } + * + * void start() { + * new Thread(new FillingLoop()).start(); + * new Thread(new EmptyingLoop()).start(); + * } + * } + * </pre> + * + * @since 1.5 + * @author Doug Lea + * @param <V> The type of objects that may be exchanged + */ +public class Exchanger<V> { + private final ReentrantLock lock = new ReentrantLock(); + private final Condition taken = lock.newCondition(); + + /** Holder for the item being exchanged */ + private V item; + + /** + * Arrival count transitions from 0 to 1 to 2 then back to 0 + * during an exchange. + */ + private int arrivalCount; + + /** + * Main exchange function, handling the different policy variants. + */ + private V doExchange(V x, boolean timed, long nanos) throws InterruptedException, TimeoutException { + lock.lock(); + try { + V other; + + // If arrival count already at two, we must wait for + // a previous pair to finish and reset the count; + while (arrivalCount == 2) { + if (!timed) + taken.await(); + else if (nanos > 0) + nanos = taken.awaitNanos(nanos); + else + throw new TimeoutException(); + } + + int count = ++arrivalCount; + + // If item is already waiting, replace it and signal other thread + if (count == 2) { + other = item; + item = x; + taken.signal(); + return other; + } + + // Otherwise, set item and wait for another thread to + // replace it and signal us. + + item = x; + InterruptedException interrupted = null; + try { + while (arrivalCount != 2) { + if (!timed) + taken.await(); + else if (nanos > 0) + nanos = taken.awaitNanos(nanos); + else + break; // timed out + } + } catch (InterruptedException ie) { + interrupted = ie; + } + + // Get and reset item and count after the wait. + // (We need to do this even if wait was aborted.) + other = item; + item = null; + count = arrivalCount; + arrivalCount = 0; + taken.signal(); + + // If the other thread replaced item, then we must + // continue even if cancelled. + if (count == 2) { + if (interrupted != null) + Thread.currentThread().interrupt(); + return other; + } + + // If no one is waiting for us, we can back out + if (interrupted != null) + throw interrupted; + else // must be timeout + throw new TimeoutException(); + } finally { + lock.unlock(); + } + } + + /** + * Create a new Exchanger. + **/ + public Exchanger() { + } + + /** + * Waits for another thread to arrive at this exchange point (unless + * it is {@link Thread#interrupt interrupted}), + * and then transfers the given object to it, receiving its object + * in return. + * <p>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. + * <p>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: + * <ul> + * <li>Some other thread enters the exchange; or + * <li>Some other thread {@link Thread#interrupt interrupts} the current + * thread. + * </ul> + * <p>If the current thread: + * <ul> + * <li>has its interrupted status set on entry to this method; or + * <li>is {@link Thread#interrupt interrupted} while waiting + * for the exchange, + * </ul> + * 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 current thread was interrupted + * while waiting + **/ + public V exchange(V x) throws InterruptedException { + try { + return doExchange(x, false, 0); + } catch (TimeoutException cannotHappen) { + throw new Error(cannotHappen); + } + } + + /** + * Waits for another thread to arrive at this exchange point (unless + * it is {@link Thread#interrupt interrupted}, or the specified waiting + * time elapses), + * and then transfers the given object to it, receiving its object + * in return. + * + * <p>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. + * + * <p>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: + * <ul> + * <li>Some other thread enters the exchange; or + * <li>Some other thread {@link Thread#interrupt interrupts} the current + * thread; or + * <li>The specified waiting time elapses. + * </ul> + * <p>If the current thread: + * <ul> + * <li>has its interrupted status set on entry to this method; or + * <li>is {@link Thread#interrupt interrupted} while waiting + * for the exchange, + * </ul> + * then {@link InterruptedException} is thrown and the current thread's + * interrupted status is cleared. + * + * <p>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 <tt>timeout</tt> argument. + * @return the object provided by the other thread. + * @throws InterruptedException if 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 { + return doExchange(x, true, unit.toNanos(timeout)); + } + +} + + diff --git a/concurrent/src/main/java/java/util/concurrent/ExecutionException.java b/concurrent/src/main/java/java/util/concurrent/ExecutionException.java new file mode 100644 index 0000000..8f0e448 --- /dev/null +++ b/concurrent/src/main/java/java/util/concurrent/ExecutionException.java @@ -0,0 +1,65 @@ +/* + * 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/licenses/publicdomain + */ + +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 a <tt>ExecutionException</tt> 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 a <tt>ExecutionException</tt> 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 a <tt>ExecutionException</tt> 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 a <tt>ExecutionException</tt> with the specified cause. + * The detail message is set to: + * <pre> + * (cause == null ? null : cause.toString())</pre> + * (which typically contains the class and detail message of + * <tt>cause</tt>). + * + * @param cause the cause (which is saved for later retrieval by the + * {@link #getCause()} method) + */ + public ExecutionException(Throwable cause) { + super(cause); + } +} diff --git a/concurrent/src/main/java/java/util/concurrent/Executor.java b/concurrent/src/main/java/java/util/concurrent/Executor.java new file mode 100644 index 0000000..60fe193 --- /dev/null +++ b/concurrent/src/main/java/java/util/concurrent/Executor.java @@ -0,0 +1,107 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent; + +/** + * An object that executes submitted {@link Runnable} tasks. This + * interface provides a way of decoupling task submission from the + * mechanics of how each task will be run, including details of thread + * use, scheduling, etc. An <tt>Executor</tt> is normally used + * instead of explicitly creating threads. For example, rather than + * invoking <tt>new Thread(new(RunnableTask())).start()</tt> for each + * of a set of tasks, you might use: + * + * <pre> + * Executor executor = <em>anExecutor</em>; + * executor.execute(new RunnableTask1()); + * executor.execute(new RunnableTask2()); + * ... + * </pre> + * + * However, the <tt>Executor</tt> interface does not strictly + * require that execution be asynchronous. In the simplest case, an + * executor can run the submitted task immediately in the caller's + * thread: + * + * <pre> + * class DirectExecutor implements Executor { + * public void execute(Runnable r) { + * r.run(); + * } + * }</pre> + * + * More typically, tasks are executed in some thread other + * than the caller's thread. The executor below spawns a new thread + * for each task. + * + * <pre> + * class ThreadPerTaskExecutor implements Executor { + * public void execute(Runnable r) { + * new Thread(r).start(); + * } + * }</pre> + * + * Many <tt>Executor</tt> implementations impose some sort of + * limitation on how and when tasks are scheduled. The executor below + * serializes the submission of tasks to a second executor, + * illustrating a composite executor. + * + * <pre> + * class SerialExecutor implements Executor { + * final Queue<Runnable> tasks = new LinkedBlockingQueue<Runnable>(); + * final Executor executor; + * Runnable active; + * + * SerialExecutor(Executor executor) { + * this.executor = executor; + * } + * + * public synchronized void execute(final Runnable r) { + * tasks.offer(new Runnable() { + * public void run() { + * try { + * r.run(); + * } finally { + * scheduleNext(); + * } + * } + * }); + * if (active == null) { + * scheduleNext(); + * } + * } + * + * protected synchronized void scheduleNext() { + * if ((active = tasks.poll()) != null) { + * executor.execute(active); + * } + * } + * }</pre> + * + * The <tt>Executor</tt> implementations provided in this package + * implement {@link ExecutorService}, which is a more extensive + * interface. The {@link ThreadPoolExecutor} class provides an + * extensible thread pool implementation. The {@link Executors} class + * provides convenient factory methods for these Executors. + * + * @since 1.5 + * @author Doug Lea + */ +public interface Executor { + + /** + * Executes the given command at some time in the future. The command + * may execute in a new thread, in a pooled thread, or in the calling + * thread, at the discretion of the <tt>Executor</tt> implementation. + * + * @param command the runnable task + * @throws RejectedExecutionException if this task cannot be + * accepted for execution. + * @throws NullPointerException if command is null + */ + void execute(Runnable command); +} diff --git a/concurrent/src/main/java/java/util/concurrent/ExecutorCompletionService.java b/concurrent/src/main/java/java/util/concurrent/ExecutorCompletionService.java new file mode 100644 index 0000000..4f9c9d9 --- /dev/null +++ b/concurrent/src/main/java/java/util/concurrent/ExecutorCompletionService.java @@ -0,0 +1,148 @@ +/* + * 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/licenses/publicdomain + */ + +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 <tt>take</tt>. + * The class is lightweight enough to be suitable for transient use + * when processing groups of tasks. + * + * <p> + * + * <b>Usage Examples.</b> + * + * Suppose you have a set of solvers for a certain problem, each + * returning a value of some type <tt>Result</tt>, and would like to + * run them concurrently, processing the results of each of them that + * return a non-null value, in some method <tt>use(Result r)</tt>. You + * could write this as: + * + * <pre> + * void solve(Executor e, Collection<Callable<Result>> solvers) + * throws InterruptedException, ExecutionException { + * CompletionService<Result> ecs = new ExecutorCompletionService<Result>(e); + * for (Callable<Result> 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); + * } + * } + * </pre> + * + * 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: + * + * <pre> + * void solve(Executor e, Collection<Callable<Result>> solvers) + * throws InterruptedException { + * CompletionService<Result> ecs = new ExecutorCompletionService<Result>(e); + * int n = solvers.size(); + * List<Future<Result>> futures = new ArrayList<Future<Result>>(n); + * Result result = null; + * try { + * for (Callable<Result> 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<Result> f : futures) + * f.cancel(true); + * } + * + * if (result != null) + * use(result); + * } + * </pre> + */ +public class ExecutorCompletionService<V> implements CompletionService<V> { + private final Executor executor; + private final BlockingQueue<Future<V>> completionQueue; + + /** + * FutureTask extension to enqueue upon completion + */ + private class QueueingFuture extends FutureTask<V> { + QueueingFuture(Callable<V> c) { super(c); } + QueueingFuture(Runnable t, V r) { super(t, r); } + protected void done() { completionQueue.add(this); } + } + + /** + * 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 <tt>null</tt> + */ + public ExecutorCompletionService(Executor executor) { + if (executor == null) + throw new NullPointerException(); + this.executor = executor; + this.completionQueue = new LinkedBlockingQueue<Future<V>>(); + } + + /** + * 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 + * @throws NullPointerException if executor or completionQueue are <tt>null</tt> + */ + public ExecutorCompletionService(Executor executor, + BlockingQueue<Future<V>> completionQueue) { + if (executor == null || completionQueue == null) + throw new NullPointerException(); + this.executor = executor; + this.completionQueue = completionQueue; + } + + public Future<V> submit(Callable<V> task) { + if (task == null) throw new NullPointerException(); + QueueingFuture f = new QueueingFuture(task); + executor.execute(f); + return f; + } + + public Future<V> submit(Runnable task, V result) { + if (task == null) throw new NullPointerException(); + QueueingFuture f = new QueueingFuture(task, result); + executor.execute(f); + return f; + } + + public Future<V> take() throws InterruptedException { + return completionQueue.take(); + } + + public Future<V> poll() { + return completionQueue.poll(); + } + + public Future<V> poll(long timeout, TimeUnit unit) throws InterruptedException { + return completionQueue.poll(timeout, unit); + } + +} + + diff --git a/concurrent/src/main/java/java/util/concurrent/ExecutorService.java b/concurrent/src/main/java/java/util/concurrent/ExecutorService.java new file mode 100644 index 0000000..f0a6346 --- /dev/null +++ b/concurrent/src/main/java/java/util/concurrent/ExecutorService.java @@ -0,0 +1,285 @@ +/* + * 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/licenses/publicdomain + */ + +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. + * + * <p> + * An <tt>ExecutorService</tt> can be shut down, which will cause it + * to stop accepting new tasks. After being shut down, the executor + * will eventually terminate, at which point no tasks are actively + * executing, no tasks are awaiting execution, and no new tasks can be + * submitted. + * + * <p> Method <tt>submit</tt> 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 <tt>invokeAny</tt> and <tt>invokeAll</tt> 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.) + * + * <p>The {@link Executors} class provides factory methods for the + * executor services provided in this package. + * + * <h3>Usage Example</h3> + * + * 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: + * + * <pre> + * class NetworkService { + * 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 serve() { + * 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 + * } + * } + * </pre> + * @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. + * @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}<tt>("modifyThread")</tt>, + * or the security manager's <tt>checkAccess</tt> 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. + * + * <p>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 if any + * tasks mask or fail to respond to interrupts, they 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}<tt>("modifyThread")</tt>, + * or the security manager's <tt>checkAccess</tt> method denies access. + */ + List<Runnable> shutdownNow(); + + /** + * Returns <tt>true</tt> if this executor has been shut down. + * + * @return <tt>true</tt> if this executor has been shut down + */ + boolean isShutdown(); + + /** + * Returns <tt>true</tt> if all tasks have completed following shut down. + * Note that <tt>isTerminated</tt> is never <tt>true</tt> unless + * either <tt>shutdown</tt> or <tt>shutdownNow</tt> was called first. + * + * @return <tt>true</tt> 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 <tt>true</tt> if this executor terminated and <tt>false</tt> + * 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. + * + * <p> + * If you would like to immediately block waiting + * for a task, you can use constructions of the form + * <tt>result = exec.submit(aCallable).get();</tt> + * + * <p> 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 task cannot be scheduled + * for execution + * @throws NullPointerException if task null + */ + <T> Future<T> submit(Callable<T> task); + + /** + * Submits a Runnable task for execution and returns a Future + * representing that task that will upon completion return + * the given result. + * + * @param task the task to submit + * @param result the result to return + * @return a Future representing pending completion of the task, + * and whose <tt>get()</tt> method will return the given result + * upon completion. + * @throws RejectedExecutionException if task cannot be scheduled + * for execution + * @throws NullPointerException if task null + */ + <T> Future<T> submit(Runnable task, T result); + + /** + * Submits a Runnable task for execution and returns a Future + * representing that task. + * + * @param task the task to submit + * @return a Future representing pending completion of the task, + * and whose <tt>get()</tt> method will return <tt>null</tt> + * upon completion. + * @throws RejectedExecutionException if task cannot be scheduled + * for execution + * @throws NullPointerException if task null + */ + Future<?> submit(Runnable task); + + /** + * Executes the given tasks, returning their results + * when all complete. + * Note that a <em>completed</em> 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 <tt>null</tt> + * @throws RejectedExecutionException if any task cannot be scheduled + * for execution + */ + <T> List<Future<T>> invokeAll(Collection<Callable<T>> tasks) + throws InterruptedException; + + /** + * Executes the given tasks, returning their results + * when all complete or the timeout expires, whichever happens first. + * Upon return, tasks that have not completed are cancelled. + * Note that a <em>completed</em> 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 thiese 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 <tt>null</tt> + * @throws RejectedExecutionException if any task cannot be scheduled + * for execution + */ + <T> List<Future<T>> invokeAll(Collection<Callable<T>> 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 of its elements + * are <tt>null</tt> + * @throws IllegalArgumentException if tasks empty + * @throws ExecutionException if no task successfully completes + * @throws RejectedExecutionException if tasks cannot be scheduled + * for execution + */ + <T> T invokeAny(Collection<Callable<T>> 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, any of its elements, or + * unit are <tt>null</tt> + * @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> T invokeAny(Collection<Callable<T>> tasks, + long timeout, TimeUnit unit) + throws InterruptedException, ExecutionException, TimeoutException; + +} diff --git a/concurrent/src/main/java/java/util/concurrent/Executors.java b/concurrent/src/main/java/java/util/concurrent/Executors.java new file mode 100644 index 0000000..23f1b75 --- /dev/null +++ b/concurrent/src/main/java/java/util/concurrent/Executors.java @@ -0,0 +1,659 @@ +/* + * 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/licenses/publicdomain + */ + +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.AccessControlException; + +/** + * 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: + * + * <ul> + * <li> Methods that create and return an {@link ExecutorService} + * set up with commonly useful configuration settings. + * <li> Methods that create and return a {@link ScheduledExecutorService} + * set up with commonly useful configuration settings. + * <li> Methods that create and return a "wrapped" ExecutorService, that + * disables reconfiguration by making implementation-specific methods + * inaccessible. + * <li> Methods that create and return a {@link ThreadFactory} + * that sets newly created threads to a known state. + * <li> Methods that create and return a {@link Callable} + * out of other closure-like forms, so they can be used + * in execution methods requiring <tt>Callable</tt>. + * </ul> + * + * @since 1.5 + * @author Doug Lea + */ +public class Executors { + + /** + * Creates a thread pool that reuses a fixed set of threads + * operating off a shared unbounded queue. 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. + * + * @param nThreads the number of threads in the pool + * @return the newly created thread pool + */ + public static ExecutorService newFixedThreadPool(int nThreads) { + return new ThreadPoolExecutor(nThreads, nThreads, + 0L, TimeUnit.MILLISECONDS, + new LinkedBlockingQueue<Runnable>()); + } + + /** + * Creates a thread pool that reuses a fixed set of threads + * operating off a shared unbounded queue, using the provided + * ThreadFactory to create new threads when needed. + * + * @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 + */ + public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) { + return new ThreadPoolExecutor(nThreads, nThreads, + 0L, TimeUnit.MILLISECONDS, + new LinkedBlockingQueue<Runnable>(), + 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 + * <tt>newFixedThreadPool(1)</tt> 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 DelegatedExecutorService + (new ThreadPoolExecutor(1, 1, + 0L, TimeUnit.MILLISECONDS, + new LinkedBlockingQueue<Runnable>())); + } + + /** + * 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 <tt>newFixedThreadPool(1, threadFactory)</tt> 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 + */ + public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) { + return new DelegatedExecutorService + (new ThreadPoolExecutor(1, 1, + 0L, TimeUnit.MILLISECONDS, + new LinkedBlockingQueue<Runnable>(), + 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 <tt>execute</tt> 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<Runnable>()); + } + + /** + * 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 + */ + public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) { + return new ThreadPoolExecutor(0, Integer.MAX_VALUE, + 60L, TimeUnit.SECONDS, + new SynchronousQueue<Runnable>(), + 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 + * <tt>newScheduledThreadPool(1)</tt> 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 <tt>newScheduledThreadPool(1, threadFactory)</tt> + * 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 + */ + 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 + */ + 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 + */ + 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 <tt>ExecutorService</tt> 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 <tt>ScheduledExecutorService</tt> 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 <tt>defaultThreadFactory</tt> method. Each new + * thread is created as a non-daemon thread with priority + * <tt>Thread.NORM_PRIORITY</tt>. New threads have names + * accessible via {@link Thread#getName} of + * <em>pool-N-thread-M</em>, where <em>N</em> is the sequence + * number of this factory, and <em>M</em> 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 + * <tt>privilegedThreadFactory</tt> method. A new + * <tt>privilegedThreadFactory</tt> 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. + * + * <p> 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 + * <tt>Callable</tt> to an otherwise resultless action. + * @param task the task to run + * @param result the result to return + * @throws NullPointerException if task null + * @return a callable object + */ + public static <T> Callable<T> callable(Runnable task, T result) { + if (task == null) + throw new NullPointerException(); + return new RunnableAdapter<T>(task, result); + } + + /** + * Returns a {@link Callable} object that, when + * called, runs the given task and returns <tt>null</tt>. + * @param task the task to run + * @return a callable object + * @throws NullPointerException if task null + */ + public static Callable<Object> callable(Runnable task) { + if (task == null) + throw new NullPointerException(); + return new RunnableAdapter<Object>(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<Object> callable(PrivilegedAction action) { + if (action == null) + throw new NullPointerException(); + return new PrivilegedActionAdapter(action); + } + + /** + * 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<Object> callable(PrivilegedExceptionAction action) { + if (action == null) + throw new NullPointerException(); + return new PrivilegedExceptionActionAdapter(action); + } + + /** + * Returns a {@link Callable} object that will, when + * called, execute the given <tt>callable</tt> 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 <T> Callable<T> privilegedCallable(Callable<T> callable) { + if (callable == null) + throw new NullPointerException(); + return new PrivilegedCallable(callable); + } + + /** + * Returns a {@link Callable} object that will, when + * called, execute the given <tt>callable</tt> 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 <T> Callable<T> privilegedCallableUsingCurrentClassLoader(Callable<T> 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<T> implements Callable<T> { + 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 given privileged action and returns its result + */ + static final class PrivilegedActionAdapter implements Callable<Object> { + PrivilegedActionAdapter(PrivilegedAction action) { + this.action = action; + } + public Object call () { + return action.run(); + } + private final PrivilegedAction action; + } + + /** + * A callable that runs given privileged exception action and returns its result + */ + static final class PrivilegedExceptionActionAdapter implements Callable<Object> { + PrivilegedExceptionActionAdapter(PrivilegedExceptionAction action) { + this.action = action; + } + public Object call () throws Exception { + return action.run(); + } + private final PrivilegedExceptionAction action; + } + + + /** + * A callable that runs under established access control settings + */ + static final class PrivilegedCallable<T> implements Callable<T> { + private final AccessControlContext acc; + private final Callable<T> task; + private T result; + private Exception exception; + PrivilegedCallable(Callable<T> task) { + this.task = task; + this.acc = AccessController.getContext(); + } + + public T call() throws Exception { + AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + try { + result = task.call(); + } catch(Exception ex) { + exception = ex; + } + return null; + } + }, acc); + if (exception != null) + throw exception; + else + return result; + } + } + + /** + * A callable that runs under established access control settings and + * current ClassLoader + */ + static final class PrivilegedCallableUsingCurrentClassLoader<T> implements Callable<T> { + private final ClassLoader ccl; + private final AccessControlContext acc; + private final Callable<T> task; + private T result; + private Exception exception; + PrivilegedCallableUsingCurrentClassLoader(Callable<T> task) { + this.task = task; + this.ccl = Thread.currentThread().getContextClassLoader(); + this.acc = AccessController.getContext(); + acc.checkPermission(new RuntimePermission("getContextClassLoader")); + acc.checkPermission(new RuntimePermission("setContextClassLoader")); + } + + public T call() throws Exception { + AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + ClassLoader savedcl = null; + Thread t = Thread.currentThread(); + try { + ClassLoader cl = t.getContextClassLoader(); + if (ccl != cl) { + t.setContextClassLoader(ccl); + savedcl = cl; + } + result = task.call(); + } catch(Exception ex) { + exception = ex; + } finally { + if (savedcl != null) + t.setContextClassLoader(savedcl); + } + return null; + } + }, acc); + if (exception != null) + throw exception; + else + return result; + } + } + + /** + * The default thread factory + */ + static class DefaultThreadFactory implements ThreadFactory { + static final AtomicInteger poolNumber = new AtomicInteger(1); + final ThreadGroup group; + final AtomicInteger threadNumber = new AtomicInteger(1); + 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 and class loader + */ + static class PrivilegedThreadFactory extends DefaultThreadFactory { + private final ClassLoader ccl; + private final AccessControlContext acc; + + PrivilegedThreadFactory() { + super(); + this.ccl = Thread.currentThread().getContextClassLoader(); + this.acc = AccessController.getContext(); + acc.checkPermission(new RuntimePermission("setContextClassLoader")); + } + + public Thread newThread(final Runnable r) { + return super.newThread(new Runnable() { + public void run() { + AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + Thread.currentThread().setContextClassLoader(ccl); + r.run(); + return null; + } + }, acc); + } + }); + } + + } + + /** + * A wrapper class that exposes only the ExecutorService methods + * of an 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<Runnable> 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 <T> Future<T> submit(Callable<T> task) { + return e.submit(task); + } + public <T> Future<T> submit(Runnable task, T result) { + return e.submit(task, result); + } + public <T> List<Future<T>> invokeAll(Collection<Callable<T>> tasks) + throws InterruptedException { + return e.invokeAll(tasks); + } + public <T> List<Future<T>> invokeAll(Collection<Callable<T>> tasks, + long timeout, TimeUnit unit) + throws InterruptedException { + return e.invokeAll(tasks, timeout, unit); + } + public <T> T invokeAny(Collection<Callable<T>> tasks) + throws InterruptedException, ExecutionException { + return e.invokeAny(tasks); + } + public <T> T invokeAny(Collection<Callable<T>> tasks, + long timeout, TimeUnit unit) + throws InterruptedException, ExecutionException, TimeoutException { + return e.invokeAny(tasks, timeout, unit); + } + } + + /** + * A wrapper class that exposes only the ExecutorService and + * ScheduleExecutor 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 <V> ScheduledFuture<V> schedule(Callable<V> 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 --git a/concurrent/src/main/java/java/util/concurrent/Future.java b/concurrent/src/main/java/java/util/concurrent/Future.java new file mode 100644 index 0000000..38fa8c6 --- /dev/null +++ b/concurrent/src/main/java/java/util/concurrent/Future.java @@ -0,0 +1,133 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent; + +/** + * A <tt>Future</tt> 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 + * <tt>get</tt> when the computation has completed, blocking if + * necessary until it is ready. Cancellation is performed by the + * <tt>cancel</tt> 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 <tt>Future</tt> for the sake + * of cancellability but not provide a usable result, you can + * declare types of the form <tt>Future<?></tt> and + * return <tt>null</tt> as a result of the underlying task. + * + * <p> + * <b>Sample Usage</b> (Note that the following classes are all + * made-up.) <p> + * <pre> + * interface ArchiveSearcher { String search(String target); } + * class App { + * ExecutorService executor = ... + * ArchiveSearcher searcher = ... + * void showSearch(final String target) throws InterruptedException { + * Future<String> future = executor.submit(new Callable<String>() { + * public String call() { return searcher.search(target); } + * }); + * displayOtherThings(); // do other things while searching + * try { + * displayText(future.get()); // use future + * } catch (ExecutionException ex) { cleanup(); return; } + * } + * } + * </pre> + * + * The {@link FutureTask} class is an implementation of <tt>Future</tt> that + * implements <tt>Runnable</tt>, and so may be executed by an <tt>Executor</tt>. + * For example, the above construction with <tt>submit</tt> could be replaced by: + * <pre> + * FutureTask<String> future = + * new FutureTask<String>(new Callable<String>() { + * public String call() { + * return searcher.search(target); + * }}); + * executor.execute(future); + * </pre> + * @see FutureTask + * @see Executor + * @since 1.5 + * @author Doug Lea + * @param <V> The result type returned by this Future's <tt>get</tt> method + */ +public interface Future<V> { + + /** + * Attempts to cancel execution of this task. This attempt will + * fail if the task has already completed, already been cancelled, + * or could not be cancelled for some other reason. If successful, + * and this task has not started when <tt>cancel</tt> is called, + * this task should never run. If the task has already started, + * then the <tt>mayInterruptIfRunning</tt> parameter determines + * whether the thread executing this task should be interrupted in + * an attempt to stop the task. + * + * @param mayInterruptIfRunning <tt>true</tt> if the thread executing this + * task should be interrupted; otherwise, in-progress tasks are allowed + * to complete + * @return <tt>false</tt> if the task could not be cancelled, + * typically because it has already completed normally; + * <tt>true</tt> otherwise + */ + boolean cancel(boolean mayInterruptIfRunning); + + /** + * Returns <tt>true</tt> if this task was cancelled before it completed + * normally. + * + * @return <tt>true</tt> if task was cancelled before it completed + */ + boolean isCancelled(); + + /** + * Returns <tt>true</tt> if this task completed. + * + * Completion may be due to normal termination, an exception, or + * cancellation -- in all of these cases, this method will return + * <tt>true</tt>. + * + * @return <tt>true</tt> 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 --git a/concurrent/src/main/java/java/util/concurrent/FutureTask.java b/concurrent/src/main/java/java/util/concurrent/FutureTask.java new file mode 100644 index 0000000..87db1cd --- /dev/null +++ b/concurrent/src/main/java/java/util/concurrent/FutureTask.java @@ -0,0 +1,276 @@ +/* + * 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/licenses/publicdomain + */ + +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 <tt>get</tt> + * method will block if the computation has not yet completed. Once + * the computation has completed, the computation cannot be restarted + * or cancelled. + * + * <p>A <tt>FutureTask</tt> can be used to wrap a {@link Callable} or + * {@link java.lang.Runnable} object. Because <tt>FutureTask</tt> + * implements <tt>Runnable</tt>, a <tt>FutureTask</tt> can be + * submitted to an {@link Executor} for execution. + * + * <p>In addition to serving as a standalone class, this class provides + * <tt>protected</tt> functionality that may be useful when creating + * customized task classes. + * + * @since 1.5 + * @author Doug Lea + * @param <V> The result type returned by this FutureTask's <tt>get</tt> method + */ +public class FutureTask<V> implements Future<V>, Runnable { + /** Synchronization control for FutureTask */ + private final Sync sync; + + /** + * Creates a <tt>FutureTask</tt> that will upon running, execute the + * given <tt>Callable</tt>. + * + * @param callable the callable task + * @throws NullPointerException if callable is null + */ + public FutureTask(Callable<V> callable) { + if (callable == null) + throw new NullPointerException(); + sync = new Sync(callable); + } + + /** + * Creates a <tt>FutureTask</tt> that will upon running, execute the + * given <tt>Runnable</tt>, and arrange that <tt>get</tt> 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: + * <tt>Future<?> f = new FutureTask<Object>(runnable, null)</tt> + * @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); + } + + public V get() throws InterruptedException, ExecutionException { + return sync.innerGet(); + } + + 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 + * <tt>isDone</tt> (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. + * @param v the value + */ + protected void set(V v) { + sync.innerSet(v); + } + + /** + * Causes this future to report an <tt>ExecutionException</tt> + * with the given throwable as its cause, unless this Future has + * already been set or has been cancelled. + * @param t the cause of failure. + */ + protected void setException(Throwable t) { + sync.innerSetException(t); + } + + /** + * Sets this Future to the result of 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 + * <tt>done</tt> 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 { + /** 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<V> 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 serve as write barrier on completion. + */ + private volatile Thread runner; + + Sync(Callable<V> 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) { + int s = getState(); + if (ranOrCancelled(s) || !compareAndSetState(s, RAN)) + return; + result = v; + releaseShared(0); + done(); + } + + void innerSetException(Throwable t) { + int s = getState(); + if (ranOrCancelled(s) || !compareAndSetState(s, RAN)) + return; + exception = t; + result = null; + releaseShared(0); + done(); + } + + boolean innerCancel(boolean mayInterruptIfRunning) { + int s = getState(); + if (ranOrCancelled(s) || !compareAndSetState(s, CANCELLED)) + return false; + if (mayInterruptIfRunning) { + Thread r = runner; + if (r != null) + r.interrupt(); + } + releaseShared(0); + done(); + return true; + } + + void innerRun() { + if (!compareAndSetState(0, RUNNING)) + return; + try { + runner = Thread.currentThread(); + innerSet(callable.call()); + } catch(Throwable ex) { + innerSetException(ex); + } + } + + boolean innerRunAndReset() { + if (!compareAndSetState(0, RUNNING)) + return false; + try { + runner = Thread.currentThread(); + callable.call(); // don't set result + runner = null; + return compareAndSetState(RUNNING, 0); + } catch(Throwable ex) { + innerSetException(ex); + return false; + } + } + } +} diff --git a/concurrent/src/main/java/java/util/concurrent/LinkedBlockingQueue.java b/concurrent/src/main/java/java/util/concurrent/LinkedBlockingQueue.java new file mode 100644 index 0000000..f2ec05b --- /dev/null +++ b/concurrent/src/main/java/java/util/concurrent/LinkedBlockingQueue.java @@ -0,0 +1,720 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent; +import java.util.concurrent.atomic.*; +import java.util.concurrent.locks.*; +import java.util.*; + +// BEGIN android-note +// removed link to collections framework docs +// END android-note + +/** + * An optionally-bounded {@linkplain BlockingQueue blocking queue} based on + * linked nodes. + * This queue orders elements FIFO (first-in-first-out). + * The <em>head</em> of the queue is that element that has been on the + * queue the longest time. + * The <em>tail</em> 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. + * + * <p> 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. + * + * <p>This class implements all of the <em>optional</em> methods + * of the {@link Collection} and {@link Iterator} interfaces. + * + * @since 1.5 + * @author Doug Lea + * @param <E> the type of elements held in this collection + * + **/ +public class LinkedBlockingQueue<E> extends AbstractQueue<E> + implements BlockingQueue<E>, 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. + */ + + /** + * Linked list node class + */ + static class Node<E> { + /** The item, volatile to ensure barrier separating write and read */ + volatile E item; + Node<E> 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 */ + private transient Node<E> head; + + /** Tail of linked list */ + private transient Node<E> 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(); + + /** + * Signal 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(); + } + } + + /** + * Signal a waiting put. Called only from take/poll. + */ + private void signalNotFull() { + final ReentrantLock putLock = this.putLock; + putLock.lock(); + try { + notFull.signal(); + } finally { + putLock.unlock(); + } + } + + /** + * Create a node and link it at end of queue + * @param x the item + */ + private void insert(E x) { + last = last.next = new Node<E>(x); + } + + /** + * Remove a node from head of queue, + * @return the node + */ + private E extract() { + Node<E> first = head.next; + head = first; + E x = first.item; + first.item = null; + return x; + } + + /** + * Lock to prevent both puts and takes. + */ + private void fullyLock() { + putLock.lock(); + takeLock.lock(); + } + + /** + * Unlock to allow both puts and takes. + */ + private void fullyUnlock() { + takeLock.unlock(); + putLock.unlock(); + } + + + /** + * Creates a <tt>LinkedBlockingQueue</tt> with a capacity of + * {@link Integer#MAX_VALUE}. + */ + public LinkedBlockingQueue() { + this(Integer.MAX_VALUE); + } + + /** + * Creates a <tt>LinkedBlockingQueue</tt> with the given (fixed) capacity. + * + * @param capacity the capacity of this queue. + * @throws IllegalArgumentException if <tt>capacity</tt> is not greater + * than zero. + */ + public LinkedBlockingQueue(int capacity) { + if (capacity <= 0) throw new IllegalArgumentException(); + this.capacity = capacity; + last = head = new Node<E>(null); + } + + /** + * Creates a <tt>LinkedBlockingQueue</tt> 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 <tt>c</tt> or any element within it + * is <tt>null</tt> + */ + public LinkedBlockingQueue(Collection<? extends E> c) { + this(Integer.MAX_VALUE); + for (Iterator<? extends E> it = c.iterator(); it.hasNext();) + add(it.next()); + } + + + // 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 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 <tt>size</tt> of this queue. + * <p>Note that you <em>cannot</em> always tell if + * an attempt to <tt>add</tt> an element will succeed by + * inspecting <tt>remainingCapacity</tt> because it may be the + * case that a waiting consumer is ready to <tt>take</tt> an + * element out of an otherwise full queue. + * + * @return the remaining capacity + */ + public int remainingCapacity() { + return capacity - count.get(); + } + + /** + * Adds the specified element to the tail of this queue, waiting if + * necessary for space to become available. + * @param o the element to add + * @throws InterruptedException if interrupted while waiting. + * @throws NullPointerException if the specified element is <tt>null</tt>. + */ + public void put(E o) throws InterruptedException { + if (o == 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; + 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. + */ + try { + while (count.get() == capacity) + notFull.await(); + } catch (InterruptedException ie) { + notFull.signal(); // propagate to a non-interrupted thread + throw ie; + } + insert(o); + 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. + * @param o the element to add + * @param timeout how long to wait before giving up, in units of + * <tt>unit</tt> + * @param unit a <tt>TimeUnit</tt> determining how to interpret the + * <tt>timeout</tt> parameter + * @return <tt>true</tt> if successful, or <tt>false</tt> if + * the specified waiting time elapses before space is available. + * @throws InterruptedException if interrupted while waiting. + * @throws NullPointerException if the specified element is <tt>null</tt>. + */ + public boolean offer(E o, long timeout, TimeUnit unit) + throws InterruptedException { + + if (o == 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 { + for (;;) { + if (count.get() < capacity) { + insert(o); + c = count.getAndIncrement(); + if (c + 1 < capacity) + notFull.signal(); + break; + } + if (nanos <= 0) + return false; + try { + nanos = notFull.awaitNanos(nanos); + } catch (InterruptedException ie) { + notFull.signal(); // propagate to a non-interrupted thread + throw ie; + } + } + } finally { + putLock.unlock(); + } + if (c == 0) + signalNotEmpty(); + return true; + } + + /** + * Inserts the specified element at the tail of this queue if possible, + * returning immediately if this queue is full. + * + * @param o the element to add. + * @return <tt>true</tt> if it was possible to add the element to + * this queue, else <tt>false</tt> + * @throws NullPointerException if the specified element is <tt>null</tt> + */ + public boolean offer(E o) { + if (o == null) throw new NullPointerException(); + final AtomicInteger count = this.count; + if (count.get() == capacity) + return false; + int c = -1; + final ReentrantLock putLock = this.putLock; + putLock.lock(); + try { + if (count.get() < capacity) { + insert(o); + 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 { + try { + while (count.get() == 0) + notEmpty.await(); + } catch (InterruptedException ie) { + notEmpty.signal(); // propagate to a non-interrupted thread + throw ie; + } + + x = extract(); + 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 { + for (;;) { + if (count.get() > 0) { + x = extract(); + c = count.getAndDecrement(); + if (c > 1) + notEmpty.signal(); + break; + } + if (nanos <= 0) + return null; + try { + nanos = notEmpty.awaitNanos(nanos); + } catch (InterruptedException ie) { + notEmpty.signal(); // propagate to a non-interrupted thread + throw ie; + } + } + } 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 = extract(); + 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<E> first = head.next; + if (first == null) + return null; + else + return first.item; + } finally { + takeLock.unlock(); + } + } + + public boolean remove(Object o) { + if (o == null) return false; + boolean removed = false; + fullyLock(); + try { + Node<E> trail = head; + Node<E> p = head.next; + while (p != null) { + if (o.equals(p.item)) { + removed = true; + break; + } + trail = p; + p = p.next; + } + if (removed) { + p.item = null; + trail.next = p.next; + if (count.getAndDecrement() == capacity) + notFull.signalAll(); + } + } finally { + fullyUnlock(); + } + return removed; + } + + public Object[] toArray() { + fullyLock(); + try { + int size = count.get(); + Object[] a = new Object[size]; + int k = 0; + for (Node<E> p = head.next; p != null; p = p.next) + a[k++] = p.item; + return a; + } finally { + fullyUnlock(); + } + } + + public <T> 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; + return a; + } finally { + fullyUnlock(); + } + } + + public String toString() { + fullyLock(); + try { + return super.toString(); + } finally { + fullyUnlock(); + } + } + + public void clear() { + fullyLock(); + try { + head.next = null; + if (count.getAndSet(0) == capacity) + notFull.signalAll(); + } finally { + fullyUnlock(); + } + } + + public int drainTo(Collection<? super E> c) { + if (c == null) + throw new NullPointerException(); + if (c == this) + throw new IllegalArgumentException(); + Node first; + fullyLock(); + try { + first = head.next; + head.next = null; + if (count.getAndSet(0) == capacity) + notFull.signalAll(); + } finally { + fullyUnlock(); + } + // Transfer the elements outside of locks + int n = 0; + for (Node<E> p = first; p != null; p = p.next) { + c.add(p.item); + p.item = null; + ++n; + } + return n; + } + + public int drainTo(Collection<? super E> c, int maxElements) { + if (c == null) + throw new NullPointerException(); + if (c == this) + throw new IllegalArgumentException(); + if (maxElements <= 0) + return 0; + fullyLock(); + try { + int n = 0; + Node<E> p = head.next; + while (p != null && n < maxElements) { + c.add(p.item); + p.item = null; + p = p.next; + ++n; + } + if (n != 0) { + head.next = p; + if (count.getAndAdd(-n) == capacity) + notFull.signalAll(); + } + return n; + } finally { + fullyUnlock(); + } + } + + /** + * Returns an iterator over the elements in this queue in proper sequence. + * The returned <tt>Iterator</tt> is a "weakly consistent" iterator that + * will never throw {@link java.util.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<E> iterator() { + return new Itr(); + } + + private class Itr implements Iterator<E> { + /* + * Basic weak-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<E> current; + private Node<E> lastRet; + private E currentElement; + + Itr() { + final ReentrantLock putLock = LinkedBlockingQueue.this.putLock; + final ReentrantLock takeLock = LinkedBlockingQueue.this.takeLock; + putLock.lock(); + takeLock.lock(); + try { + current = head.next; + if (current != null) + currentElement = current.item; + } finally { + takeLock.unlock(); + putLock.unlock(); + } + } + + public boolean hasNext() { + return current != null; + } + + public E next() { + final ReentrantLock putLock = LinkedBlockingQueue.this.putLock; + final ReentrantLock takeLock = LinkedBlockingQueue.this.takeLock; + putLock.lock(); + takeLock.lock(); + try { + if (current == null) + throw new NoSuchElementException(); + E x = currentElement; + lastRet = current; + current = current.next; + if (current != null) + currentElement = current.item; + return x; + } finally { + takeLock.unlock(); + putLock.unlock(); + } + } + + public void remove() { + if (lastRet == null) + throw new IllegalStateException(); + final ReentrantLock putLock = LinkedBlockingQueue.this.putLock; + final ReentrantLock takeLock = LinkedBlockingQueue.this.takeLock; + putLock.lock(); + takeLock.lock(); + try { + Node<E> node = lastRet; + lastRet = null; + Node<E> trail = head; + Node<E> p = head.next; + while (p != null && p != node) { + trail = p; + p = p.next; + } + if (p == node) { + p.item = null; + trail.next = p.next; + int c = count.getAndDecrement(); + if (c == capacity) + notFull.signalAll(); + } + } finally { + takeLock.unlock(); + putLock.unlock(); + } + } + } + + /** + * Save the state to a stream (that is, serialize it). + * + * @serialData The capacity is emitted (int), followed by all of + * its elements (each an <tt>Object</tt>) 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<E> 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<E>(null); + + // Read in all elements and place in queue + for (;;) { + E item = (E)s.readObject(); + if (item == null) + break; + add(item); + } + } +} diff --git a/concurrent/src/main/java/java/util/concurrent/PriorityBlockingQueue.java b/concurrent/src/main/java/java/util/concurrent/PriorityBlockingQueue.java new file mode 100644 index 0000000..85c0165 --- /dev/null +++ b/concurrent/src/main/java/java/util/concurrent/PriorityBlockingQueue.java @@ -0,0 +1,455 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent; + +import java.util.concurrent.locks.*; +import java.util.*; + +// BEGIN android-note +// removed link to collections framework docs +// END android-note + +/** + * 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 <tt>OutOfMemoryError</tt>). This class does not permit + * <tt>null</tt> elements. A priority queue relying on natural + * ordering also does not permit insertion of non-comparable objects + * (doing so results in <tt>ClassCastException</tt>). + * + * <p>This class implements all of the <em>optional</em> methods + * of the {@link Collection} and {@link Iterator} interfaces. + * <p>The Iterator provided in method {@link #iterator()} is + * <em>not</em> guaranteed to traverse the elements of the + * PriorityBlockingQueue in any particular order. If you need ordered + * traversal, consider using <tt>Arrays.sort(pq.toArray())</tt>. + * + * @since 1.5 + * @author Doug Lea + * @param <E> the type of elements held in this collection + */ +public class PriorityBlockingQueue<E> extends AbstractQueue<E> + implements BlockingQueue<E>, java.io.Serializable { + private static final long serialVersionUID = 5595510919245408276L; + + private final PriorityQueue<E> q; + private final ReentrantLock lock = new ReentrantLock(true); + private final Condition notEmpty = lock.newCondition(); + + /** + * Creates a <tt>PriorityBlockingQueue</tt> with the default initial + * capacity + * (11) that orders its elements according to their natural + * ordering (using <tt>Comparable</tt>). + */ + public PriorityBlockingQueue() { + q = new PriorityQueue<E>(); + } + + /** + * Creates a <tt>PriorityBlockingQueue</tt> with the specified initial + * capacity + * that orders its elements according to their natural ordering + * (using <tt>Comparable</tt>). + * + * @param initialCapacity the initial capacity for this priority queue. + * @throws IllegalArgumentException if <tt>initialCapacity</tt> is less + * than 1 + */ + public PriorityBlockingQueue(int initialCapacity) { + q = new PriorityQueue<E>(initialCapacity, null); + } + + /** + * Creates a <tt>PriorityBlockingQueue</tt> 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 used to order this priority queue. + * If <tt>null</tt> then the order depends on the elements' natural + * ordering. + * @throws IllegalArgumentException if <tt>initialCapacity</tt> is less + * than 1 + */ + public PriorityBlockingQueue(int initialCapacity, + Comparator<? super E> comparator) { + q = new PriorityQueue<E>(initialCapacity, comparator); + } + + /** + * Creates a <tt>PriorityBlockingQueue</tt> containing the elements + * in the specified collection. The priority queue has an initial + * capacity of 110% of the size of the specified collection. If + * the specified collection is a {@link SortedSet} or a {@link + * PriorityQueue}, this priority queue will be sorted according to + * the same comparator, or according to its elements' natural + * order if the collection is sorted according to its elements' + * natural order. Otherwise, this priority queue is ordered + * according to its elements' natural order. + * + * @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 <tt>c</tt> or any element within it + * is <tt>null</tt> + */ + public PriorityBlockingQueue(Collection<? extends E> c) { + q = new PriorityQueue<E>(c); + } + + + // these first few override just to update doc comments + + /** + * Adds the specified element to this queue. + * @param o the element to add + * @return <tt>true</tt> (as per the general contract of + * <tt>Collection.add</tt>). + * + * @throws NullPointerException if the specified element is <tt>null</tt>. + * @throws ClassCastException if the specified element cannot be compared + * with elements currently in the priority queue according + * to the priority queue's ordering. + */ + public boolean add(E o) { + return super.add(o); + } + + // BEGIN android-changed + /** + * Returns the comparator used to order this collection, or <tt>null</tt> + * if this collection is sorted according to its elements natural ordering + * (using <tt>Comparable</tt>). + * + * @return the comparator used to order this collection, or <tt>null</tt> + * if this collection is sorted according to its elements natural ordering. + */ + public Comparator<? super E> comparator() { + return q.comparator(); + } + // END android-changed + + /** + * Inserts the specified element into this priority queue. + * + * @param o the element to add + * @return <tt>true</tt> + * @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 <tt>null</tt>. + */ + public boolean offer(E o) { + if (o == null) throw new NullPointerException(); + final ReentrantLock lock = this.lock; + lock.lock(); + try { + boolean ok = q.offer(o); + assert ok; + notEmpty.signal(); + return true; + } finally { + lock.unlock(); + } + } + + /** + * Adds the specified element to this priority queue. As the queue is + * unbounded this method will never block. + * @param o the element to add + * @throws ClassCastException if the 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 <tt>null</tt>. + */ + public void put(E o) { + offer(o); // never need to block + } + + /** + * Inserts the specified element into this priority queue. As the queue is + * unbounded this method will never block. + * @param o 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 <tt>true</tt> + * @throws ClassCastException if the 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 <tt>null</tt>. + */ + public boolean offer(E o, long timeout, TimeUnit unit) { + return offer(o); // never need to block + } + + public E take() throws InterruptedException { + final ReentrantLock lock = this.lock; + lock.lockInterruptibly(); + try { + try { + while (q.size() == 0) + notEmpty.await(); + } catch (InterruptedException ie) { + notEmpty.signal(); // propagate to non-interrupted thread + throw ie; + } + E x = q.poll(); + assert x != null; + return x; + } finally { + lock.unlock(); + } + } + + public E poll() { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + return q.poll(); + } 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 { + for (;;) { + E x = q.poll(); + if (x != null) + return x; + if (nanos <= 0) + return null; + try { + nanos = notEmpty.awaitNanos(nanos); + } catch (InterruptedException ie) { + notEmpty.signal(); // propagate to non-interrupted thread + throw ie; + } + } + } finally { + lock.unlock(); + } + } + + 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(); + } + } + + /** + * Always returns <tt>Integer.MAX_VALUE</tt> because + * a <tt>PriorityBlockingQueue</tt> is not capacity constrained. + * @return <tt>Integer.MAX_VALUE</tt> + */ + public int remainingCapacity() { + return Integer.MAX_VALUE; + } + + public boolean remove(Object o) { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + return q.remove(o); + } finally { + lock.unlock(); + } + } + + public boolean contains(Object o) { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + return q.contains(o); + } finally { + lock.unlock(); + } + } + + public Object[] toArray() { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + return q.toArray(); + } finally { + lock.unlock(); + } + } + + public String toString() { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + return q.toString(); + } finally { + lock.unlock(); + } + } + + public int drainTo(Collection<? super E> 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 = q.poll()) != null) { + c.add(e); + ++n; + } + return n; + } finally { + lock.unlock(); + } + } + + public int drainTo(Collection<? super E> 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 = q.poll()) != null) { + c.add(e); + ++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. + */ + public void clear() { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + q.clear(); + } finally { + lock.unlock(); + } + } + + public <T> T[] toArray(T[] a) { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + return q.toArray(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 thread-safe "fast-fail" iterator + * that will throw {@link + * java.util.ConcurrentModificationException} upon detected + * interference. + * + * @return an iterator over the elements in this queue. + */ + public Iterator<E> iterator() { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + return new Itr(q.iterator()); + } finally { + lock.unlock(); + } + } + + private class Itr<E> implements Iterator<E> { + private final Iterator<E> iter; + Itr(Iterator<E> i) { + iter = i; + } + + public boolean hasNext() { + /* + * No sync -- we rely on underlying hasNext to be + * stateless, in which case we can return true by mistake + * only when next() will subsequently throw + * ConcurrentModificationException. + */ + return iter.hasNext(); + } + + public E next() { + ReentrantLock lock = PriorityBlockingQueue.this.lock; + lock.lock(); + try { + return iter.next(); + } finally { + lock.unlock(); + } + } + + public void remove() { + ReentrantLock lock = PriorityBlockingQueue.this.lock; + lock.lock(); + try { + iter.remove(); + } finally { + lock.unlock(); + } + } + } + + /** + * Save the state to a stream (that is, serialize it). This + * merely wraps default serialization within lock. The + * serialization strategy for items is left to underlying + * Queue. Note that locking is not needed on deserialization, so + * readObject is not defined, just relying on default. + */ + private void writeObject(java.io.ObjectOutputStream s) + throws java.io.IOException { + lock.lock(); + try { + s.defaultWriteObject(); + } finally { + lock.unlock(); + } + } + +} diff --git a/concurrent/src/main/java/java/util/concurrent/RejectedExecutionException.java b/concurrent/src/main/java/java/util/concurrent/RejectedExecutionException.java new file mode 100644 index 0000000..199b9de --- /dev/null +++ b/concurrent/src/main/java/java/util/concurrent/RejectedExecutionException.java @@ -0,0 +1,62 @@ +/* + * 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/licenses/publicdomain + */ + +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 <tt>RejectedExecutionException</tt> 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 <tt>RejectedExecutionException</tt> 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 <tt>RejectedExecutionException</tt> 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 <tt>RejectedExecutionException</tt> with the + * specified cause. The detail message is set to: <pre> (cause == + * null ? null : cause.toString())</pre> (which typically contains + * the class and detail message of <tt>cause</tt>). + * + * @param cause the cause (which is saved for later retrieval by the + * {@link #getCause()} method) + */ + public RejectedExecutionException(Throwable cause) { + super(cause); + } +} diff --git a/concurrent/src/main/java/java/util/concurrent/RejectedExecutionHandler.java b/concurrent/src/main/java/java/util/concurrent/RejectedExecutionHandler.java new file mode 100644 index 0000000..4b4bbea --- /dev/null +++ b/concurrent/src/main/java/java/util/concurrent/RejectedExecutionHandler.java @@ -0,0 +1,33 @@ +/* + * 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/licenses/publicdomain + */ + +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 + * <tt>execute</tt> 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 other alternatives, the method may throw an + * unchecked {@link RejectedExecutionException}, which will be + * propagated to the caller of <tt>execute</tt>. + * + * @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 --git a/concurrent/src/main/java/java/util/concurrent/ScheduledExecutorService.java b/concurrent/src/main/java/java/util/concurrent/ScheduledExecutorService.java new file mode 100644 index 0000000..9579fef --- /dev/null +++ b/concurrent/src/main/java/java/util/concurrent/ScheduledExecutorService.java @@ -0,0 +1,145 @@ +/* + * 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/licenses/publicdomain + */ + +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. + * + * <p> The <tt>schedule</tt> methods create tasks with various delays + * and return a task object that can be used to cancel or check + * execution. The <tt>scheduleAtFixedRate</tt> and + * <tt>scheduleWithFixedDelay</tt> methods create and execute tasks + * that run periodically until cancelled. + * + * <p> Commands submitted using the {@link Executor#execute} and + * {@link ExecutorService} <tt>submit</tt> methods are scheduled with + * a requested delay of zero. Zero and negative delays (but not + * periods) are also allowed in <tt>schedule</tt> methods, and are + * treated as requests for immediate execution. + * + * <p>All <tt>schedule</tt> methods accept <em>relative</em> 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 <tt>date</tt>, you can use: <tt>schedule(task, + * date.getTime() - System.currentTimeMillis(), + * TimeUnit.MILLISECONDS)</tt>. Beware however that expiration of a + * relative delay need not coincide with the current <tt>Date</tt> 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. + * + * <h3>Usage Example</h3> + * + * Here is a class with a method that sets up a ScheduledExecutorService + * to beep every ten seconds for an hour: + * + * <pre> + * 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); + * } + * } + * </pre> + * + * @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 Future representing pending completion of the task, + * and whose <tt>get()</tt> method will return <tt>null</tt> + * upon completion. + * @throws RejectedExecutionException if 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 task cannot be scheduled + * for execution. + * @throws NullPointerException if callable is null + */ + public <V> ScheduledFuture<V> schedule(Callable<V> 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 + * <tt>initialDelay</tt> then <tt>initialDelay+period</tt>, then + * <tt>initialDelay + 2 * period</tt>, 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. + * @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 Future representing pending completion of the task, + * and whose <tt>get()</tt> method will throw an exception upon + * cancellation. + * @throws RejectedExecutionException if 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 Future representing pending completion of the task, + * and whose <tt>get()</tt> method will throw an exception upon + * cancellation. + * @throws RejectedExecutionException if 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 --git a/concurrent/src/main/java/java/util/concurrent/ScheduledFuture.java b/concurrent/src/main/java/java/util/concurrent/ScheduledFuture.java new file mode 100644 index 0000000..239d681 --- /dev/null +++ b/concurrent/src/main/java/java/util/concurrent/ScheduledFuture.java @@ -0,0 +1,19 @@ +/* + * 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/licenses/publicdomain + */ + +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 <V> The result type returned by this Future + */ +public interface ScheduledFuture<V> extends Delayed, Future<V> { +} diff --git a/concurrent/src/main/java/java/util/concurrent/ScheduledThreadPoolExecutor.java b/concurrent/src/main/java/java/util/concurrent/ScheduledThreadPoolExecutor.java new file mode 100644 index 0000000..09ec681 --- /dev/null +++ b/concurrent/src/main/java/java/util/concurrent/ScheduledThreadPoolExecutor.java @@ -0,0 +1,541 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent; +import java.util.concurrent.atomic.*; +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. + * + * <p> 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. + * + * <p>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 + * <tt>corePoolSize</tt> threads and an unbounded queue, adjustments + * to <tt>maximumPoolSize</tt> have no useful effect. + * + * @since 1.5 + * @author Doug Lea + */ +public class ScheduledThreadPoolExecutor + extends ThreadPoolExecutor + implements ScheduledExecutorService { + + /** + * 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; + + /** + * Sequence number to break scheduling ties, and in turn to + * guarantee FIFO order among tied entries. + */ + private static final AtomicLong sequencer = new AtomicLong(0); + + /** Base of nanosecond timings, to avoid wrapping */ + private static final long NANO_ORIGIN = System.nanoTime(); + + /** + * Returns nanosecond time offset by origin + */ + final long now() { + return System.nanoTime() - NANO_ORIGIN; + } + + private class ScheduledFutureTask<V> + extends FutureTask<V> implements ScheduledFuture<V> { + + /** 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; + + /** + * 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<V> callable, long ns) { + super(callable); + this.time = ns; + this.period = 0; + this.sequenceNumber = sequencer.getAndIncrement(); + } + + public long getDelay(TimeUnit unit) { + long d = unit.convert(time - now(), TimeUnit.NANOSECONDS); + return d; + } + + public int compareTo(Delayed other) { + if (other == this) // compare zero ONLY if same object + return 0; + 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; + } + + /** + * Returns true if this is a periodic (not a one-shot) action. + * @return true if periodic + */ + boolean isPeriodic() { + return period != 0; + } + + /** + * Run a periodic task + */ + private void runPeriodic() { + boolean ok = ScheduledFutureTask.super.runAndReset(); + boolean down = isShutdown(); + // Reschedule if not cancelled and not shutdown or policy allows + if (ok && (!down || + (getContinueExistingPeriodicTasksAfterShutdownPolicy() && + !isTerminating()))) { + long p = period; + if (p > 0) + time += p; + else + time = now() - p; + ScheduledThreadPoolExecutor.super.getQueue().add(this); + } + // This might have been the final executed delayed + // task. Wake up threads to check. + else if (down) + interruptIdleWorkers(); + } + + /** + * Overrides FutureTask version so as to reset/requeue if periodic. + */ + public void run() { + if (isPeriodic()) + runPeriodic(); + else + ScheduledFutureTask.super.run(); + } + } + + /** + * Specialized variant of ThreadPoolExecutor.execute for delayed tasks. + */ + private void delayedExecute(Runnable command) { + if (isShutdown()) { + reject(command); + return; + } + // Prestart a thread if necessary. We cannot prestart it + // running the task because the task (probably) shouldn't be + // run yet, so thread will just idle until delay elapses. + if (getPoolSize() < getCorePoolSize()) + prestartCoreThread(); + + super.getQueue().add(command); + } + + /** + * Cancel and clear the queue of all tasks that should not be run + * due to shutdown policy. + */ + private void cancelUnwantedTasks() { + boolean keepDelayed = getExecuteExistingDelayedTasksAfterShutdownPolicy(); + boolean keepPeriodic = getContinueExistingPeriodicTasksAfterShutdownPolicy(); + if (!keepDelayed && !keepPeriodic) + super.getQueue().clear(); + else if (keepDelayed || keepPeriodic) { + Object[] entries = super.getQueue().toArray(); + for (int i = 0; i < entries.length; ++i) { + Object e = entries[i]; + if (e instanceof ScheduledFutureTask) { + ScheduledFutureTask<?> t = (ScheduledFutureTask<?>)e; + if (t.isPeriodic()? !keepPeriodic : !keepDelayed) + t.cancel(false); + } + } + entries = null; + purge(); + } + } + + public boolean remove(Runnable task) { + if (!(task instanceof ScheduledFutureTask)) + return false; + return getQueue().remove(task); + } + + /** + * Creates a new ScheduledThreadPoolExecutor with the given core + * pool size. + * + * @param corePoolSize the number of threads to keep in the pool, + * even if they are idle. + * @throws IllegalArgumentException if corePoolSize less than or + * equal to zero + */ + public ScheduledThreadPoolExecutor(int corePoolSize) { + super(corePoolSize, Integer.MAX_VALUE, 0, TimeUnit.NANOSECONDS, + new DelayedWorkQueue()); + } + + /** + * 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. + * @param threadFactory the factory to use when the executor + * creates a new thread. + * @throws NullPointerException if 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. + * @param handler the handler to use when execution is blocked + * because the thread bounds and queue capacities are reached. + * @throws NullPointerException if 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. + * @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 NullPointerException if threadFactory or handler is null + */ + public ScheduledThreadPoolExecutor(int corePoolSize, + ThreadFactory threadFactory, + RejectedExecutionHandler handler) { + super(corePoolSize, Integer.MAX_VALUE, 0, TimeUnit.NANOSECONDS, + new DelayedWorkQueue(), threadFactory, handler); + } + + public ScheduledFuture<?> schedule(Runnable command, + long delay, + TimeUnit unit) { + if (command == null || unit == null) + throw new NullPointerException(); + long triggerTime = now() + unit.toNanos(delay); + ScheduledFutureTask<?> t = + new ScheduledFutureTask<Boolean>(command, null, triggerTime); + delayedExecute(t); + return t; + } + + public <V> ScheduledFuture<V> schedule(Callable<V> callable, + long delay, + TimeUnit unit) { + if (callable == null || unit == null) + throw new NullPointerException(); + if (delay < 0) delay = 0; + long triggerTime = now() + unit.toNanos(delay); + ScheduledFutureTask<V> t = + new ScheduledFutureTask<V>(callable, triggerTime); + delayedExecute(t); + return t; + } + + 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(); + if (initialDelay < 0) initialDelay = 0; + long triggerTime = now() + unit.toNanos(initialDelay); + ScheduledFutureTask<?> t = + new ScheduledFutureTask<Object>(command, + null, + triggerTime, + unit.toNanos(period)); + delayedExecute(t); + return t; + } + + 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(); + if (initialDelay < 0) initialDelay = 0; + long triggerTime = now() + unit.toNanos(initialDelay); + ScheduledFutureTask<?> t = + new ScheduledFutureTask<Boolean>(command, + null, + triggerTime, + unit.toNanos(-delay)); + delayedExecute(t); + return t; + } + + + /** + * Execute command with zero required delay. This has effect + * equivalent to <tt>schedule(command, 0, anyUnit)</tt>. Note + * that inspections of the queue and of the list returned by + * <tt>shutdownNow</tt> will access the zero-delayed + * {@link ScheduledFuture}, not the <tt>command</tt> itself. + * + * @param command the task to execute + * @throws RejectedExecutionException at discretion of + * <tt>RejectedExecutionHandler</tt>, if task cannot be accepted + * for execution because the executor has been shut down. + * @throws NullPointerException if command is null + */ + public void execute(Runnable command) { + if (command == null) + throw new NullPointerException(); + schedule(command, 0, TimeUnit.NANOSECONDS); + } + + // Override AbstractExecutorService methods + + public Future<?> submit(Runnable task) { + return schedule(task, 0, TimeUnit.NANOSECONDS); + } + + public <T> Future<T> submit(Runnable task, T result) { + return schedule(Executors.callable(task, result), + 0, TimeUnit.NANOSECONDS); + } + + public <T> Future<T> submit(Callable<T> task) { + return schedule(task, 0, TimeUnit.NANOSECONDS); + } + + /** + * Set policy on whether to continue executing existing periodic + * tasks even when this executor has been <tt>shutdown</tt>. In + * this case, these tasks will only terminate upon + * <tt>shutdownNow</tt>, or after setting the policy to + * <tt>false</tt> when already shutdown. This value is by default + * false. + * @param value if true, continue after shutdown, else don't. + * @see #getExecuteExistingDelayedTasksAfterShutdownPolicy + */ + public void setContinueExistingPeriodicTasksAfterShutdownPolicy(boolean value) { + continueExistingPeriodicTasksAfterShutdown = value; + if (!value && isShutdown()) + cancelUnwantedTasks(); + } + + /** + * Get the policy on whether to continue executing existing + * periodic tasks even when this executor has been + * <tt>shutdown</tt>. In this case, these tasks will only + * terminate upon <tt>shutdownNow</tt> or after setting the policy + * to <tt>false</tt> when already shutdown. This value is by + * default false. + * @return true if will continue after shutdown. + * @see #setContinueExistingPeriodicTasksAfterShutdownPolicy + */ + public boolean getContinueExistingPeriodicTasksAfterShutdownPolicy() { + return continueExistingPeriodicTasksAfterShutdown; + } + + /** + * Set policy on whether to execute existing delayed + * tasks even when this executor has been <tt>shutdown</tt>. In + * this case, these tasks will only terminate upon + * <tt>shutdownNow</tt>, or after setting the policy to + * <tt>false</tt> when already shutdown. This value is by default + * true. + * @param value if true, execute after shutdown, else don't. + * @see #getExecuteExistingDelayedTasksAfterShutdownPolicy + */ + public void setExecuteExistingDelayedTasksAfterShutdownPolicy(boolean value) { + executeExistingDelayedTasksAfterShutdown = value; + if (!value && isShutdown()) + cancelUnwantedTasks(); + } + + /** + * Get policy on whether to execute existing delayed + * tasks even when this executor has been <tt>shutdown</tt>. In + * this case, these tasks will only terminate upon + * <tt>shutdownNow</tt>, or after setting the policy to + * <tt>false</tt> when already shutdown. This value is by default + * true. + * @return true if will execute after shutdown. + * @see #setExecuteExistingDelayedTasksAfterShutdownPolicy + */ + public boolean getExecuteExistingDelayedTasksAfterShutdownPolicy() { + return executeExistingDelayedTasksAfterShutdown; + } + + + /** + * Initiates an orderly shutdown in which previously submitted + * tasks are executed, but no new tasks will be accepted. If the + * <tt>ExecuteExistingDelayedTasksAfterShutdownPolicy</tt> has + * been set <tt>false</tt>, existing delayed tasks whose delays + * have not yet elapsed are cancelled. And unless the + * <tt>ContinueExistingPeriodicTasksAfterShutdownPolicy</tt> has + * been set <tt>true</tt>, future executions of existing periodic + * tasks will be cancelled. + */ + public void shutdown() { + cancelUnwantedTasks(); + 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. + * + * <p>There are no guarantees beyond best-effort attempts to stop + * processing actively executing tasks. This implementation + * cancels tasks via {@link Thread#interrupt}, so if any tasks mask or + * fail to respond to interrupts, they 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 <tt>execute</tt>, which + * are for scheduling purposes used as the basis of a zero-delay + * <tt>ScheduledFuture</tt>. + */ + public List<Runnable> 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 <tt>execute</tt> which are for scheduling + * purposes used as the basis of a zero-delay + * <tt>ScheduledFuture</tt>. Iteration over this queue is + * <em>not</em> guaranteed to traverse tasks in the order in + * which they will execute. + * + * @return the task queue + */ + public BlockingQueue<Runnable> getQueue() { + return super.getQueue(); + } + + /** + * An annoying wrapper class to convince generics compiler to + * use a DelayQueue<ScheduledFutureTask> as a BlockingQueue<Runnable> + */ + private static class DelayedWorkQueue + extends AbstractCollection<Runnable> + implements BlockingQueue<Runnable> { + + private final DelayQueue<ScheduledFutureTask> dq = new DelayQueue<ScheduledFutureTask>(); + public Runnable poll() { return dq.poll(); } + public Runnable peek() { return dq.peek(); } + public Runnable take() throws InterruptedException { return dq.take(); } + public Runnable poll(long timeout, TimeUnit unit) throws InterruptedException { + return dq.poll(timeout, unit); + } + + public boolean add(Runnable x) { return dq.add((ScheduledFutureTask)x); } + public boolean offer(Runnable x) { return dq.offer((ScheduledFutureTask)x); } + public void put(Runnable x) { + dq.put((ScheduledFutureTask)x); + } + public boolean offer(Runnable x, long timeout, TimeUnit unit) { + return dq.offer((ScheduledFutureTask)x, timeout, unit); + } + + public Runnable remove() { return dq.remove(); } + public Runnable element() { return dq.element(); } + public void clear() { dq.clear(); } + public int drainTo(Collection<? super Runnable> c) { return dq.drainTo(c); } + public int drainTo(Collection<? super Runnable> c, int maxElements) { + return dq.drainTo(c, maxElements); + } + + public int remainingCapacity() { return dq.remainingCapacity(); } + public boolean remove(Object x) { return dq.remove(x); } + public boolean contains(Object x) { return dq.contains(x); } + public int size() { return dq.size(); } + public boolean isEmpty() { return dq.isEmpty(); } + public Object[] toArray() { return dq.toArray(); } + public <T> T[] toArray(T[] array) { return dq.toArray(array); } + public Iterator<Runnable> iterator() { + return new Iterator<Runnable>() { + private Iterator<ScheduledFutureTask> it = dq.iterator(); + public boolean hasNext() { return it.hasNext(); } + public Runnable next() { return it.next(); } + public void remove() { it.remove(); } + }; + } + } +} diff --git a/concurrent/src/main/java/java/util/concurrent/Semaphore.java b/concurrent/src/main/java/java/util/concurrent/Semaphore.java new file mode 100644 index 0000000..6eb80bc --- /dev/null +++ b/concurrent/src/main/java/java/util/concurrent/Semaphore.java @@ -0,0 +1,665 @@ +/* + * 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/licenses/publicdomain + */ + +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 <tt>Semaphore</tt> just + * keeps a count of the number available and acts accordingly. + * + * <p>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: + * <pre> + * class Pool { + * private static final 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; + * } + * + * } + * </pre> + * + * <p>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. + * + * <p>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 <em>binary + * semaphore</em>, 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. + * + * <p> The constructor for this class optionally accepts a + * <em>fairness</em> parameter. When set false, this class makes no + * guarantees about the order in which threads acquire permits. In + * particular, <em>barging</em> is permitted, that is, a thread + * invoking {@link #acquire} can be allocated a permit ahead of a + * thread that has been waiting. When fairness is set true, the + * semaphore guarantees that threads invoking any of the {@link + * #acquire() acquire} methods are allocated 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 + * <tt>acquire</tt> before another, but reach the ordering point after + * the other, and similarly upon return from the method. + * + * <p>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. + * + * <p>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. + * + * @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 { + 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 p = getState(); + if (compareAndSetState(p, p + releases)) + return true; + } + } + + final void reducePermits(int reductions) { + for (;;) { + int current = getState(); + int next = current - reductions; + if (compareAndSetState(current, next)) + return; + } + } + + final int drainPermits() { + for (;;) { + int current = getState(); + if (current == 0 || compareAndSetState(current, 0)) + return current; + } + } + } + + /** + * NonFair version + */ + final static class NonfairSync extends Sync { + NonfairSync(int permits) { + super(permits); + } + + protected int tryAcquireShared(int acquires) { + return nonfairTryAcquireShared(acquires); + } + } + + /** + * Fair version + */ + final static class FairSync extends Sync { + FairSync(int permits) { + super(permits); + } + + protected int tryAcquireShared(int acquires) { + Thread current = Thread.currentThread(); + for (;;) { + Thread first = getFirstQueuedThread(); + if (first != null && first != current) + return -1; + int available = getState(); + int remaining = available - acquires; + if (remaining < 0 || + compareAndSetState(available, remaining)) + return remaining; + } + } + } + + /** + * Creates a <tt>Semaphore</tt> 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 <tt>Semaphore</tt> 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 true if this semaphore will guarantee first-in + * first-out granting of permits under contention, else 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 {@link Thread#interrupt interrupted}. + * + * <p>Acquires a permit, if one is available and returns immediately, + * reducing the number of available permits by one. + * <p>If no permit is available then the current thread becomes + * disabled for thread scheduling purposes and lies dormant until + * one of two things happens: + * <ul> + * <li>Some other thread invokes the {@link #release} method for this + * semaphore and the current thread is next to be assigned a permit; or + * <li>Some other thread {@link Thread#interrupt interrupts} the current + * thread. + * </ul> + * + * <p>If the current thread: + * <ul> + * <li>has its interrupted status set on entry to this method; or + * <li>is {@link Thread#interrupt interrupted} while waiting + * for a permit, + * </ul> + * then {@link InterruptedException} is thrown and the current thread's + * interrupted status is cleared. + * + * @throws InterruptedException if the current thread is interrupted + * + * @see Thread#interrupt + */ + public void acquire() throws InterruptedException { + sync.acquireSharedInterruptibly(1); + } + + /** + * Acquires a permit from this semaphore, blocking until one is + * available. + * + * <p>Acquires a permit, if one is available and returns immediately, + * reducing the number of available permits by one. + * <p>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. + * + * <p>If the current thread + * is {@link 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. + * <p>Acquires a permit, if one is available and returns immediately, + * with the value <tt>true</tt>, + * reducing the number of available permits by one. + * + * <p>If no permit is available then this method will return + * immediately with the value <tt>false</tt>. + * + * <p>Even when this semaphore has been set to use a + * fair ordering policy, a call to <tt>tryAcquire()</tt> <em>will</em> + * 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 <tt>true</tt> if a permit was acquired and <tt>false</tt> + * 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 {@link Thread#interrupt interrupted}. + * <p>Acquires a permit, if one is available and returns immediately, + * with the value <tt>true</tt>, + * reducing the number of available permits by one. + * <p>If no permit is available then + * the current thread becomes disabled for thread scheduling + * purposes and lies dormant until one of three things happens: + * <ul> + * <li>Some other thread invokes the {@link #release} method for this + * semaphore and the current thread is next to be assigned a permit; or + * <li>Some other thread {@link Thread#interrupt interrupts} the current + * thread; or + * <li>The specified waiting time elapses. + * </ul> + * <p>If a permit is acquired then the value <tt>true</tt> is returned. + * <p>If the current thread: + * <ul> + * <li>has its interrupted status set on entry to this method; or + * <li>is {@link Thread#interrupt interrupted} while waiting to acquire + * a permit, + * </ul> + * then {@link InterruptedException} is thrown and the current thread's + * interrupted status is cleared. + * <p>If the specified waiting time elapses then the value <tt>false</tt> + * 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 <tt>timeout</tt> argument. + * @return <tt>true</tt> if a permit was acquired and <tt>false</tt> + * if the waiting time elapsed before a permit was acquired. + * + * @throws InterruptedException if the current thread is interrupted + * + * @see Thread#interrupt + * + */ + public boolean tryAcquire(long timeout, TimeUnit unit) + throws InterruptedException { + return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout)); + } + + /** + * Releases a permit, returning it to the semaphore. + * <p>Releases a permit, increasing the number of available permits + * by one. + * If any threads are blocking 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. + * <p>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 {@link Thread#interrupt interrupted}. + * + * <p>Acquires the given number of permits, if they are available, + * and returns immediately, + * reducing the number of available permits by the given amount. + * + * <p>If insufficient permits are available then the current thread becomes + * disabled for thread scheduling purposes and lies dormant until + * one of two things happens: + * <ul> + * <li>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 + * <li>Some other thread {@link Thread#interrupt interrupts} the current + * thread. + * </ul> + * + * <p>If the current thread: + * <ul> + * <li>has its interrupted status set on entry to this method; or + * <li>is {@link Thread#interrupt interrupted} while waiting + * for a permit, + * </ul> + * 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 the next waiting thread(s), as if + * they 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 permits less than zero. + * + * @see Thread#interrupt + */ + 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. + * + * <p>Acquires the given number of permits, if they are available, + * and returns immediately, + * reducing the number of available permits by the given amount. + * + * <p>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. + * + * <p>If the current thread + * is {@link 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 permits less than zero. + * + */ + 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. + * + * <p>Acquires the given number of permits, if they are available, and + * returns immediately, with the value <tt>true</tt>, + * reducing the number of available permits by the given amount. + * + * <p>If insufficient permits are available then this method will return + * immediately with the value <tt>false</tt> and the number of available + * permits is unchanged. + * + * <p>Even when this semaphore has been set to use a fair ordering + * policy, a call to <tt>tryAcquire</tt> <em>will</em> + * 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 <tt>true</tt> if the permits were acquired and <tt>false</tt> + * otherwise. + * @throws IllegalArgumentException if permits less than zero. + */ + 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 {@link Thread#interrupt interrupted}. + * <p>Acquires the given number of permits, if they are available and + * returns immediately, with the value <tt>true</tt>, + * reducing the number of available permits by the given amount. + * <p>If insufficient permits are available then + * the current thread becomes disabled for thread scheduling + * purposes and lies dormant until one of three things happens: + * <ul> + * <li>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 + * <li>Some other thread {@link Thread#interrupt interrupts} the current + * thread; or + * <li>The specified waiting time elapses. + * </ul> + * <p>If the permits are acquired then the value <tt>true</tt> is returned. + * <p>If the current thread: + * <ul> + * <li>has its interrupted status set on entry to this method; or + * <li>is {@link Thread#interrupt interrupted} while waiting to acquire + * the permits, + * </ul> + * 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 the next waiting thread(s), as if + * they had been made available by a call to {@link #release()}. + * + * <p>If the specified waiting time elapses then the value <tt>false</tt> + * 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 the next waiting thread(s), as if + * they 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 <tt>timeout</tt> argument. + * @return <tt>true</tt> if all permits were acquired and <tt>false</tt> + * if the waiting time elapsed before all permits were acquired. + * + * @throws InterruptedException if the current thread is interrupted + * @throws IllegalArgumentException if permits less than zero. + * + * @see Thread#interrupt + * + */ + 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. + * <p>Releases the given number of permits, increasing the number of + * available permits by that amount. + * If any threads are blocking trying to acquire permits, then the + * one that has been waiting the longest + * 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 continues to wait. If there are still permits available + * after the first thread's request has been satisfied, then those permits + * are assigned to the next waiting thread. If it is satisfied then it is + * re-enabled for thread scheduling purposes. This continues until there + * are insufficient permits to satisfy the next waiting thread, or there + * are no more waiting threads. + * + * <p>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 permits less than zero. + */ + public void release(int permits) { + if (permits < 0) throw new IllegalArgumentException(); + sync.releaseShared(permits); + } + + /** + * Returns the current number of permits available in this semaphore. + * <p>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(); + } + + /** + * Acquire and return all permits that are immediately available. + * @return the number of permits + */ + 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 <tt>acquire</tt> in that it does not block + * waiting for permits to become available. + * @param reduction the number of permits to remove + * @throws IllegalArgumentException if reduction is negative + */ + protected void reducePermits(int reduction) { + if (reduction < 0) throw new IllegalArgumentException(); + sync.reducePermits(reduction); + } + + /** + * Returns true if this semaphore has fairness set true. + * @return 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 <tt>true</tt> + * 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 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<Thread> getQueuedThreads() { + return sync.getQueuedThreads(); + } + + /** + * Returns a string identifying this semaphore, as well as its state. + * The state, in brackets, includes the String + * "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 --git a/concurrent/src/main/java/java/util/concurrent/SynchronousQueue.java b/concurrent/src/main/java/java/util/concurrent/SynchronousQueue.java new file mode 100644 index 0000000..811dc38 --- /dev/null +++ b/concurrent/src/main/java/java/util/concurrent/SynchronousQueue.java @@ -0,0 +1,684 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent; +import java.util.concurrent.locks.*; +import java.util.*; + +// BEGIN android-note +// removed link to collections framework docs +// END android-note + +/** + * A {@linkplain BlockingQueue blocking queue} in which each + * <tt>put</tt> must wait for a <tt>take</tt>, and vice versa. A + * synchronous queue does not have any internal capacity, not even a + * capacity of one. You cannot <tt>peek</tt> at a synchronous queue + * because an element is only present when you try to take it; you + * cannot add an element (using any method) unless another thread is + * trying to remove it; you cannot iterate as there is nothing to + * iterate. The <em>head</em> of the queue is the element that the + * first queued thread is trying to add to the queue; if there are no + * queued threads then no element is being added and the head is + * <tt>null</tt>. For purposes of other <tt>Collection</tt> methods + * (for example <tt>contains</tt>), a <tt>SynchronousQueue</tt> acts + * as an empty collection. This queue does not permit <tt>null</tt> + * elements. + * + * <p>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. + * + * <p> 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 <tt>true</tt> grants threads access in FIFO order. Fairness + * generally decreases throughput but reduces variability and avoids + * starvation. + * + * <p>This class implements all of the <em>optional</em> methods + * of the {@link Collection} and {@link Iterator} interfaces. + * + * @since 1.5 + * @author Doug Lea + * @param <E> the type of elements held in this collection + */ +public class SynchronousQueue<E> extends AbstractQueue<E> + implements BlockingQueue<E>, java.io.Serializable { + private static final long serialVersionUID = -3223113410248163686L; + + /* + This implementation divides actions into two cases for puts: + + * An arriving producer that does not already have a waiting consumer + creates a node holding item, and then waits for a consumer to take it. + * An arriving producer that does already have a waiting consumer fills + the slot node created by the consumer, and notifies it to continue. + + And symmetrically, two for takes: + + * An arriving consumer that does not already have a waiting producer + creates an empty slot node, and then waits for a producer to fill it. + * An arriving consumer that does already have a waiting producer takes + item from the node created by the producer, and notifies it to continue. + + When a put or take waiting for the actions of its counterpart + aborts due to interruption or timeout, it marks the node + it created as "CANCELLED", which causes its counterpart to retry + the entire put or take sequence. + + This requires keeping two simple queues, waitingProducers and + waitingConsumers. Each of these can be FIFO (preserves fairness) + or LIFO (improves throughput). + */ + + /** Lock protecting both wait queues */ + private final ReentrantLock qlock; + /** Queue holding waiting puts */ + private final WaitQueue waitingProducers; + /** Queue holding waiting takes */ + private final WaitQueue waitingConsumers; + + /** + * Creates a <tt>SynchronousQueue</tt> with nonfair access policy. + */ + public SynchronousQueue() { + this(false); + } + + /** + * Creates a <tt>SynchronousQueue</tt> with specified fairness policy. + * @param fair if true, threads contend in FIFO order for access; + * otherwise the order is unspecified. + */ + public SynchronousQueue(boolean fair) { + if (fair) { + qlock = new ReentrantLock(true); + waitingProducers = new FifoWaitQueue(); + waitingConsumers = new FifoWaitQueue(); + } + else { + qlock = new ReentrantLock(); + waitingProducers = new LifoWaitQueue(); + waitingConsumers = new LifoWaitQueue(); + } + } + + /** + * Queue to hold waiting puts/takes; specialized to Fifo/Lifo below. + * These queues have all transient fields, but are serializable + * in order to recover fairness settings when deserialized. + */ + static abstract class WaitQueue implements java.io.Serializable { + /** Create, add, and return node for x */ + abstract Node enq(Object x); + /** Remove and return node, or null if empty */ + abstract Node deq(); + } + + /** + * FIFO queue to hold waiting puts/takes. + */ + static final class FifoWaitQueue extends WaitQueue implements java.io.Serializable { + private static final long serialVersionUID = -3623113410248163686L; + private transient Node head; + private transient Node last; + + Node enq(Object x) { + Node p = new Node(x); + if (last == null) + last = head = p; + else + last = last.next = p; + return p; + } + + Node deq() { + Node p = head; + if (p != null) { + if ((head = p.next) == null) + last = null; + p.next = null; + } + return p; + } + } + + /** + * LIFO queue to hold waiting puts/takes. + */ + static final class LifoWaitQueue extends WaitQueue implements java.io.Serializable { + private static final long serialVersionUID = -3633113410248163686L; + private transient Node head; + + Node enq(Object x) { + return head = new Node(x, head); + } + + Node deq() { + Node p = head; + if (p != null) { + head = p.next; + p.next = null; + } + return p; + } + } + + /** + * Nodes each maintain an item and handle waits and signals for + * getting and setting it. The class extends + * AbstractQueuedSynchronizer to manage blocking, using AQS state + * 0 for waiting, 1 for ack, -1 for cancelled. + */ + static final class Node extends AbstractQueuedSynchronizer { + /** Synchronization state value representing that node acked */ + private static final int ACK = 1; + /** Synchronization state value representing that node cancelled */ + private static final int CANCEL = -1; + + /** The item being transferred */ + Object item; + /** Next node in wait queue */ + Node next; + + /** Creates a node with initial item */ + Node(Object x) { item = x; } + + /** Creates a node with initial item and next */ + Node(Object x, Node n) { item = x; next = n; } + + /** + * Implements AQS base acquire to succeed if not in WAITING state + */ + protected boolean tryAcquire(int ignore) { + return getState() != 0; + } + + /** + * Implements AQS base release to signal if state changed + */ + protected boolean tryRelease(int newState) { + return compareAndSetState(0, newState); + } + + /** + * Takes item and nulls out field (for sake of GC) + */ + private Object extract() { + Object x = item; + item = null; + return x; + } + + /** + * Tries to cancel on interrupt; if so rethrowing, + * else setting interrupt state + */ + private void checkCancellationOnInterrupt(InterruptedException ie) + throws InterruptedException { + if (release(CANCEL)) + throw ie; + Thread.currentThread().interrupt(); + } + + /** + * Fills in the slot created by the consumer and signal consumer to + * continue. + */ + boolean setItem(Object x) { + item = x; // can place in slot even if cancelled + return release(ACK); + } + + /** + * Removes item from slot created by producer and signal producer + * to continue. + */ + Object getItem() { + return (release(ACK))? extract() : null; + } + + /** + * Waits for a consumer to take item placed by producer. + */ + void waitForTake() throws InterruptedException { + try { + acquireInterruptibly(0); + } catch (InterruptedException ie) { + checkCancellationOnInterrupt(ie); + } + } + + /** + * Waits for a producer to put item placed by consumer. + */ + Object waitForPut() throws InterruptedException { + try { + acquireInterruptibly(0); + } catch (InterruptedException ie) { + checkCancellationOnInterrupt(ie); + } + return extract(); + } + + /** + * Waits for a consumer to take item placed by producer or time out. + */ + boolean waitForTake(long nanos) throws InterruptedException { + try { + if (!tryAcquireNanos(0, nanos) && + release(CANCEL)) + return false; + } catch (InterruptedException ie) { + checkCancellationOnInterrupt(ie); + } + return true; + } + + /** + * Waits for a producer to put item placed by consumer, or time out. + */ + Object waitForPut(long nanos) throws InterruptedException { + try { + if (!tryAcquireNanos(0, nanos) && + release(CANCEL)) + return null; + } catch (InterruptedException ie) { + checkCancellationOnInterrupt(ie); + } + return extract(); + } + } + + /** + * Adds the specified element to this queue, waiting if necessary for + * another thread to receive it. + * @param o the element to add + * @throws InterruptedException if interrupted while waiting. + * @throws NullPointerException if the specified element is <tt>null</tt>. + */ + public void put(E o) throws InterruptedException { + if (o == null) throw new NullPointerException(); + final ReentrantLock qlock = this.qlock; + + for (;;) { + Node node; + boolean mustWait; + if (Thread.interrupted()) throw new InterruptedException(); + qlock.lock(); + try { + node = waitingConsumers.deq(); + if ( (mustWait = (node == null)) ) + node = waitingProducers.enq(o); + } finally { + qlock.unlock(); + } + + if (mustWait) { + node.waitForTake(); + return; + } + + else if (node.setItem(o)) + return; + + // else consumer cancelled, so retry + } + } + + /** + * Inserts the specified element into this queue, waiting if necessary + * up to the specified wait time for another thread to receive it. + * @param o the element to add + * @param timeout how long to wait before giving up, in units of + * <tt>unit</tt> + * @param unit a <tt>TimeUnit</tt> determining how to interpret the + * <tt>timeout</tt> parameter + * @return <tt>true</tt> if successful, or <tt>false</tt> if + * the specified waiting time elapses before a consumer appears. + * @throws InterruptedException if interrupted while waiting. + * @throws NullPointerException if the specified element is <tt>null</tt>. + */ + public boolean offer(E o, long timeout, TimeUnit unit) throws InterruptedException { + if (o == null) throw new NullPointerException(); + long nanos = unit.toNanos(timeout); + final ReentrantLock qlock = this.qlock; + for (;;) { + Node node; + boolean mustWait; + if (Thread.interrupted()) throw new InterruptedException(); + qlock.lock(); + try { + node = waitingConsumers.deq(); + if ( (mustWait = (node == null)) ) + node = waitingProducers.enq(o); + } finally { + qlock.unlock(); + } + + if (mustWait) + return node.waitForTake(nanos); + + else if (node.setItem(o)) + return true; + + // else consumer cancelled, so retry + } + } + + /** + * Retrieves and removes the head of this queue, waiting if necessary + * for another thread to insert it. + * @throws InterruptedException if interrupted while waiting. + * @return the head of this queue + */ + public E take() throws InterruptedException { + final ReentrantLock qlock = this.qlock; + for (;;) { + Node node; + boolean mustWait; + + if (Thread.interrupted()) throw new InterruptedException(); + qlock.lock(); + try { + node = waitingProducers.deq(); + if ( (mustWait = (node == null)) ) + node = waitingConsumers.enq(null); + } finally { + qlock.unlock(); + } + + if (mustWait) { + Object x = node.waitForPut(); + return (E)x; + } + else { + Object x = node.getItem(); + if (x != null) + return (E)x; + // else cancelled, so retry + } + } + } + + /** + * Retrieves and removes the head of this queue, waiting + * if necessary up to the specified wait time, for another thread + * to insert it. + * @param timeout how long to wait before giving up, in units of + * <tt>unit</tt> + * @param unit a <tt>TimeUnit</tt> determining how to interpret the + * <tt>timeout</tt> parameter + * @return the head of this queue, or <tt>null</tt> if the + * specified waiting time elapses before an element is present. + * @throws InterruptedException if interrupted while waiting. + */ + public E poll(long timeout, TimeUnit unit) throws InterruptedException { + long nanos = unit.toNanos(timeout); + final ReentrantLock qlock = this.qlock; + + for (;;) { + Node node; + boolean mustWait; + + if (Thread.interrupted()) throw new InterruptedException(); + qlock.lock(); + try { + node = waitingProducers.deq(); + if ( (mustWait = (node == null)) ) + node = waitingConsumers.enq(null); + } finally { + qlock.unlock(); + } + + if (mustWait) { + Object x = node.waitForPut(nanos); + return (E)x; + } + else { + Object x = node.getItem(); + if (x != null) + return (E)x; + // else cancelled, so retry + } + } + } + + // Untimed nonblocking versions + + /** + * Inserts the specified element into this queue, if another thread is + * waiting to receive it. + * + * @param o the element to add. + * @return <tt>true</tt> if it was possible to add the element to + * this queue, else <tt>false</tt> + * @throws NullPointerException if the specified element is <tt>null</tt> + */ + public boolean offer(E o) { + if (o == null) throw new NullPointerException(); + final ReentrantLock qlock = this.qlock; + + for (;;) { + Node node; + qlock.lock(); + try { + node = waitingConsumers.deq(); + } finally { + qlock.unlock(); + } + if (node == null) + return false; + + else if (node.setItem(o)) + return true; + // else retry + } + } + + /** + * Retrieves and removes the head of this queue, if another thread + * is currently making an element available. + * + * @return the head of this queue, or <tt>null</tt> if no + * element is available. + */ + public E poll() { + final ReentrantLock qlock = this.qlock; + for (;;) { + Node node; + qlock.lock(); + try { + node = waitingProducers.deq(); + } finally { + qlock.unlock(); + } + if (node == null) + return null; + + else { + Object x = node.getItem(); + if (x != null) + return (E)x; + // else retry + } + } + } + + /** + * Always returns <tt>true</tt>. + * A <tt>SynchronousQueue</tt> has no internal capacity. + * @return <tt>true</tt> + */ + public boolean isEmpty() { + return true; + } + + /** + * Always returns zero. + * A <tt>SynchronousQueue</tt> has no internal capacity. + * @return zero. + */ + public int size() { + return 0; + } + + /** + * Always returns zero. + * A <tt>SynchronousQueue</tt> has no internal capacity. + * @return zero. + */ + public int remainingCapacity() { + return 0; + } + + /** + * Does nothing. + * A <tt>SynchronousQueue</tt> has no internal capacity. + */ + public void clear() {} + + /** + * Always returns <tt>false</tt>. + * A <tt>SynchronousQueue</tt> has no internal capacity. + * @param o the element + * @return <tt>false</tt> + */ + public boolean contains(Object o) { + return false; + } + + /** + * Always returns <tt>false</tt>. + * A <tt>SynchronousQueue</tt> has no internal capacity. + * + * @param o the element to remove + * @return <tt>false</tt> + */ + public boolean remove(Object o) { + return false; + } + + /** + * Returns <tt>false</tt> unless given collection is empty. + * A <tt>SynchronousQueue</tt> has no internal capacity. + * @param c the collection + * @return <tt>false</tt> unless given collection is empty + */ + public boolean containsAll(Collection<?> c) { + return c.isEmpty(); + } + + /** + * Always returns <tt>false</tt>. + * A <tt>SynchronousQueue</tt> has no internal capacity. + * @param c the collection + * @return <tt>false</tt> + */ + public boolean removeAll(Collection<?> c) { + return false; + } + + /** + * Always returns <tt>false</tt>. + * A <tt>SynchronousQueue</tt> has no internal capacity. + * @param c the collection + * @return <tt>false</tt> + */ + public boolean retainAll(Collection<?> c) { + return false; + } + + /** + * Always returns <tt>null</tt>. + * A <tt>SynchronousQueue</tt> does not return elements + * unless actively waited on. + * @return <tt>null</tt> + */ + public E peek() { + return null; + } + + + static class EmptyIterator<E> implements Iterator<E> { + public boolean hasNext() { + return false; + } + public E next() { + throw new NoSuchElementException(); + } + public void remove() { + throw new IllegalStateException(); + } + } + + /** + * Returns an empty iterator in which <tt>hasNext</tt> always returns + * <tt>false</tt>. + * + * @return an empty iterator + */ + public Iterator<E> iterator() { + return new EmptyIterator<E>(); + } + + + /** + * 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 <tt>null</tt> + * (if the array has non-zero length) and returns it. + * @param a the array + * @return the specified array + */ + public <T> T[] toArray(T[] a) { + if (a.length > 0) + a[0] = null; + return a; + } + + public int drainTo(Collection<? super E> 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; + } + + public int drainTo(Collection<? super E> 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; + } +} + + + + + diff --git a/concurrent/src/main/java/java/util/concurrent/ThreadFactory.java b/concurrent/src/main/java/java/util/concurrent/ThreadFactory.java new file mode 100644 index 0000000..04c63e1 --- /dev/null +++ b/concurrent/src/main/java/java/util/concurrent/ThreadFactory.java @@ -0,0 +1,40 @@ +/* + * 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/licenses/publicdomain + */ + +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. + * + * <p> + * The simplest implementation of this interface is just: + * <pre> + * class SimpleThreadFactory implements ThreadFactory { + * public Thread newThread(Runnable r) { + * return new Thread(r); + * } + * } + * </pre> + * + * 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 <tt>Thread</tt>. Implementations may also initialize + * priority, name, daemon status, <tt>ThreadGroup</tt>, etc. + * + * @param r a runnable to be executed by new thread instance + * @return constructed thread + */ + Thread newThread(Runnable r); +} diff --git a/concurrent/src/main/java/java/util/concurrent/ThreadPoolExecutor.java b/concurrent/src/main/java/java/util/concurrent/ThreadPoolExecutor.java new file mode 100644 index 0000000..1aa8e55 --- /dev/null +++ b/concurrent/src/main/java/java/util/concurrent/ThreadPoolExecutor.java @@ -0,0 +1,1513 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent; +import java.util.concurrent.locks.*; +import java.util.*; + +// BEGIN android-note +// Altered {@link TimeUnit#NANOSECONDS} because our javadoc tool doesn't +// like it. +// END android-note + +/** + * An {@link ExecutorService} that executes each submitted task using + * one of possibly several pooled threads, normally configured + * using {@link Executors} factory methods. + * + * <p>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 <tt>ThreadPoolExecutor</tt> also maintains some basic + * statistics, such as the number of completed tasks. + * + * <p>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: + * + * <dl> + * + * <dt>Core and maximum pool sizes</dt> + * + * <dd>A <tt>ThreadPoolExecutor</tt> will automatically adjust the + * pool size + * (see {@link ThreadPoolExecutor#getPoolSize}) + * according to the bounds set by corePoolSize + * (see {@link ThreadPoolExecutor#getCorePoolSize}) + * and + * maximumPoolSize + * (see {@link ThreadPoolExecutor#getMaximumPoolSize}). + * When a new task is submitted in method {@link + * ThreadPoolExecutor#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 <tt>Integer.MAX_VALUE</tt>, 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 + * ThreadPoolExecutor#setCorePoolSize} and {@link + * ThreadPoolExecutor#setMaximumPoolSize}. <dd> + * + * <dt> On-demand construction + * + * <dd> By default, even core threads are initially created and + * started only when needed by new tasks, but this can be overridden + * dynamically using method {@link + * ThreadPoolExecutor#prestartCoreThread} or + * {@link ThreadPoolExecutor#prestartAllCoreThreads}. </dd> + * + * <dt>Creating new threads</dt> + * + * <dd>New threads are created using a {@link + * java.util.concurrent.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 + * <tt>NORM_PRIORITY</tt> priority and non-daemon status. By supplying + * a different ThreadFactory, you can alter the thread's name, thread + * group, priority, daemon status, etc. </dd> + * + * <dt>Keep-alive times</dt> + * + * <dd>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 + * ThreadPoolExecutor#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 ThreadPoolExecutor#setKeepAliveTime}. Using + * a value of <tt>Long.MAX_VALUE</tt> <code>TimeUnit.NANOSECONDS</code> + * effectively disables idle threads from ever terminating prior + * to shut down. + * </dd> + * + * <dt>Queuing</dt> + * + * <dd>Any {@link BlockingQueue} may be used to transfer and hold + * submitted tasks. The use of this queue interacts with pool sizing: + * + * <ul> + * + * <li> If fewer than corePoolSize threads are running, the Executor + * always prefers adding a new thread + * rather than queuing.</li> + * + * <li> If corePoolSize or more threads are running, the Executor + * always prefers queuing a request rather than adding a new + * thread.</li> + * + * <li> If a request cannot be queued, a new thread is created unless + * this would exceed maximumPoolSize, in which case, the task will be + * rejected.</li> + * + * </ul> + * + * There are three general strategies for queuing: + * <ol> + * + * <li> <em> Direct handoffs.</em> 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. </li> + * + * <li><em> Unbounded queues.</em> Using an unbounded queue (for + * example a {@link LinkedBlockingQueue} without a predefined + * capacity) will cause new tasks to be queued in cases where 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. </li> + * + * <li><em>Bounded queues.</em> 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. </li> + * + * </ol> + * + * </dd> + * + * <dt>Rejected tasks</dt> + * + * <dd> New tasks submitted in method {@link + * ThreadPoolExecutor#execute} will be <em>rejected</em> 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 <tt>execute</tt> method invokes the + * {@link RejectedExecutionHandler#rejectedExecution} method of its + * {@link RejectedExecutionHandler}. Four predefined handler policies + * are provided: + * + * <ol> + * + * <li> In the + * default {@link ThreadPoolExecutor.AbortPolicy}, the handler throws a + * runtime {@link RejectedExecutionException} upon rejection. </li> + * + * <li> In {@link + * ThreadPoolExecutor.CallerRunsPolicy}, the thread that invokes + * <tt>execute</tt> itself runs the task. This provides a simple + * feedback control mechanism that will slow down the rate that new + * tasks are submitted. </li> + * + * <li> In {@link ThreadPoolExecutor.DiscardPolicy}, + * a task that cannot be executed is simply dropped. </li> + * + * <li>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.) </li> + * + * </ol> + * + * 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. </dd> + * + * <dt>Hook methods</dt> + * + * <dd>This class provides <tt>protected</tt> overridable {@link + * ThreadPoolExecutor#beforeExecute} and {@link + * ThreadPoolExecutor#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 ThreadPoolExecutor#terminated} can be overridden to perform + * any special processing that needs to be done once the Executor has + * fully terminated.</dd> + * + * <dt>Queue maintenance</dt> + * + * <dd> Method {@link ThreadPoolExecutor#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 ThreadPoolExecutor#remove} and {@link + * ThreadPoolExecutor#purge} are available to assist in storage + * reclamation when large numbers of queued tasks become + * cancelled.</dd> </dl> + * + * <p> <b>Extension example</b>. 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: + * + * <pre> + * 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(); + * } + * } + * } + * </pre> + * @since 1.5 + * @author Doug Lea + */ +public class ThreadPoolExecutor extends AbstractExecutorService { + /** + * Only used to force toArray() to produce a Runnable[]. + */ + private static final Runnable[] EMPTY_RUNNABLE_ARRAY = new Runnable[0]; + + /** + * Permission for checking shutdown + */ + private static final RuntimePermission shutdownPerm = + new RuntimePermission("modifyThread"); + + /** + * Queue used for holding tasks and handing off to worker threads. + */ + private final BlockingQueue<Runnable> workQueue; + + /** + * Lock held on updates to poolSize, corePoolSize, maximumPoolSize, and + * workers set. + */ + private final ReentrantLock mainLock = new ReentrantLock(); + + /** + * Wait condition to support awaitTermination + */ + private final Condition termination = mainLock.newCondition(); + + /** + * Set containing all worker threads in pool. + */ + private final HashSet<Worker> workers = new HashSet<Worker>(); + + /** + * Timeout in nanoseconds for idle threads waiting for work. + * Threads use this timeout only when there are more than + * corePoolSize present. Otherwise they wait forever for new work. + */ + private volatile long keepAliveTime; + + /** + * Core pool size, updated only while holding mainLock, + * but volatile to allow concurrent readability even + * during updates. + */ + private volatile int corePoolSize; + + /** + * Maximum pool size, updated only while holding mainLock + * but volatile to allow concurrent readability even + * during updates. + */ + private volatile int maximumPoolSize; + + /** + * Current pool size, updated only while holding mainLock + * but volatile to allow concurrent readability even + * during updates. + */ + private volatile int poolSize; + + /** + * Lifecycle state + */ + volatile int runState; + + // Special values for runState + /** Normal, not-shutdown mode */ + static final int RUNNING = 0; + /** Controlled shutdown mode */ + static final int SHUTDOWN = 1; + /** Immediate shutdown mode */ + static final int STOP = 2; + /** Final state */ + static final int TERMINATED = 3; + + /** + * Handler called when saturated or shutdown in execute. + */ + private volatile RejectedExecutionHandler handler; + + /** + * Factory for new threads. + */ + private volatile ThreadFactory threadFactory; + + /** + * Tracks largest attained pool size. + */ + private int largestPoolSize; + + /** + * Counter for completed tasks. Updated only on termination of + * worker threads. + */ + private long completedTaskCount; + + /** + * The default rejected execution handler + */ + private static final RejectedExecutionHandler defaultHandler = + new AbortPolicy(); + + /** + * Invoke the rejected execution handler for the given command. + */ + void reject(Runnable command) { + handler.rejectedExecution(command, this); + } + + /** + * Create and return a new thread running firstTask as its first + * task. Call only while holding mainLock + * @param firstTask the task the new thread should run first (or + * null if none) + * @return the new thread + */ + private Thread addThread(Runnable firstTask) { + Worker w = new Worker(firstTask); + Thread t = threadFactory.newThread(w); + w.thread = t; + workers.add(w); + int nt = ++poolSize; + if (nt > largestPoolSize) + largestPoolSize = nt; + return t; + } + + /** + * Create and start a new thread running firstTask as its first + * task, only if fewer than corePoolSize threads are running. + * @param firstTask the task the new thread should run first (or + * null if none) + * @return true if successful. + */ + private boolean addIfUnderCorePoolSize(Runnable firstTask) { + Thread t = null; + final ReentrantLock mainLock = this.mainLock; + mainLock.lock(); + try { + if (poolSize < corePoolSize) + t = addThread(firstTask); + } finally { + mainLock.unlock(); + } + if (t == null) + return false; + t.start(); + return true; + } + + /** + * Create and start a new thread only if fewer than maximumPoolSize + * threads are running. The new thread runs as its first task the + * next task in queue, or if there is none, the given task. + * @param firstTask the task the new thread should run first (or + * null if none) + * @return null on failure, else the first task to be run by new thread. + */ + private Runnable addIfUnderMaximumPoolSize(Runnable firstTask) { + Thread t = null; + Runnable next = null; + final ReentrantLock mainLock = this.mainLock; + mainLock.lock(); + try { + if (poolSize < maximumPoolSize) { + next = workQueue.poll(); + if (next == null) + next = firstTask; + t = addThread(next); + } + } finally { + mainLock.unlock(); + } + if (t == null) + return null; + t.start(); + return next; + } + + + /** + * Get the next task for a worker thread to run. + * @return the task + * @throws InterruptedException if interrupted while waiting for task + */ + Runnable getTask() throws InterruptedException { + for (;;) { + switch(runState) { + case RUNNING: { + if (poolSize <= corePoolSize) // untimed wait if core + return workQueue.take(); + + long timeout = keepAliveTime; + if (timeout <= 0) // die immediately for 0 timeout + return null; + Runnable r = workQueue.poll(timeout, TimeUnit.NANOSECONDS); + if (r != null) + return r; + if (poolSize > corePoolSize) // timed out + return null; + // else, after timeout, pool shrank so shouldn't die, so retry + break; + } + + case SHUTDOWN: { + // Help drain queue + Runnable r = workQueue.poll(); + if (r != null) + return r; + + // Check if can terminate + if (workQueue.isEmpty()) { + interruptIdleWorkers(); + return null; + } + + // There could still be delayed tasks in queue. + // Wait for one, re-checking state upon interruption + try { + return workQueue.take(); + } catch(InterruptedException ignore) {} + break; + } + + case STOP: + return null; + default: + assert false; + } + } + } + + /** + * Wake up all threads that might be waiting for tasks. + */ + void interruptIdleWorkers() { + final ReentrantLock mainLock = this.mainLock; + mainLock.lock(); + try { + for (Worker w : workers) + w.interruptIfIdle(); + } finally { + mainLock.unlock(); + } + } + + /** + * Perform bookkeeping for a terminated worker thread. + * @param w the worker + */ + void workerDone(Worker w) { + final ReentrantLock mainLock = this.mainLock; + mainLock.lock(); + try { + completedTaskCount += w.completedTasks; + workers.remove(w); + if (--poolSize > 0) + return; + + // Else, this is the last thread. Deal with potential shutdown. + + int state = runState; + assert state != TERMINATED; + + if (state != STOP) { + // If there are queued tasks but no threads, create + // replacement. + Runnable r = workQueue.poll(); + if (r != null) { + addThread(r).start(); + return; + } + + // If there are some (presumably delayed) tasks but + // none pollable, create an idle replacement to wait. + if (!workQueue.isEmpty()) { + addThread(null).start(); + return; + } + + // Otherwise, we can exit without replacement + if (state == RUNNING) + return; + } + + // Either state is STOP, or state is SHUTDOWN and there is + // no work to do. So we can terminate. + termination.signalAll(); + runState = TERMINATED; + // fall through to call terminate() outside of lock. + } finally { + mainLock.unlock(); + } + + assert runState == TERMINATED; + terminated(); + } + + /** + * Worker threads + */ + private class Worker implements Runnable { + + /** + * The runLock is acquired and released surrounding each task + * execution. It mainly protects against interrupts that are + * intended to cancel the worker thread from instead + * interrupting the task being run. + */ + private final ReentrantLock runLock = new ReentrantLock(); + + /** + * Initial task to run before entering run loop + */ + private Runnable firstTask; + + /** + * Per thread completed task counter; accumulated + * into completedTaskCount upon termination. + */ + volatile long completedTasks; + + /** + * Thread this worker is running in. Acts as a final field, + * but cannot be set until thread is created. + */ + Thread thread; + + Worker(Runnable firstTask) { + this.firstTask = firstTask; + } + + boolean isActive() { + return runLock.isLocked(); + } + + /** + * Interrupt thread if not running a task + */ + void interruptIfIdle() { + final ReentrantLock runLock = this.runLock; + if (runLock.tryLock()) { + try { + thread.interrupt(); + } finally { + runLock.unlock(); + } + } + } + + /** + * Cause thread to die even if running a task. + */ + void interruptNow() { + thread.interrupt(); + } + + /** + * Run a single task between before/after methods. + */ + private void runTask(Runnable task) { + final ReentrantLock runLock = this.runLock; + runLock.lock(); + try { + // Abort now if immediate cancel. Otherwise, we have + // committed to run this task. + if (runState == STOP) + return; + + Thread.interrupted(); // clear interrupt status on entry + boolean ran = false; + beforeExecute(thread, task); + try { + task.run(); + ran = true; + afterExecute(task, null); + ++completedTasks; + } catch(RuntimeException ex) { + if (!ran) + afterExecute(task, ex); + // Else the exception occurred within + // afterExecute itself in which case we don't + // want to call it again. + throw ex; + } + } finally { + runLock.unlock(); + } + } + + /** + * Main run loop + */ + public void run() { + try { + Runnable task = firstTask; + firstTask = null; + while (task != null || (task = getTask()) != null) { + runTask(task); + task = null; // unnecessary but can help GC + } + } catch(InterruptedException ie) { + // fall through + } finally { + workerDone(this); + } + } + } + + // Public methods + + /** + * Creates a new <tt>ThreadPoolExecutor</tt> with the given + * initial parameters and default thread factory and 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. + * @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 keepAliveTime + * argument. + * @param workQueue the queue to use for holding tasks before they + * are executed. This queue will hold only the <tt>Runnable</tt> + * tasks submitted by the <tt>execute</tt> method. + * @throws IllegalArgumentException if corePoolSize, or + * keepAliveTime less than zero, or if maximumPoolSize less than or + * equal to zero, or if corePoolSize greater than maximumPoolSize. + * @throws NullPointerException if <tt>workQueue</tt> is null + */ + public ThreadPoolExecutor(int corePoolSize, + int maximumPoolSize, + long keepAliveTime, + TimeUnit unit, + BlockingQueue<Runnable> workQueue) { + this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, + Executors.defaultThreadFactory(), defaultHandler); + } + + /** + * Creates a new <tt>ThreadPoolExecutor</tt> with the given initial + * parameters. + * + * @param corePoolSize the number of threads to keep in the + * pool, even if they are idle. + * @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 keepAliveTime + * argument. + * @param workQueue the queue to use for holding tasks before they + * are executed. This queue will hold only the <tt>Runnable</tt> + * tasks submitted by the <tt>execute</tt> method. + * @param threadFactory the factory to use when the executor + * creates a new thread. + * @throws IllegalArgumentException if corePoolSize, or + * keepAliveTime less than zero, or if maximumPoolSize less than or + * equal to zero, or if corePoolSize greater than maximumPoolSize. + * @throws NullPointerException if <tt>workQueue</tt> + * or <tt>threadFactory</tt> are null. + */ + public ThreadPoolExecutor(int corePoolSize, + int maximumPoolSize, + long keepAliveTime, + TimeUnit unit, + BlockingQueue<Runnable> workQueue, + ThreadFactory threadFactory) { + this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, + threadFactory, defaultHandler); + } + + /** + * Creates a new <tt>ThreadPoolExecutor</tt> with the given initial + * parameters. + * + * @param corePoolSize the number of threads to keep in the + * pool, even if they are idle. + * @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 keepAliveTime + * argument. + * @param workQueue the queue to use for holding tasks before they + * are executed. This queue will hold only the <tt>Runnable</tt> + * tasks submitted by the <tt>execute</tt> method. + * @param handler the handler to use when execution is blocked + * because the thread bounds and queue capacities are reached. + * @throws IllegalArgumentException if corePoolSize, or + * keepAliveTime less than zero, or if maximumPoolSize less than or + * equal to zero, or if corePoolSize greater than maximumPoolSize. + * @throws NullPointerException if <tt>workQueue</tt> + * or <tt>handler</tt> are null. + */ + public ThreadPoolExecutor(int corePoolSize, + int maximumPoolSize, + long keepAliveTime, + TimeUnit unit, + BlockingQueue<Runnable> workQueue, + RejectedExecutionHandler handler) { + this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, + Executors.defaultThreadFactory(), handler); + } + + /** + * Creates a new <tt>ThreadPoolExecutor</tt> with the given initial + * parameters. + * + * @param corePoolSize the number of threads to keep in the + * pool, even if they are idle. + * @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 keepAliveTime + * argument. + * @param workQueue the queue to use for holding tasks before they + * are executed. This queue will hold only the <tt>Runnable</tt> + * tasks submitted by the <tt>execute</tt> 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 corePoolSize, or + * keepAliveTime less than zero, or if maximumPoolSize less than or + * equal to zero, or if corePoolSize greater than maximumPoolSize. + * @throws NullPointerException if <tt>workQueue</tt> + * or <tt>threadFactory</tt> or <tt>handler</tt> are null. + */ + public ThreadPoolExecutor(int corePoolSize, + int maximumPoolSize, + long keepAliveTime, + TimeUnit unit, + BlockingQueue<Runnable> 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 <tt>RejectedExecutionHandler</tt>. + * + * @param command the task to execute + * @throws RejectedExecutionException at discretion of + * <tt>RejectedExecutionHandler</tt>, if task cannot be accepted + * for execution + * @throws NullPointerException if command is null + */ + public void execute(Runnable command) { + if (command == null) + throw new NullPointerException(); + for (;;) { + if (runState != RUNNING) { + reject(command); + return; + } + if (poolSize < corePoolSize && addIfUnderCorePoolSize(command)) + return; + if (workQueue.offer(command)) + return; + Runnable r = addIfUnderMaximumPoolSize(command); + if (r == command) + return; + if (r == null) { + reject(command); + return; + } + // else retry + } + } + + /** + * 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. + * @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}<tt>("modifyThread")</tt>, + * or the security manager's <tt>checkAccess</tt> method denies access. + */ + public void shutdown() { + // Fail if caller doesn't have modifyThread permission + SecurityManager security = System.getSecurityManager(); + if (security != null) + java.security.AccessController.checkPermission(shutdownPerm); + + boolean fullyTerminated = false; + final ReentrantLock mainLock = this.mainLock; + mainLock.lock(); + try { + if (workers.size() > 0) { + // Check if caller can modify worker threads. This + // might not be true even if passed above check, if + // the SecurityManager treats some threads specially. + if (security != null) { + for (Worker w: workers) + security.checkAccess(w.thread); + } + + int state = runState; + if (state == RUNNING) // don't override shutdownNow + runState = SHUTDOWN; + + try { + for (Worker w: workers) + w.interruptIfIdle(); + } catch(SecurityException se) { + // If SecurityManager allows above checks, but + // then unexpectedly throws exception when + // interrupting threads (which it ought not do), + // back out as cleanly as we can. Some threads may + // have been killed but we remain in non-shutdown + // state. + runState = state; + throw se; + } + } + else { // If no workers, trigger full termination now + fullyTerminated = true; + runState = TERMINATED; + termination.signalAll(); + } + } finally { + mainLock.unlock(); + } + if (fullyTerminated) + terminated(); + } + + + /** + * Attempts to stop all actively executing tasks, halts the + * processing of waiting tasks, and returns a list of the tasks that were + * awaiting execution. + * + * <p>This implementation cancels tasks via {@link + * Thread#interrupt}, so if any tasks mask or fail to respond to + * interrupts, they 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}<tt>("modifyThread")</tt>, + * or the security manager's <tt>checkAccess</tt> method denies access. + */ + public List<Runnable> shutdownNow() { + // Almost the same code as shutdown() + SecurityManager security = System.getSecurityManager(); + if (security != null) + java.security.AccessController.checkPermission(shutdownPerm); + + boolean fullyTerminated = false; + final ReentrantLock mainLock = this.mainLock; + mainLock.lock(); + try { + if (workers.size() > 0) { + if (security != null) { + for (Worker w: workers) + security.checkAccess(w.thread); + } + + int state = runState; + if (state != TERMINATED) + runState = STOP; + try { + for (Worker w : workers) + w.interruptNow(); + } catch(SecurityException se) { + runState = state; // back out; + throw se; + } + } + else { // If no workers, trigger full termination now + fullyTerminated = true; + runState = TERMINATED; + termination.signalAll(); + } + } finally { + mainLock.unlock(); + } + if (fullyTerminated) + terminated(); + return Arrays.asList(workQueue.toArray(EMPTY_RUNNABLE_ARRAY)); + } + + public boolean isShutdown() { + return runState != RUNNING; + } + + /** + * Returns true if this executor is in the process of terminating + * after <tt>shutdown</tt> or <tt>shutdownNow</tt> but has not + * completely terminated. This method may be useful for + * debugging. A return of <tt>true</tt> 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() { + return runState == STOP; + } + + public boolean isTerminated() { + return runState == 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 (runState == TERMINATED) + return true; + if (nanos <= 0) + return false; + nanos = termination.awaitNanos(nanos); + } + } finally { + mainLock.unlock(); + } + } + + /** + * Invokes <tt>shutdown</tt> when this executor is no longer + * referenced. + */ + 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; + } + + /** + * 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<Runnable> 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. + * + * <p> 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 <tt>submit</tt> might be + * converted into a form that maintains <tt>Future</tt> status. + * However, in such cases, method {@link ThreadPoolExecutor#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) { + return getQueue().remove(task); + } + + + /** + * 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() { + // Fail if we encounter interference during traversal + try { + Iterator<Runnable> it = getQueue().iterator(); + while (it.hasNext()) { + Runnable r = it.next(); + if (r instanceof Future<?>) { + Future<?> c = (Future<?>)r; + if (c.isCancelled()) + it.remove(); + } + } + } + catch(ConcurrentModificationException ex) { + return; + } + } + + /** + * 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 <tt>corePoolSize</tt> + * less than zero + * @see #getCorePoolSize + */ + public void setCorePoolSize(int corePoolSize) { + if (corePoolSize < 0) + throw new IllegalArgumentException(); + final ReentrantLock mainLock = this.mainLock; + mainLock.lock(); + try { + int extra = this.corePoolSize - corePoolSize; + this.corePoolSize = corePoolSize; + if (extra < 0) { + Runnable r; + while (extra++ < 0 && poolSize < corePoolSize && + (r = workQueue.poll()) != null) + addThread(r).start(); + } + else if (extra > 0 && poolSize > corePoolSize) { + Iterator<Worker> it = workers.iterator(); + while (it.hasNext() && + extra-- > 0 && + poolSize > corePoolSize && + workQueue.remainingCapacity() == 0) + it.next().interruptIfIdle(); + } + } finally { + mainLock.unlock(); + } + } + + /** + * 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 <tt>false</tt> + * if all core threads have already been started. + * @return true if a thread was started + */ + public boolean prestartCoreThread() { + return addIfUnderCorePoolSize(null); + } + + /** + * 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 (addIfUnderCorePoolSize(null)) + ++n; + return n; + } + + /** + * 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 maximumPoolSize less than zero or + * the {@link #getCorePoolSize core pool size} + * @see #getMaximumPoolSize + */ + public void setMaximumPoolSize(int maximumPoolSize) { + if (maximumPoolSize <= 0 || maximumPoolSize < corePoolSize) + throw new IllegalArgumentException(); + final ReentrantLock mainLock = this.mainLock; + mainLock.lock(); + try { + int extra = this.maximumPoolSize - maximumPoolSize; + this.maximumPoolSize = maximumPoolSize; + if (extra > 0 && poolSize > maximumPoolSize) { + Iterator<Worker> it = workers.iterator(); + while (it.hasNext() && + extra > 0 && + poolSize > maximumPoolSize) { + it.next().interruptIfIdle(); + --extra; + } + } + } finally { + mainLock.unlock(); + } + } + + /** + * 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 time argument + * @throws IllegalArgumentException if time less than zero + * @see #getKeepAliveTime + */ + public void setKeepAliveTime(long time, TimeUnit unit) { + if (time < 0) + throw new IllegalArgumentException(); + this.keepAliveTime = unit.toNanos(time); + } + + /** + * Returns the thread keep-alive time, which is the amount of time + * which 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); + } + + /* Statistics */ + + /** + * Returns the current number of threads in the pool. + * + * @return the number of threads + */ + public int getPoolSize() { + return poolSize; + } + + /** + * 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.isActive()) + ++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 been + * scheduled for 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 getTaskCount() { + final ReentrantLock mainLock = this.mainLock; + mainLock.lock(); + try { + long n = completedTaskCount; + for (Worker w : workers) { + n += w.completedTasks; + if (w.isActive()) + ++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(); + } + } + + /** + * Method invoked prior to executing the given Runnable in the + * given thread. This method is invoked by thread <tt>t</tt> that + * will execute task <tt>r</tt>, and may be used to re-initialize + * ThreadLocals, or to perform logging. Note: To properly nest + * multiple overridings, subclasses should generally invoke + * <tt>super.beforeExecute</tt> at the end of this method. + * + * @param t the thread that will run task 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 exception + * that caused execution to terminate abruptly. Note: To properly + * nest multiple overridings, subclasses should generally invoke + * <tt>super.afterExecute</tt> at the beginning of this method. + * + * @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 + * <tt>super.terminated</tt> within this method. + */ + protected void terminated() { } + + /** + * A handler for rejected tasks that runs the rejected task + * directly in the calling thread of the <tt>execute</tt> method, + * unless the executor has been shut down, in which case the task + * is discarded. + */ + public static class CallerRunsPolicy implements RejectedExecutionHandler { + /** + * Creates a <tt>CallerRunsPolicy</tt>. + */ + 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 + * <tt>RejectedExecutionException</tt>. + */ + public static class AbortPolicy implements RejectedExecutionHandler { + /** + * Creates an <tt>AbortPolicy</tt>. + */ + 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(); + } + } + + /** + * A handler for rejected tasks that silently discards the + * rejected task. + */ + public static class DiscardPolicy implements RejectedExecutionHandler { + /** + * Creates a <tt>DiscardPolicy</tt>. + */ + 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 <tt>execute</tt>, unless the executor + * is shut down, in which case the task is discarded. + */ + public static class DiscardOldestPolicy implements RejectedExecutionHandler { + /** + * Creates a <tt>DiscardOldestPolicy</tt> 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 --git a/concurrent/src/main/java/java/util/concurrent/TimeUnit.java b/concurrent/src/main/java/java/util/concurrent/TimeUnit.java new file mode 100644 index 0000000..b186aeb --- /dev/null +++ b/concurrent/src/main/java/java/util/concurrent/TimeUnit.java @@ -0,0 +1,238 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent; + +/** + * A <tt>TimeUnit</tt> represents time durations at a given unit of + * granularity and provides utility methods to convert across units, + * and to perform timing and delay operations in these units. A + * <tt>TimeUnit</tt> does not maintain time information, but only + * helps organize and use time representations that may be maintained + * separately across various contexts. + * + * <p>A <tt>TimeUnit</tt> is mainly used to inform time-based methods + * how a given timing parameter should be interpreted. For example, + * the following code will timeout in 50 milliseconds if the {@link + * java.util.concurrent.locks.Lock lock} is not available: + * + * <pre> Lock lock = ...; + * if ( lock.tryLock(50L, TimeUnit.MILLISECONDS) ) ... + * </pre> + * while this code will timeout in 50 seconds: + * <pre> + * Lock lock = ...; + * if ( lock.tryLock(50L, TimeUnit.SECONDS) ) ... + * </pre> + * + * Note however, that there is no guarantee that a particular timeout + * implementation will be able to notice the passage of time at the + * same granularity as the given <tt>TimeUnit</tt>. + * + * @since 1.5 + * @author Doug Lea + */ +public enum TimeUnit { + /** TimeUnit which represents one nanosecond. */ + NANOSECONDS(0), + /** TimeUnit which represents one microsecond. */ + MICROSECONDS(1), + /** TimeUnit which represents one millisecond. */ + MILLISECONDS(2), + /** TimeUnit which represents one second. */ + SECONDS(3); + + /** the index of this unit */ + private final int index; + + /** Internal constructor */ + TimeUnit(int index) { + this.index = index; + } + + /** Lookup table for conversion factors */ + private static final int[] multipliers = { + 1, + 1000, + 1000 * 1000, + 1000 * 1000 * 1000 + }; + + /** + * Lookup table to check saturation. Note that because we are + * dividing these down, we don't have to deal with asymmetry of + * MIN/MAX values. + */ + private static final long[] overflows = { + 0, // unused + Long.MAX_VALUE / 1000, + Long.MAX_VALUE / (1000 * 1000), + Long.MAX_VALUE / (1000 * 1000 * 1000) + }; + + /** + * Perform conversion based on given delta representing the + * difference between units + * @param delta the difference in index values of source and target units + * @param duration the duration + * @return converted duration or saturated value + */ + private static long doConvert(int delta, long duration) { + if (delta == 0) + return duration; + if (delta < 0) + return duration / multipliers[-delta]; + if (duration > overflows[delta]) + return Long.MAX_VALUE; + if (duration < -overflows[delta]) + return Long.MIN_VALUE; + return duration * multipliers[delta]; + } + + /** + * Convert the given time duration in the given unit to this + * unit. Conversions from finer to coarser granularities + * truncate, so lose precision. For example converting + * <tt>999</tt> milliseconds to seconds results in + * <tt>0</tt>. Conversions from coarser to finer granularities + * with arguments that would numerically overflow saturate to + * <tt>Long.MIN_VALUE</tt> if negative or <tt>Long.MAX_VALUE</tt> + * if positive. + * + * @param duration the time duration in the given <tt>unit</tt> + * @param unit the unit of the <tt>duration</tt> argument + * @return the converted duration in this unit, + * or <tt>Long.MIN_VALUE</tt> if conversion would negatively + * overflow, or <tt>Long.MAX_VALUE</tt> if it would positively overflow. + */ + public long convert(long duration, TimeUnit unit) { + return doConvert(unit.index - index, duration); + } + + /** + * Equivalent to <tt>NANOSECONDS.convert(duration, this)</tt>. + * @param duration the duration + * @return the converted duration, + * or <tt>Long.MIN_VALUE</tt> if conversion would negatively + * overflow, or <tt>Long.MAX_VALUE</tt> if it would positively overflow. + * @see #convert + */ + public long toNanos(long duration) { + return doConvert(index, duration); + } + + /** + * Equivalent to <tt>MICROSECONDS.convert(duration, this)</tt>. + * @param duration the duration + * @return the converted duration, + * or <tt>Long.MIN_VALUE</tt> if conversion would negatively + * overflow, or <tt>Long.MAX_VALUE</tt> if it would positively overflow. + * @see #convert + */ + public long toMicros(long duration) { + return doConvert(index - MICROSECONDS.index, duration); + } + + /** + * Equivalent to <tt>MILLISECONDS.convert(duration, this)</tt>. + * @param duration the duration + * @return the converted duration, + * or <tt>Long.MIN_VALUE</tt> if conversion would negatively + * overflow, or <tt>Long.MAX_VALUE</tt> if it would positively overflow. + * @see #convert + */ + public long toMillis(long duration) { + return doConvert(index - MILLISECONDS.index, duration); + } + + /** + * Equivalent to <tt>SECONDS.convert(duration, this)</tt>. + * @param duration the duration + * @return the converted duration. + * @see #convert + */ + public long toSeconds(long duration) { + return doConvert(index - SECONDS.index, duration); + } + + + /** + * Utility method to compute the excess-nanosecond argument to + * wait, sleep, join. + */ + private int excessNanos(long time, long ms) { + if (this == NANOSECONDS) + return (int) (time - (ms * 1000 * 1000)); + if (this == MICROSECONDS) + return (int) ((time * 1000) - (ms * 1000 * 1000)); + return 0; + } + + /** + * Perform a timed <tt>Object.wait</tt> using this time unit. + * This is a convenience method that converts timeout arguments + * into the form required by the <tt>Object.wait</tt> method. + * + * <p>For example, you could implement a blocking <tt>poll</tt> + * method (see {@link BlockingQueue#poll BlockingQueue.poll}) + * using: + * + * <pre> public synchronized Object poll(long timeout, TimeUnit unit) throws InterruptedException { + * while (empty) { + * unit.timedWait(this, timeout); + * ... + * } + * }</pre> + * + * @param obj the object to wait on + * @param timeout the maximum time to wait. + * @throws InterruptedException if interrupted while waiting. + * @see Object#wait(long, int) + */ + public void timedWait(Object obj, long timeout) + throws InterruptedException { + if (timeout > 0) { + long ms = toMillis(timeout); + int ns = excessNanos(timeout, ms); + obj.wait(ms, ns); + } + } + + /** + * Perform a timed <tt>Thread.join</tt> using this time unit. + * This is a convenience method that converts time arguments into the + * form required by the <tt>Thread.join</tt> method. + * @param thread the thread to wait for + * @param timeout the maximum time to wait + * @throws InterruptedException if interrupted while waiting. + * @see Thread#join(long, int) + */ + public void timedJoin(Thread thread, long timeout) + throws InterruptedException { + if (timeout > 0) { + long ms = toMillis(timeout); + int ns = excessNanos(timeout, ms); + thread.join(ms, ns); + } + } + + /** + * Perform a <tt>Thread.sleep</tt> using this unit. + * This is a convenience method that converts time arguments into the + * form required by the <tt>Thread.sleep</tt> method. + * @param timeout the minimum time to sleep + * @throws InterruptedException if interrupted while sleeping. + * @see Thread#sleep + */ + public void sleep(long timeout) throws InterruptedException { + if (timeout > 0) { + long ms = toMillis(timeout); + int ns = excessNanos(timeout, ms); + Thread.sleep(ms, ns); + } + } + +} diff --git a/concurrent/src/main/java/java/util/concurrent/TimeoutException.java b/concurrent/src/main/java/java/util/concurrent/TimeoutException.java new file mode 100644 index 0000000..8b84f28 --- /dev/null +++ b/concurrent/src/main/java/java/util/concurrent/TimeoutException.java @@ -0,0 +1,38 @@ +/* + * 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/licenses/publicdomain + */ + +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 <tt>TimeoutException</tt> should be + * declared and thrown. + * + * @since 1.5 + * @author Doug Lea + */ +public class TimeoutException extends Exception { + private static final long serialVersionUID = 1900926677490660714L; + + /** + * Constructs a <tt>TimeoutException</tt> with no specified detail + * message. + */ + public TimeoutException() {} + + /** + * Constructs a <tt>TimeoutException</tt> with the specified detail + * message. + * + * @param message the detail message + */ + public TimeoutException(String message) { + super(message); + } +} diff --git a/concurrent/src/main/java/java/util/concurrent/atomic/AtomicBoolean.java b/concurrent/src/main/java/java/util/concurrent/atomic/AtomicBoolean.java new file mode 100644 index 0000000..5b9b556 --- /dev/null +++ b/concurrent/src/main/java/java/util/concurrent/atomic/AtomicBoolean.java @@ -0,0 +1,127 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent.atomic; +import sun.misc.Unsafe; + +/** + * A <tt>boolean</tt> value that may be updated atomically. See the + * {@link java.util.concurrent.atomic} package specification for + * description of the properties of atomic variables. An + * <tt>AtomicBoolean</tt> is used in applications such as atomically + * updated flags, and cannot be used as a replacement for a + * {@link java.lang.Boolean}. + * + * @since 1.5 + * @author Doug Lea + */ +public class AtomicBoolean implements java.io.Serializable { + private static final long serialVersionUID = 4654671469794556979L; + + // setup to use Unsafe.compareAndSwapInt for updates + // BEGIN android-changed + private static final Unsafe unsafe = UnsafeAccess.THE_ONE; + // END android-changed + + private static final long valueOffset; + + static { + try { + valueOffset = unsafe.objectFieldOffset + (AtomicBoolean.class.getDeclaredField("value")); + } catch (Exception ex) { throw new Error(ex); } + } + + private volatile int value; + + /** + * Creates a new <tt>AtomicBoolean</tt> with the given initial value. + * + * @param initialValue the initial value + */ + public AtomicBoolean(boolean initialValue) { + value = initialValue ? 1 : 0; + } + + /** + * Creates a new <tt>AtomicBoolean</tt> with initial value <tt>false</tt>. + */ + public AtomicBoolean() { + } + + /** + * Returns the current value. + * + * @return the current value + */ + public final boolean get() { + return value != 0; + } + + /** + * Atomically sets the value to the given update value if the + * current value is equal to the expected value. Any given + * invocation of this operation may fail (return + * <tt>false</tt>) spuriously, but repeated invocation when + * the current value holds the expected value and no other thread + * is also attempting to set the value will eventually succeed. + * + * @param expect the expected value + * @param update the new value + * @return true if successful + */ + public final boolean compareAndSet(boolean expect, boolean update) { + int e = expect ? 1 : 0; + int u = update ? 1 : 0; + return unsafe.compareAndSwapInt(this, valueOffset, e, u); + } + + /** + * Atomically set the value to the given updated value + * if the current value <tt>==</tt> the expected value. + * May fail spuriously. + * @param expect the expected value + * @param update the new value + * @return true if successful. + */ + public boolean weakCompareAndSet(boolean expect, boolean update) { + int e = expect ? 1 : 0; + int u = update ? 1 : 0; + return unsafe.compareAndSwapInt(this, valueOffset, e, u); + } + + /** + * Unconditionally sets to the given value. + * + * @param newValue the new value + */ + public final void set(boolean newValue) { + value = newValue ? 1 : 0; + } + + /** + * Sets to the given value and returns the previous value. + * + * @param newValue the new value + * @return the previous value + */ + public final boolean getAndSet(boolean newValue) { + for (;;) { + boolean current = get(); + if (compareAndSet(current, newValue)) + return current; + } + } + + /** + * Returns the String representation of the current value. + * @return the String representation of the current value. + */ + public String toString() { + return Boolean.toString(get()); + } + +} diff --git a/concurrent/src/main/java/java/util/concurrent/atomic/AtomicInteger.java b/concurrent/src/main/java/java/util/concurrent/atomic/AtomicInteger.java new file mode 100644 index 0000000..2b9d15c --- /dev/null +++ b/concurrent/src/main/java/java/util/concurrent/atomic/AtomicInteger.java @@ -0,0 +1,223 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent.atomic; +import sun.misc.Unsafe; + +/** + * An <tt>int</tt> value that may be updated atomically. See the + * {@link java.util.concurrent.atomic} package specification for + * description of the properties of atomic variables. An + * <tt>AtomicInteger</tt> is used in applications such as atomically + * incremented counters, and cannot be used as a replacement for an + * {@link java.lang.Integer}. However, this class does extend + * <tt>Number</tt> to allow uniform access by tools and utilities that + * deal with numerically-based classes. + * + * + * @since 1.5 + * @author Doug Lea +*/ +public class AtomicInteger extends Number implements java.io.Serializable { + private static final long serialVersionUID = 6214790243416807050L; + + // setup to use Unsafe.compareAndSwapInt for updates + // BEGIN android-changed + private static final Unsafe unsafe = UnsafeAccess.THE_ONE; + // END android-changed + private static final long valueOffset; + + static { + try { + valueOffset = unsafe.objectFieldOffset + (AtomicInteger.class.getDeclaredField("value")); + } catch(Exception ex) { throw new Error(ex); } + } + + private volatile int value; + + /** + * Create a new AtomicInteger with the given initial value. + * + * @param initialValue the initial value + */ + public AtomicInteger(int initialValue) { + value = initialValue; + } + + /** + * Create a new AtomicInteger with initial value <tt>0</tt>. + */ + public AtomicInteger() { + } + + /** + * Get the current value. + * + * @return the current value + */ + public final int get() { + return value; + } + + /** + * Set to the given value. + * + * @param newValue the new value + */ + public final void set(int newValue) { + value = newValue; + } + + /** + * Set to the give value and return the old value. + * + * @param newValue the new value + * @return the previous value + */ + public final int getAndSet(int newValue) { + for (;;) { + int current = get(); + if (compareAndSet(current, newValue)) + return current; + } + } + + + /** + * Atomically set the value to the given updated value + * if the current value <tt>==</tt> the expected value. + * @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. + */ + public final boolean compareAndSet(int expect, int update) { + return unsafe.compareAndSwapInt(this, valueOffset, expect, update); + } + + /** + * Atomically set the value to the given updated value + * if the current value <tt>==</tt> the expected value. + * May fail spuriously. + * @param expect the expected value + * @param update the new value + * @return true if successful. + */ + public final boolean weakCompareAndSet(int expect, int update) { + return unsafe.compareAndSwapInt(this, valueOffset, expect, update); + } + + + /** + * Atomically increment by one the current value. + * @return the previous value + */ + public final int getAndIncrement() { + for (;;) { + int current = get(); + int next = current + 1; + if (compareAndSet(current, next)) + return current; + } + } + + + /** + * Atomically decrement by one the current value. + * @return the previous value + */ + public final int getAndDecrement() { + for (;;) { + int current = get(); + int next = current - 1; + if (compareAndSet(current, next)) + return current; + } + } + + + /** + * Atomically add the given value to current value. + * @param delta the value to add + * @return the previous value + */ + public final int getAndAdd(int delta) { + for (;;) { + int current = get(); + int next = current + delta; + if (compareAndSet(current, next)) + return current; + } + } + + /** + * Atomically increment by one the current value. + * @return the updated value + */ + public final int incrementAndGet() { + for (;;) { + int current = get(); + int next = current + 1; + if (compareAndSet(current, next)) + return next; + } + } + + /** + * Atomically decrement by one the current value. + * @return the updated value + */ + public final int decrementAndGet() { + for (;;) { + int current = get(); + int next = current - 1; + if (compareAndSet(current, next)) + return next; + } + } + + + /** + * Atomically add the given value to current value. + * @param delta the value to add + * @return the updated value + */ + public final int addAndGet(int delta) { + for (;;) { + int current = get(); + int next = current + delta; + if (compareAndSet(current, next)) + return next; + } + } + + /** + * Returns the String representation of the current value. + * @return the String representation of the current value. + */ + public String toString() { + return Integer.toString(get()); + } + + + public int intValue() { + return get(); + } + + public long longValue() { + return (long)get(); + } + + public float floatValue() { + return (float)get(); + } + + public double doubleValue() { + return (double)get(); + } + +} diff --git a/concurrent/src/main/java/java/util/concurrent/atomic/AtomicIntegerArray.java b/concurrent/src/main/java/java/util/concurrent/atomic/AtomicIntegerArray.java new file mode 100644 index 0000000..5c49038 --- /dev/null +++ b/concurrent/src/main/java/java/util/concurrent/atomic/AtomicIntegerArray.java @@ -0,0 +1,246 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent.atomic; +import sun.misc.Unsafe; +import java.util.*; + +/** + * An <tt>int</tt> array in which elements may be updated atomically. + * See the {@link java.util.concurrent.atomic} package + * specification for description of the properties of atomic + * variables. + * @since 1.5 + * @author Doug Lea + */ +public class AtomicIntegerArray implements java.io.Serializable { + private static final long serialVersionUID = 2862133569453604235L; + + // setup to use Unsafe.compareAndSwapInt for updates + // BEGIN android-changed + private static final Unsafe unsafe = UnsafeAccess.THE_ONE; + // END android-changed + + private static final int base = unsafe.arrayBaseOffset(int[].class); + private static final int scale = unsafe.arrayIndexScale(int[].class); + private final int[] array; + + private long rawIndex(int i) { + if (i < 0 || i >= array.length) + throw new IndexOutOfBoundsException("index " + i); + return base + i * scale; + } + + /** + * Create a new AtomicIntegerArray of given length. + * + * @param length the length of the array + */ + public AtomicIntegerArray(int length) { + array = new int[length]; + // must perform at least one volatile write to conform to JMM + if (length > 0) + unsafe.putIntVolatile(array, rawIndex(0), 0); + } + + /** + * Create a new AtomicIntegerArray with the same length as, and + * all elements copied from, the given array. + * + * @param array the array to copy elements from + * @throws NullPointerException if array is null + */ + public AtomicIntegerArray(int[] array) { + if (array == null) + throw new NullPointerException(); + int length = array.length; + this.array = new int[length]; + if (length > 0) { + int last = length-1; + for (int i = 0; i < last; ++i) + this.array[i] = array[i]; + // Do the last write as volatile + unsafe.putIntVolatile(this.array, rawIndex(last), array[last]); + } + } + + /** + * Returns the length of the array. + * + * @return the length of the array + */ + public final int length() { + return array.length; + } + + /** + * Get the current value at position <tt>i</tt>. + * + * @param i the index + * @return the current value + */ + public final int get(int i) { + return unsafe.getIntVolatile(array, rawIndex(i)); + } + + /** + * Set the element at position <tt>i</tt> to the given value. + * + * @param i the index + * @param newValue the new value + */ + public final void set(int i, int newValue) { + unsafe.putIntVolatile(array, rawIndex(i), newValue); + } + + /** + * Set the element at position <tt>i</tt> to the given value and return the + * old value. + * + * @param i the index + * @param newValue the new value + * @return the previous value + */ + public final int getAndSet(int i, int newValue) { + while (true) { + int current = get(i); + if (compareAndSet(i, current, newValue)) + return current; + } + } + + /** + * Atomically set the value to the given updated value + * if the current value <tt>==</tt> the expected value. + * + * @param i the index + * @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. + */ + public final boolean compareAndSet(int i, int expect, int update) { + return unsafe.compareAndSwapInt(array, rawIndex(i), + expect, update); + } + + /** + * Atomically set the value to the given updated value + * if the current value <tt>==</tt> the expected value. + * May fail spuriously. + * + * @param i the index + * @param expect the expected value + * @param update the new value + * @return true if successful. + */ + public final boolean weakCompareAndSet(int i, int expect, int update) { + return compareAndSet(i, expect, update); + } + + /** + * Atomically increment by one the element at index <tt>i</tt>. + * + * @param i the index + * @return the previous value; + */ + public final int getAndIncrement(int i) { + while (true) { + int current = get(i); + int next = current + 1; + if (compareAndSet(i, current, next)) + return current; + } + } + + /** + * Atomically decrement by one the element at index <tt>i</tt>. + * + * @param i the index + * @return the previous value; + */ + public final int getAndDecrement(int i) { + while (true) { + int current = get(i); + int next = current - 1; + if (compareAndSet(i, current, next)) + return current; + } + } + + /** + * Atomically add the given value to element at index <tt>i</tt>. + * + * @param i the index + * @param delta the value to add + * @return the previous value; + */ + public final int getAndAdd(int i, int delta) { + while (true) { + int current = get(i); + int next = current + delta; + if (compareAndSet(i, current, next)) + return current; + } + } + + /** + * Atomically increment by one the element at index <tt>i</tt>. + * + * @param i the index + * @return the updated value; + */ + public final int incrementAndGet(int i) { + while (true) { + int current = get(i); + int next = current + 1; + if (compareAndSet(i, current, next)) + return next; + } + } + + /** + * Atomically decrement by one the element at index <tt>i</tt>. + * + * @param i the index + * @return the updated value; + */ + public final int decrementAndGet(int i) { + while (true) { + int current = get(i); + int next = current - 1; + if (compareAndSet(i, current, next)) + return next; + } + } + + /** + * Atomically add the given value to element at index <tt>i</tt>. + * + * @param i the index + * @param delta the value to add + * @return the updated value; + */ + public final int addAndGet(int i, int delta) { + while (true) { + int current = get(i); + int next = current + delta; + if (compareAndSet(i, current, next)) + return next; + } + } + + /** + * Returns the String representation of the current values of array. + * @return the String representation of the current values of array. + */ + public String toString() { + if (array.length > 0) // force volatile read + get(0); + return Arrays.toString(array); + } + +} diff --git a/concurrent/src/main/java/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java b/concurrent/src/main/java/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java new file mode 100644 index 0000000..e3a0515 --- /dev/null +++ b/concurrent/src/main/java/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java @@ -0,0 +1,261 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent.atomic; +import sun.misc.Unsafe; +import java.lang.reflect.*; + +/** + * A reflection-based utility that enables atomic updates to + * designated <tt>volatile int</tt> fields of designated classes. + * This class is designed for use in atomic data structures in which + * several fields of the same node are independently subject to atomic + * updates. + * + * <p> Note that the guarantees of the <tt>compareAndSet</tt> method + * in this class are weaker than in other atomic classes. Because this + * class cannot ensure that all uses of the field are appropriate for + * purposes of atomic access, it can guarantee atomicity and volatile + * semantics only with respect to other invocations of + * <tt>compareAndSet</tt> and <tt>set</tt>. + * @since 1.5 + * @author Doug Lea + * @param <T> The type of the object holding the updatable field + */ +public abstract class AtomicIntegerFieldUpdater<T> { + /** + * Creates an updater for objects with the given field. The Class + * argument is needed to check that reflective types and generic + * types match. + * @param tclass the class of the objects holding the field + * @param fieldName the name of the field to be updated. + * @return the updater + * @throws IllegalArgumentException if the field is not a + * volatile integer type. + * @throws RuntimeException with a nested reflection-based + * exception if the class does not hold field or is the wrong type. + */ + public static <U> AtomicIntegerFieldUpdater<U> newUpdater(Class<U> tclass, String fieldName) { + return new AtomicIntegerFieldUpdaterImpl<U>(tclass, fieldName); + } + + /** + * Protected do-nothing constructor for use by subclasses. + */ + protected AtomicIntegerFieldUpdater() { + } + + /** + * Atomically set the value of the field of the given object managed + * by this Updater to the given updated value if the current value + * <tt>==</tt> the expected value. This method is guaranteed to be + * atomic with respect to other calls to <tt>compareAndSet</tt> and + * <tt>set</tt>, but not necessarily with respect to other + * changes in the field. + * @param obj An object whose field to conditionally set + * @param expect the expected value + * @param update the new value + * @return true if successful. + * @throws ClassCastException if <tt>obj</tt> is not an instance + * of the class possessing the field established in the constructor. + */ + + public abstract boolean compareAndSet(T obj, int expect, int update); + + /** + * Atomically set the value of the field of the given object managed + * by this Updater to the given updated value if the current value + * <tt>==</tt> the expected value. This method is guaranteed to be + * atomic with respect to other calls to <tt>compareAndSet</tt> and + * <tt>set</tt>, but not necessarily with respect to other + * changes in the field, and may fail spuriously. + * @param obj An object whose field to conditionally set + * @param expect the expected value + * @param update the new value + * @return true if successful. + * @throws ClassCastException if <tt>obj</tt> is not an instance + * of the class possessing the field established in the constructor. + */ + + public abstract boolean weakCompareAndSet(T obj, int expect, int update); + + /** + * Set the field of the given object managed by this updater. This + * operation is guaranteed to act as a volatile store with respect + * to subsequent invocations of <tt>compareAndSet</tt>. + * @param obj An object whose field to set + * @param newValue the new value + */ + public abstract void set(T obj, int newValue); + + /** + * Get the current value held in the field by the given object. + * @param obj An object whose field to get + * @return the current value + */ + public abstract int get(T obj); + + /** + * Set to the given value and return the old value. + * + * @param obj An object whose field to get and set + * @param newValue the new value + * @return the previous value + */ + public int getAndSet(T obj, int newValue) { + for (;;) { + int current = get(obj); + if (compareAndSet(obj, current, newValue)) + return current; + } + } + + /** + * Atomically increment by one the current value. + * @param obj An object whose field to get and set + * @return the previous value; + */ + public int getAndIncrement(T obj) { + for (;;) { + int current = get(obj); + int next = current + 1; + if (compareAndSet(obj, current, next)) + return current; + } + } + + + /** + * Atomically decrement by one the current value. + * @param obj An object whose field to get and set + * @return the previous value; + */ + public int getAndDecrement(T obj) { + for (;;) { + int current = get(obj); + int next = current - 1; + if (compareAndSet(obj, current, next)) + return current; + } + } + + + /** + * Atomically add the given value to current value. + * @param obj An object whose field to get and set + * @param delta the value to add + * @return the previous value; + */ + public int getAndAdd(T obj, int delta) { + for (;;) { + int current = get(obj); + int next = current + delta; + if (compareAndSet(obj, current, next)) + return current; + } + } + + /** + * Atomically increment by one the current value. + * @param obj An object whose field to get and set + * @return the updated value; + */ + public int incrementAndGet(T obj) { + for (;;) { + int current = get(obj); + int next = current + 1; + if (compareAndSet(obj, current, next)) + return next; + } + } + + + /** + * Atomically decrement by one the current value. + * @param obj An object whose field to get and set + * @return the updated value; + */ + public int decrementAndGet(T obj) { + for (;;) { + int current = get(obj); + int next = current - 1; + if (compareAndSet(obj, current, next)) + return next; + } + } + + + /** + * Atomically add the given value to current value. + * @param obj An object whose field to get and set + * @param delta the value to add + * @return the updated value; + */ + public int addAndGet(T obj, int delta) { + for (;;) { + int current = get(obj); + int next = current + delta; + if (compareAndSet(obj, current, next)) + return next; + } + } + + /** + * Standard hotspot implementation using intrinsics + */ + private static class AtomicIntegerFieldUpdaterImpl<T> extends AtomicIntegerFieldUpdater<T> { + // BEGIN android-changed + private static final Unsafe unsafe = UnsafeAccess.THE_ONE; + // END android-changed + + private final long offset; + private final Class<T> tclass; + + AtomicIntegerFieldUpdaterImpl(Class<T> tclass, String fieldName) { + Field field = null; + try { + field = tclass.getDeclaredField(fieldName); + } catch(Exception ex) { + throw new RuntimeException(ex); + } + + Class fieldt = field.getType(); + if (fieldt != int.class) + throw new IllegalArgumentException("Must be integer type"); + + if (!Modifier.isVolatile(field.getModifiers())) + throw new IllegalArgumentException("Must be volatile type"); + + this.tclass = tclass; + offset = unsafe.objectFieldOffset(field); + } + + public boolean compareAndSet(T obj, int expect, int update) { + if (!tclass.isInstance(obj)) + throw new ClassCastException(); + return unsafe.compareAndSwapInt(obj, offset, expect, update); + } + + public boolean weakCompareAndSet(T obj, int expect, int update) { + if (!tclass.isInstance(obj)) + throw new ClassCastException(); + return unsafe.compareAndSwapInt(obj, offset, expect, update); + } + + public void set(T obj, int newValue) { + if (!tclass.isInstance(obj)) + throw new ClassCastException(); + unsafe.putIntVolatile(obj, offset, newValue); + } + + public final int get(T obj) { + if (!tclass.isInstance(obj)) + throw new ClassCastException(); + return unsafe.getIntVolatile(obj, offset); + } + } +} + diff --git a/concurrent/src/main/java/java/util/concurrent/atomic/AtomicLong.java b/concurrent/src/main/java/java/util/concurrent/atomic/AtomicLong.java new file mode 100644 index 0000000..ca45984 --- /dev/null +++ b/concurrent/src/main/java/java/util/concurrent/atomic/AtomicLong.java @@ -0,0 +1,235 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent.atomic; +import sun.misc.Unsafe; + +/** + * A <tt>long</tt> value that may be updated atomically. See the + * {@link java.util.concurrent.atomic} package specification for + * description of the properties of atomic variables. An + * <tt>AtomicLong</tt> is used in applications such as atomically + * incremented sequence numbers, and cannot be used as a replacement + * for a {@link java.lang.Long}. However, this class does extend + * <tt>Number</tt> to allow uniform access by tools and utilities that + * deal with numerically-based classes. + * + * @since 1.5 + * @author Doug Lea + */ +public class AtomicLong extends Number implements java.io.Serializable { + private static final long serialVersionUID = 1927816293512124184L; + + // setup to use Unsafe.compareAndSwapLong for updates + // BEGIN android-changed + private static final Unsafe unsafe = UnsafeAccess.THE_ONE; + // END android-changed + + private static final long valueOffset; + + /** + * Record whether the underlying JVM supports lockless + * CompareAndSet for longs. While the unsafe.CompareAndSetLong + * method works in either case, some constructions should be + * handled at Java level to avoid locking user-visible locks. + */ + static final boolean VM_SUPPORTS_LONG_CAS = VMSupportsCS8(); + + /** + * Returns whether underlying JVM supports lockless CompareAndSet + * for longs. Called only once and cached in VM_SUPPORTS_LONG_CAS. + */ + private static native boolean VMSupportsCS8(); + + static { + try { + valueOffset = unsafe.objectFieldOffset + (AtomicLong.class.getDeclaredField("value")); + } catch(Exception ex) { throw new Error(ex); } + } + + private volatile long value; + + /** + * Create a new AtomicLong with the given initial value. + * + * @param initialValue the initial value + */ + public AtomicLong(long initialValue) { + value = initialValue; + } + + /** + * Create a new AtomicLong with initial value <tt>0</tt>. + */ + public AtomicLong() { + } + + /** + * Get the current value. + * + * @return the current value + */ + public final long get() { + return value; + } + + /** + * Set to the given value. + * + * @param newValue the new value + */ + public final void set(long newValue) { + value = newValue; + } + + /** + * Set to the give value and return the old value. + * + * @param newValue the new value + * @return the previous value + */ + public final long getAndSet(long newValue) { + while (true) { + long current = get(); + if (compareAndSet(current, newValue)) + return current; + } + } + + /** + * Atomically set the value to the given updated value + * if the current value <tt>==</tt> the expected value. + * @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. + */ + public final boolean compareAndSet(long expect, long update) { + return unsafe.compareAndSwapLong(this, valueOffset, expect, update); + } + + /** + * Atomically set the value to the given updated value + * if the current value <tt>==</tt> the expected value. + * May fail spuriously. + * @param expect the expected value + * @param update the new value + * @return true if successful. + */ + public final boolean weakCompareAndSet(long expect, long update) { + return unsafe.compareAndSwapLong(this, valueOffset, expect, update); + } + + /** + * Atomically increment by one the current value. + * @return the previous value + */ + public final long getAndIncrement() { + while (true) { + long current = get(); + long next = current + 1; + if (compareAndSet(current, next)) + return current; + } + } + + + /** + * Atomically decrement by one the current value. + * @return the previous value + */ + public final long getAndDecrement() { + while (true) { + long current = get(); + long next = current - 1; + if (compareAndSet(current, next)) + return current; + } + } + + + /** + * Atomically add the given value to current value. + * @param delta the value to add + * @return the previous value + */ + public final long getAndAdd(long delta) { + while (true) { + long current = get(); + long next = current + delta; + if (compareAndSet(current, next)) + return current; + } + } + + /** + * Atomically increment by one the current value. + * @return the updated value + */ + public final long incrementAndGet() { + for (;;) { + long current = get(); + long next = current + 1; + if (compareAndSet(current, next)) + return next; + } + } + + /** + * Atomically decrement by one the current value. + * @return the updated value + */ + public final long decrementAndGet() { + for (;;) { + long current = get(); + long next = current - 1; + if (compareAndSet(current, next)) + return next; + } + } + + + /** + * Atomically add the given value to current value. + * @param delta the value to add + * @return the updated value + */ + public final long addAndGet(long delta) { + for (;;) { + long current = get(); + long next = current + delta; + if (compareAndSet(current, next)) + return next; + } + } + + /** + * Returns the String representation of the current value. + * @return the String representation of the current value. + */ + public String toString() { + return Long.toString(get()); + } + + + public int intValue() { + return (int)get(); + } + + public long longValue() { + return (long)get(); + } + + public float floatValue() { + return (float)get(); + } + + public double doubleValue() { + return (double)get(); + } + +} diff --git a/concurrent/src/main/java/java/util/concurrent/atomic/AtomicLongArray.java b/concurrent/src/main/java/java/util/concurrent/atomic/AtomicLongArray.java new file mode 100644 index 0000000..b9201b2 --- /dev/null +++ b/concurrent/src/main/java/java/util/concurrent/atomic/AtomicLongArray.java @@ -0,0 +1,243 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent.atomic; +import sun.misc.Unsafe; +import java.util.*; + +/** + * A <tt>long</tt> array in which elements may be updated atomically. + * See the {@link java.util.concurrent.atomic} package specification + * for description of the properties of atomic variables. + * @since 1.5 + * @author Doug Lea + */ +public class AtomicLongArray implements java.io.Serializable { + private static final long serialVersionUID = -2308431214976778248L; + + // setup to use Unsafe.compareAndSwapInt for updates + // BEGIN android-changed + private static final Unsafe unsafe = UnsafeAccess.THE_ONE; + // END android-changed + + private static final int base = unsafe.arrayBaseOffset(long[].class); + private static final int scale = unsafe.arrayIndexScale(long[].class); + private final long[] array; + + private long rawIndex(int i) { + if (i < 0 || i >= array.length) + throw new IndexOutOfBoundsException("index " + i); + return base + i * scale; + } + + /** + * Create a new AtomicLongArray of given length. + * @param length the length of the array + */ + public AtomicLongArray(int length) { + array = new long[length]; + // must perform at least one volatile write to conform to JMM + if (length > 0) + unsafe.putLongVolatile(array, rawIndex(0), 0); + } + + /** + * Create a new AtomicLongArray with the same length as, and + * all elements copied from, the given array. + * + * @param array the array to copy elements from + * @throws NullPointerException if array is null + */ + public AtomicLongArray(long[] array) { + if (array == null) + throw new NullPointerException(); + int length = array.length; + this.array = new long[length]; + if (length > 0) { + int last = length-1; + for (int i = 0; i < last; ++i) + this.array[i] = array[i]; + // Do the last write as volatile + unsafe.putLongVolatile(this.array, rawIndex(last), array[last]); + } + } + + /** + * Returns the length of the array. + * + * @return the length of the array + */ + public final int length() { + return array.length; + } + + /** + * Get the current value at position <tt>i</tt>. + * + * @param i the index + * @return the current value + */ + public final long get(int i) { + return unsafe.getLongVolatile(array, rawIndex(i)); + } + + /** + * Set the element at position <tt>i</tt> to the given value. + * + * @param i the index + * @param newValue the new value + */ + public final void set(int i, long newValue) { + unsafe.putLongVolatile(array, rawIndex(i), newValue); + } + + /** + * Set the element at position <tt>i</tt> to the given value and return the + * old value. + * + * @param i the index + * @param newValue the new value + * @return the previous value + */ + public final long getAndSet(int i, long newValue) { + while (true) { + long current = get(i); + if (compareAndSet(i, current, newValue)) + return current; + } + } + + /** + * Atomically set the value to the given updated value + * if the current value <tt>==</tt> the expected value. + * @param i the index + * @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. + */ + public final boolean compareAndSet(int i, long expect, long update) { + return unsafe.compareAndSwapLong(array, rawIndex(i), + expect, update); + } + + /** + * Atomically set the value to the given updated value + * if the current value <tt>==</tt> the expected value. + * May fail spuriously. + * @param i the index + * @param expect the expected value + * @param update the new value + * @return true if successful. + */ + public final boolean weakCompareAndSet(int i, long expect, long update) { + return compareAndSet(i, expect, update); + } + + /** + * Atomically increment by one the element at index <tt>i</tt>. + * + * @param i the index + * @return the previous value; + */ + public final long getAndIncrement(int i) { + while (true) { + long current = get(i); + long next = current + 1; + if (compareAndSet(i, current, next)) + return current; + } + } + + /** + * Atomically decrement by one the element at index <tt>i</tt>. + * + * @param i the index + * @return the previous value; + */ + public final long getAndDecrement(int i) { + while (true) { + long current = get(i); + long next = current - 1; + if (compareAndSet(i, current, next)) + return current; + } + } + + /** + * Atomically add the given value to element at index <tt>i</tt>. + * + * @param i the index + * @param delta the value to add + * @return the previous value; + */ + public final long getAndAdd(int i, long delta) { + while (true) { + long current = get(i); + long next = current + delta; + if (compareAndSet(i, current, next)) + return current; + } + } + + + /** + * Atomically increment the element at index <tt>i</tt>. + * + * @param i the index + * @return the updated value; + */ + public final long incrementAndGet(int i) { + while (true) { + long current = get(i); + long next = current + 1; + if (compareAndSet(i, current, next)) + return next; + } + } + + /** + * Atomically decrement the element at index <tt>i</tt>. + * + * @param i the index + * @return the updated value; + */ + public final long decrementAndGet(int i) { + while (true) { + long current = get(i); + long next = current - 1; + if (compareAndSet(i, current, next)) + return next; + } + } + + /** + * Atomically add the given value to element at index <tt>i</tt>. + * + * @param i the index + * @param delta the value to add + * @return the updated value; + */ + public long addAndGet(int i, long delta) { + while (true) { + long current = get(i); + long next = current + delta; + if (compareAndSet(i, current, next)) + return next; + } + } + + /** + * Returns the String representation of the current values of array. + * @return the String representation of the current values of array. + */ + public String toString() { + if (array.length > 0) // force volatile read + get(0); + return Arrays.toString(array); + } + +} diff --git a/concurrent/src/main/java/java/util/concurrent/atomic/AtomicLongFieldUpdater.java b/concurrent/src/main/java/java/util/concurrent/atomic/AtomicLongFieldUpdater.java new file mode 100644 index 0000000..ad5edd8 --- /dev/null +++ b/concurrent/src/main/java/java/util/concurrent/atomic/AtomicLongFieldUpdater.java @@ -0,0 +1,323 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent.atomic; +import sun.misc.Unsafe; +import java.lang.reflect.*; + +/** + * A reflection-based utility that enables atomic updates to + * designated <tt>volatile long</tt> fields of designated classes. + * This class is designed for use in atomic data structures in which + * several fields of the same node are independently subject to atomic + * updates. + * + * <p> Note that the guarantees of the <tt>compareAndSet</tt> method + * in this class are weaker than in other atomic classes. Because this + * class cannot ensure that all uses of the field are appropriate for + * purposes of atomic access, it can guarantee atomicity and volatile + * semantics only with respect to other invocations of + * <tt>compareAndSet</tt> and <tt>set</tt>. + * + * @since 1.5 + * @author Doug Lea + * @param <T> The type of the object holding the updatable field + */ +public abstract class AtomicLongFieldUpdater<T> { + /** + * Creates an updater for objects with the given field. The Class + * argument is needed to check that reflective types and generic + * types match. + * @param tclass the class of the objects holding the field + * @param fieldName the name of the field to be updated. + * @return the updater + * @throws IllegalArgumentException if the field is not a + * volatile long type. + * @throws RuntimeException with a nested reflection-based + * exception if the class does not hold field or is the wrong type. + */ + public static <U> AtomicLongFieldUpdater<U> newUpdater(Class<U> tclass, String fieldName) { + if (AtomicLong.VM_SUPPORTS_LONG_CAS) + return new CASUpdater<U>(tclass, fieldName); + else + return new LockedUpdater<U>(tclass, fieldName); + } + + /** + * Protected do-nothing constructor for use by subclasses. + */ + protected AtomicLongFieldUpdater() { + } + + /** + * Atomically set the value of the field of the given object managed + * by this Updater to the given updated value if the current value + * <tt>==</tt> the expected value. This method is guaranteed to be + * atomic with respect to other calls to <tt>compareAndSet</tt> and + * <tt>set</tt>, but not necessarily with respect to other + * changes in the field. + * @param obj An object whose field to conditionally set + * @param expect the expected value + * @param update the new value + * @return true if successful. + * @throws ClassCastException if <tt>obj</tt> is not an instance + * of the class possessing the field established in the constructor. + */ + + public abstract boolean compareAndSet(T obj, long expect, long update); + + /** + * Atomically set the value of the field of the given object managed + * by this Updater to the given updated value if the current value + * <tt>==</tt> the expected value. This method is guaranteed to be + * atomic with respect to other calls to <tt>compareAndSet</tt> and + * <tt>set</tt>, but not necessarily with respect to other + * changes in the field, and may fail spuriously. + * @param obj An object whose field to conditionally set + * @param expect the expected value + * @param update the new value + * @return true if successful. + * @throws ClassCastException if <tt>obj</tt> is not an instance + * of the class possessing the field established in the constructor. + */ + + public abstract boolean weakCompareAndSet(T obj, long expect, long update); + + /** + * Set the field of the given object managed by this updater. This + * operation is guaranteed to act as a volatile store with respect + * to subsequent invocations of <tt>compareAndSet</tt>. + * @param obj An object whose field to set + * @param newValue the new value + */ + public abstract void set(T obj, long newValue); + + /** + * Get the current value held in the field by the given object. + * @param obj An object whose field to get + * @return the current value + */ + public abstract long get(T obj); + + /** + * Set to the given value and return the old value. + * + * @param obj An object whose field to get and set + * @param newValue the new value + * @return the previous value + */ + public long getAndSet(T obj, long newValue) { + for (;;) { + long current = get(obj); + if (compareAndSet(obj, current, newValue)) + return current; + } + } + + /** + * Atomically increment by one the current value. + * @param obj An object whose field to get and set + * @return the previous value; + */ + public long getAndIncrement(T obj) { + for (;;) { + long current = get(obj); + long next = current + 1; + if (compareAndSet(obj, current, next)) + return current; + } + } + + + /** + * Atomically decrement by one the current value. + * @param obj An object whose field to get and set + * @return the previous value; + */ + public long getAndDecrement(T obj) { + for (;;) { + long current = get(obj); + long next = current - 1; + if (compareAndSet(obj, current, next)) + return current; + } + } + + + /** + * Atomically add the given value to current value. + * @param obj An object whose field to get and set + * @param delta the value to add + * @return the previous value; + */ + public long getAndAdd(T obj, long delta) { + for (;;) { + long current = get(obj); + long next = current + delta; + if (compareAndSet(obj, current, next)) + return current; + } + } + + /** + * Atomically increment by one the current value. + * @param obj An object whose field to get and set + * @return the updated value; + */ + public long incrementAndGet(T obj) { + for (;;) { + long current = get(obj); + long next = current + 1; + if (compareAndSet(obj, current, next)) + return next; + } + } + + + /** + * Atomically decrement by one the current value. + * @param obj An object whose field to get and set + * @return the updated value; + */ + public long decrementAndGet(T obj) { + for (;;) { + long current = get(obj); + long next = current - 1; + if (compareAndSet(obj, current, next)) + return next; + } + } + + + /** + * Atomically add the given value to current value. + * @param obj An object whose field to get and set + * @param delta the value to add + * @return the updated value; + */ + public long addAndGet(T obj, long delta) { + for (;;) { + long current = get(obj); + long next = current + delta; + if (compareAndSet(obj, current, next)) + return next; + } + } + + private static class CASUpdater<T> extends AtomicLongFieldUpdater<T> { + // BEGIN android-changed + private static final Unsafe unsafe = UnsafeAccess.THE_ONE; + // END android-changed + + private final long offset; + private final Class<T> tclass; + + CASUpdater(Class<T> tclass, String fieldName) { + Field field = null; + try { + field = tclass.getDeclaredField(fieldName); + } catch(Exception ex) { + throw new RuntimeException(ex); + } + + Class fieldt = field.getType(); + if (fieldt != long.class) + throw new IllegalArgumentException("Must be long type"); + + if (!Modifier.isVolatile(field.getModifiers())) + throw new IllegalArgumentException("Must be volatile type"); + + this.tclass = tclass; + offset = unsafe.objectFieldOffset(field); + } + + public boolean compareAndSet(T obj, long expect, long update) { + if (!tclass.isInstance(obj)) + throw new ClassCastException(); + return unsafe.compareAndSwapLong(obj, offset, expect, update); + } + + public boolean weakCompareAndSet(T obj, long expect, long update) { + if (!tclass.isInstance(obj)) + throw new ClassCastException(); + return unsafe.compareAndSwapLong(obj, offset, expect, update); + } + + public void set(T obj, long newValue) { + if (!tclass.isInstance(obj)) + throw new ClassCastException(); + unsafe.putLongVolatile(obj, offset, newValue); + } + + public long get(T obj) { + if (!tclass.isInstance(obj)) + throw new ClassCastException(); + return unsafe.getLongVolatile(obj, offset); + } + } + + + private static class LockedUpdater<T> extends AtomicLongFieldUpdater<T> { + // BEGIN android-changed + private static final Unsafe unsafe = UnsafeAccess.THE_ONE; + // END android-changed + + private final long offset; + private final Class<T> tclass; + + LockedUpdater(Class<T> tclass, String fieldName) { + Field field = null; + try { + field = tclass.getDeclaredField(fieldName); + } catch(Exception ex) { + throw new RuntimeException(ex); + } + + Class fieldt = field.getType(); + if (fieldt != long.class) + throw new IllegalArgumentException("Must be long type"); + + if (!Modifier.isVolatile(field.getModifiers())) + throw new IllegalArgumentException("Must be volatile type"); + + this.tclass = tclass; + offset = unsafe.objectFieldOffset(field); + } + + public boolean compareAndSet(T obj, long expect, long update) { + if (!tclass.isInstance(obj)) + throw new ClassCastException(); + synchronized(this) { + long v = unsafe.getLong(obj, offset); + if (v != expect) + return false; + unsafe.putLong(obj, offset, update); + return true; + } + } + + public boolean weakCompareAndSet(T obj, long expect, long update) { + return compareAndSet(obj, expect, update); + } + + public void set(T obj, long newValue) { + if (!tclass.isInstance(obj)) + throw new ClassCastException(); + synchronized(this) { + unsafe.putLong(obj, offset, newValue); + } + } + + public long get(T obj) { + if (!tclass.isInstance(obj)) + throw new ClassCastException(); + synchronized(this) { + return unsafe.getLong(obj, offset); + } + } + } +} + diff --git a/concurrent/src/main/java/java/util/concurrent/atomic/AtomicMarkableReference.java b/concurrent/src/main/java/java/util/concurrent/atomic/AtomicMarkableReference.java new file mode 100644 index 0000000..11c91ba --- /dev/null +++ b/concurrent/src/main/java/java/util/concurrent/atomic/AtomicMarkableReference.java @@ -0,0 +1,163 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent.atomic; + +/** + * An <tt>AtomicMarkableReference</tt> maintains an object reference + * along with a mark bit, that can be updated atomically. + * <p> + * <p> Implementation note. This implementation maintains markable + * references by creating internal objects representing "boxed" + * [reference, boolean] pairs. + * + * @since 1.5 + * @author Doug Lea + * @param <V> The type of object referred to by this reference + */ +public class AtomicMarkableReference<V> { + + private static class ReferenceBooleanPair<T> { + private final T reference; + private final boolean bit; + ReferenceBooleanPair(T r, boolean i) { + reference = r; bit = i; + } + } + + private final AtomicReference<ReferenceBooleanPair<V>> atomicRef; + + /** + * Creates a new <tt>AtomicMarkableReference</tt> with the given + * initial values. + * + * @param initialRef the initial reference + * @param initialMark the initial mark + */ + public AtomicMarkableReference(V initialRef, boolean initialMark) { + atomicRef = new AtomicReference<ReferenceBooleanPair<V>> (new ReferenceBooleanPair<V>(initialRef, initialMark)); + } + + /** + * Returns the current value of the reference. + * + * @return the current value of the reference + */ + public V getReference() { + return atomicRef.get().reference; + } + + /** + * Returns the current value of the mark. + * + * @return the current value of the mark + */ + public boolean isMarked() { + return atomicRef.get().bit; + } + + /** + * Returns the current values of both the reference and the mark. + * Typical usage is <tt>boolean[1] holder; ref = v.get(holder); </tt>. + * + * @param markHolder an array of size of at least one. On return, + * <tt>markholder[0]</tt> will hold the value of the mark. + * @return the current value of the reference + */ + public V get(boolean[] markHolder) { + ReferenceBooleanPair<V> p = atomicRef.get(); + markHolder[0] = p.bit; + return p.reference; + } + + /** + * Atomically sets the value of both the reference and mark + * to the given update values if the + * current reference is <tt>==</tt> to the expected reference + * and the current mark is equal to the expected mark. Any given + * invocation of this operation may fail (return + * <tt>false</tt>) spuriously, but repeated invocation when + * the current value holds the expected value and no other thread + * is also attempting to set the value will eventually succeed. + * + * @param expectedReference the expected value of the reference + * @param newReference the new value for the reference + * @param expectedMark the expected value of the mark + * @param newMark the new value for the mark + * @return true if successful + */ + public boolean weakCompareAndSet(V expectedReference, + V newReference, + boolean expectedMark, + boolean newMark) { + ReferenceBooleanPair current = atomicRef.get(); + return expectedReference == current.reference && + expectedMark == current.bit && + ((newReference == current.reference && newMark == current.bit) || + atomicRef.weakCompareAndSet(current, + new ReferenceBooleanPair<V>(newReference, + newMark))); + } + + /** + * Atomically sets the value of both the reference and mark + * to the given update values if the + * current reference is <tt>==</tt> to the expected reference + * and the current mark is equal to the expected mark. + * + * @param expectedReference the expected value of the reference + * @param newReference the new value for the reference + * @param expectedMark the expected value of the mark + * @param newMark the new value for the mark + * @return true if successful + */ + public boolean compareAndSet(V expectedReference, + V newReference, + boolean expectedMark, + boolean newMark) { + ReferenceBooleanPair current = atomicRef.get(); + return expectedReference == current.reference && + expectedMark == current.bit && + ((newReference == current.reference && newMark == current.bit) || + atomicRef.compareAndSet(current, + new ReferenceBooleanPair<V>(newReference, + newMark))); + } + + /** + * Unconditionally sets the value of both the reference and mark. + * + * @param newReference the new value for the reference + * @param newMark the new value for the mark + */ + public void set(V newReference, boolean newMark) { + ReferenceBooleanPair current = atomicRef.get(); + if (newReference != current.reference || newMark != current.bit) + atomicRef.set(new ReferenceBooleanPair<V>(newReference, newMark)); + } + + /** + * Atomically sets the value of the mark to the given update value + * if the current reference is <tt>==</tt> to the expected + * reference. Any given invocation of this operation may fail + * (return <tt>false</tt>) spuriously, but repeated invocation + * when the current value holds the expected value and no other + * thread is also attempting to set the value will eventually + * succeed. + * + * @param expectedReference the expected value of the reference + * @param newMark the new value for the mark + * @return true if successful + */ + public boolean attemptMark(V expectedReference, boolean newMark) { + ReferenceBooleanPair current = atomicRef.get(); + return expectedReference == current.reference && + (newMark == current.bit || + atomicRef.compareAndSet + (current, new ReferenceBooleanPair<V>(expectedReference, + newMark))); + } +} diff --git a/concurrent/src/main/java/java/util/concurrent/atomic/AtomicReference.java b/concurrent/src/main/java/java/util/concurrent/atomic/AtomicReference.java new file mode 100644 index 0000000..d51d5ce --- /dev/null +++ b/concurrent/src/main/java/java/util/concurrent/atomic/AtomicReference.java @@ -0,0 +1,115 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent.atomic; +import sun.misc.Unsafe; + +/** + * An object reference that may be updated atomically. See the {@link + * java.util.concurrent.atomic} package specification for description + * of the properties of atomic variables. + * @since 1.5 + * @author Doug Lea + * @param <V> The type of object referred to by this reference + */ +public class AtomicReference<V> implements java.io.Serializable { + private static final long serialVersionUID = -1848883965231344442L; + + // BEGIN android-changed + private static final Unsafe unsafe = UnsafeAccess.THE_ONE; + // END android-changed + + private static final long valueOffset; + + static { + try { + valueOffset = unsafe.objectFieldOffset + (AtomicReference.class.getDeclaredField("value")); + } catch(Exception ex) { throw new Error(ex); } + } + + private volatile V value; + + /** + * Create a new AtomicReference with the given initial value. + * + * @param initialValue the initial value + */ + public AtomicReference(V initialValue) { + value = initialValue; + } + + /** + * Create a new AtomicReference with null initial value. + */ + public AtomicReference() { + } + + /** + * Get the current value. + * + * @return the current value + */ + public final V get() { + return value; + } + + /** + * Set to the given value. + * + * @param newValue the new value + */ + public final void set(V newValue) { + value = newValue; + } + + /** + * Atomically set the value to the given updated value + * if the current value <tt>==</tt> the expected value. + * @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. + */ + public final boolean compareAndSet(V expect, V update) { + return unsafe.compareAndSwapObject(this, valueOffset, expect, update); + } + + /** + * Atomically set the value to the given updated value + * if the current value <tt>==</tt> the expected value. + * May fail spuriously. + * @param expect the expected value + * @param update the new value + * @return true if successful. + */ + public final boolean weakCompareAndSet(V expect, V update) { + return unsafe.compareAndSwapObject(this, valueOffset, expect, update); + } + + /** + * Set to the given value and return the old value. + * + * @param newValue the new value + * @return the previous value + */ + public final V getAndSet(V newValue) { + while (true) { + V x = get(); + if (compareAndSet(x, newValue)) + return x; + } + } + + /** + * Returns the String representation of the current value. + * @return the String representation of the current value. + */ + public String toString() { + return String.valueOf(get()); + } + +} diff --git a/concurrent/src/main/java/java/util/concurrent/atomic/AtomicReferenceArray.java b/concurrent/src/main/java/java/util/concurrent/atomic/AtomicReferenceArray.java new file mode 100644 index 0000000..98b83c4 --- /dev/null +++ b/concurrent/src/main/java/java/util/concurrent/atomic/AtomicReferenceArray.java @@ -0,0 +1,152 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent.atomic; +import sun.misc.Unsafe; +import java.util.*; + +/** + * An array of object references in which elements may be updated + * atomically. See the {@link java.util.concurrent.atomic} package + * specification for description of the properties of atomic + * variables. + * @since 1.5 + * @author Doug Lea + * @param <E> The base class of elements held in this array + */ +public class AtomicReferenceArray<E> implements java.io.Serializable { + private static final long serialVersionUID = -6209656149925076980L; + + // BEGIN android-changed + private static final Unsafe unsafe = UnsafeAccess.THE_ONE; + // END android-changed + + private static final int base = unsafe.arrayBaseOffset(Object[].class); + private static final int scale = unsafe.arrayIndexScale(Object[].class); + private final Object[] array; + + private long rawIndex(int i) { + if (i < 0 || i >= array.length) + throw new IndexOutOfBoundsException("index " + i); + return base + i * scale; + } + + /** + * Create a new AtomicReferenceArray of given length. + * @param length the length of the array + */ + public AtomicReferenceArray(int length) { + array = new Object[length]; + // must perform at least one volatile write to conform to JMM + if (length > 0) + unsafe.putObjectVolatile(array, rawIndex(0), null); + } + + /** + * Create a new AtomicReferenceArray with the same length as, and + * all elements copied from, the given array. + * + * @param array the array to copy elements from + * @throws NullPointerException if array is null + */ + public AtomicReferenceArray(E[] array) { + if (array == null) + throw new NullPointerException(); + int length = array.length; + this.array = new Object[length]; + if (length > 0) { + int last = length-1; + for (int i = 0; i < last; ++i) + this.array[i] = array[i]; + // Do the last write as volatile + E e = array[last]; + unsafe.putObjectVolatile(this.array, rawIndex(last), e); + } + } + + /** + * Returns the length of the array. + * + * @return the length of the array + */ + public final int length() { + return array.length; + } + + /** + * Get the current value at position <tt>i</tt>. + * + * @param i the index + * @return the current value + */ + public final E get(int i) { + return (E) unsafe.getObjectVolatile(array, rawIndex(i)); + } + + /** + * Set the element at position <tt>i</tt> to the given value. + * + * @param i the index + * @param newValue the new value + */ + public final void set(int i, E newValue) { + unsafe.putObjectVolatile(array, rawIndex(i), newValue); + } + + /** + * Set the element at position <tt>i</tt> to the given value and return the + * old value. + * + * @param i the index + * @param newValue the new value + * @return the previous value + */ + public final E getAndSet(int i, E newValue) { + while (true) { + E current = get(i); + if (compareAndSet(i, current, newValue)) + return current; + } + } + + /** + * Atomically set the value to the given updated value + * if the current value <tt>==</tt> the expected value. + * @param i the index + * @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. + */ + public final boolean compareAndSet(int i, E expect, E update) { + return unsafe.compareAndSwapObject(array, rawIndex(i), + expect, update); + } + + /** + * Atomically set the value to the given updated value + * if the current value <tt>==</tt> the expected value. + * May fail spuriously. + * @param i the index + * @param expect the expected value + * @param update the new value + * @return true if successful. + */ + public final boolean weakCompareAndSet(int i, E expect, E update) { + return compareAndSet(i, expect, update); + } + + /** + * Returns the String representation of the current values of array. + * @return the String representation of the current values of array. + */ + public String toString() { + if (array.length > 0) // force volatile read + get(0); + return Arrays.toString(array); + } + +} diff --git a/concurrent/src/main/java/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java b/concurrent/src/main/java/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java new file mode 100644 index 0000000..044d6cd --- /dev/null +++ b/concurrent/src/main/java/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java @@ -0,0 +1,198 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent.atomic; +import sun.misc.Unsafe; +import java.lang.reflect.*; + +/** + * A reflection-based utility that enables atomic updates to + * designated <tt>volatile</tt> reference fields of designated + * classes. This class is designed for use in atomic data structures + * in which several reference fields of the same node are + * independently subject to atomic updates. For example, a tree node + * might be declared as + * + * <pre> + * class Node { + * private volatile Node left, right; + * + * private static final AtomicReferenceFieldUpdater<Node, Node> leftUpdater = + * AtomicReferenceFieldUpdater.newUpdater(Node.class, Node.class, "left"); + * private static AtomicReferenceFieldUpdater<Node, Node> rightUpdater = + * AtomicReferenceFieldUpdater.newUpdater(Node.class, Node.class, "right"); + * + * Node getLeft() { return left; } + * boolean compareAndSetLeft(Node expect, Node update) { + * return leftUpdater.compareAndSet(this, expect, update); + * } + * // ... and so on + * } + * </pre> + * + * <p> Note that the guarantees of the <tt>compareAndSet</tt> + * method in this class are weaker than in other atomic classes. Because this + * class cannot ensure that all uses of the field are appropriate for + * purposes of atomic access, it can guarantee atomicity and volatile + * semantics only with respect to other invocations of + * <tt>compareAndSet</tt> and <tt>set</tt>. + * @since 1.5 + * @author Doug Lea + * @param <T> The type of the object holding the updatable field + * @param <V> The type of the field + */ +public abstract class AtomicReferenceFieldUpdater<T, V> { + + /** + * Creates an updater for objects with the given field. The Class + * arguments are needed to check that reflective types and generic + * types match. + * @param tclass the class of the objects holding the field. + * @param vclass the class of the field + * @param fieldName the name of the field to be updated. + * @return the updater + * @throws IllegalArgumentException if the field is not a volatile reference type. + * @throws RuntimeException with a nested reflection-based + * exception if the class does not hold field or is the wrong type. + */ + public static <U, W> AtomicReferenceFieldUpdater<U,W> newUpdater(Class<U> tclass, Class<W> vclass, String fieldName) { + // Currently rely on standard intrinsics implementation + return new AtomicReferenceFieldUpdaterImpl<U,W>(tclass, + vclass, + fieldName); + } + + /** + * Protected do-nothing constructor for use by subclasses. + */ + protected AtomicReferenceFieldUpdater() { + } + + /** + * Atomically set the value of the field of the given object managed + * by this Updater to the given updated value if the current value + * <tt>==</tt> the expected value. This method is guaranteed to be + * atomic with respect to other calls to <tt>compareAndSet</tt> and + * <tt>set</tt>, but not necessarily with respect to other + * changes in the field. + * @param obj An object whose field to conditionally set + * @param expect the expected value + * @param update the new value + * @return true if successful. + */ + + public abstract boolean compareAndSet(T obj, V expect, V update); + + /** + * Atomically set the value of the field of the given object managed + * by this Updater to the given updated value if the current value + * <tt>==</tt> the expected value. This method is guaranteed to be + * atomic with respect to other calls to <tt>compareAndSet</tt> and + * <tt>set</tt>, but not necessarily with respect to other + * changes in the field, and may fail spuriously. + * @param obj An object whose field to conditionally set + * @param expect the expected value + * @param update the new value + * @return true if successful. + */ + public abstract boolean weakCompareAndSet(T obj, V expect, V update); + + /** + * Set the field of the given object managed by this updater. This + * operation is guaranteed to act as a volatile store with respect + * to subsequent invocations of <tt>compareAndSet</tt>. + * @param obj An object whose field to set + * @param newValue the new value + */ + public abstract void set(T obj, V newValue); + + /** + * Get the current value held in the field by the given object. + * @param obj An object whose field to get + * @return the current value + */ + public abstract V get(T obj); + + /** + * Set to the given value and return the old value. + * + * @param obj An object whose field to get and set + * @param newValue the new value + * @return the previous value + */ + public V getAndSet(T obj, V newValue) { + for (;;) { + V current = get(obj); + if (compareAndSet(obj, current, newValue)) + return current; + } + } + + /** + * Standard hotspot implementation using intrinsics + */ + private static class AtomicReferenceFieldUpdaterImpl<T,V> extends AtomicReferenceFieldUpdater<T,V> { + // BEGIN android-changed + private static final Unsafe unsafe = UnsafeAccess.THE_ONE; + // END android-changed + + private final long offset; + private final Class<T> tclass; + private final Class<V> vclass; + + AtomicReferenceFieldUpdaterImpl(Class<T> tclass, Class<V> vclass, String fieldName) { + Field field = null; + Class fieldClass = null; + try { + field = tclass.getDeclaredField(fieldName); + fieldClass = field.getType(); + } catch(Exception ex) { + throw new RuntimeException(ex); + } + + if (vclass != fieldClass) + throw new ClassCastException(); + + if (!Modifier.isVolatile(field.getModifiers())) + throw new IllegalArgumentException("Must be volatile type"); + + this.tclass = tclass; + this.vclass = vclass; + offset = unsafe.objectFieldOffset(field); + } + + + public boolean compareAndSet(T obj, V expect, V update) { + if (!tclass.isInstance(obj) || + (update != null && !vclass.isInstance(update))) + throw new ClassCastException(); + return unsafe.compareAndSwapObject(obj, offset, expect, update); + } + + public boolean weakCompareAndSet(T obj, V expect, V update) { + // same implementation as strong form for now + if (!tclass.isInstance(obj) || + (update != null && !vclass.isInstance(update))) + throw new ClassCastException(); + return unsafe.compareAndSwapObject(obj, offset, expect, update); + } + + + public void set(T obj, V newValue) { + if (!tclass.isInstance(obj) || + (newValue != null && !vclass.isInstance(newValue))) + throw new ClassCastException(); + unsafe.putObjectVolatile(obj, offset, newValue); + } + + public V get(T obj) { + if (!tclass.isInstance(obj)) + throw new ClassCastException(); + return (V)unsafe.getObjectVolatile(obj, offset); + } + } +} + diff --git a/concurrent/src/main/java/java/util/concurrent/atomic/AtomicStampedReference.java b/concurrent/src/main/java/java/util/concurrent/atomic/AtomicStampedReference.java new file mode 100644 index 0000000..b0a02c2 --- /dev/null +++ b/concurrent/src/main/java/java/util/concurrent/atomic/AtomicStampedReference.java @@ -0,0 +1,167 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent.atomic; + +/** + * An <tt>AtomicStampedReference</tt> maintains an object reference + * along with an integer "stamp", that can be updated atomically. + * + * <p> Implementation note. This implementation maintains stamped + * references by creating internal objects representing "boxed" + * [reference, integer] pairs. + * + * @since 1.5 + * @author Doug Lea + * @param <V> The type of object referred to by this reference + */ +public class AtomicStampedReference<V> { + + private static class ReferenceIntegerPair<T> { + private final T reference; + private final int integer; + ReferenceIntegerPair(T r, int i) { + reference = r; integer = i; + } + } + + private final AtomicReference<ReferenceIntegerPair<V>> atomicRef; + + /** + * Creates a new <tt>AtomicStampedReference</tt> with the given + * initial values. + * + * @param initialRef the initial reference + * @param initialStamp the initial stamp + */ + public AtomicStampedReference(V initialRef, int initialStamp) { + atomicRef = new AtomicReference<ReferenceIntegerPair<V>> + (new ReferenceIntegerPair<V>(initialRef, initialStamp)); + } + + /** + * Returns the current value of the reference. + * + * @return the current value of the reference + */ + public V getReference() { + return atomicRef.get().reference; + } + + /** + * Returns the current value of the stamp. + * + * @return the current value of the stamp + */ + public int getStamp() { + return atomicRef.get().integer; + } + + /** + * Returns the current values of both the reference and the stamp. + * Typical usage is <tt>int[1] holder; ref = v.get(holder); </tt>. + * + * @param stampHolder an array of size of at least one. On return, + * <tt>stampholder[0]</tt> will hold the value of the stamp. + * @return the current value of the reference + */ + public V get(int[] stampHolder) { + ReferenceIntegerPair<V> p = atomicRef.get(); + stampHolder[0] = p.integer; + return p.reference; + } + + /** + * Atomically sets the value of both the reference and stamp + * to the given update values if the + * current reference is <tt>==</tt> to the expected reference + * and the current stamp is equal to the expected stamp. Any given + * invocation of this operation may fail (return + * <tt>false</tt>) spuriously, but repeated invocation when + * the current value holds the expected value and no other thread + * is also attempting to set the value will eventually succeed. + * + * @param expectedReference the expected value of the reference + * @param newReference the new value for the reference + * @param expectedStamp the expected value of the stamp + * @param newStamp the new value for the stamp + * @return true if successful + */ + public boolean weakCompareAndSet(V expectedReference, + V newReference, + int expectedStamp, + int newStamp) { + ReferenceIntegerPair current = atomicRef.get(); + return expectedReference == current.reference && + expectedStamp == current.integer && + ((newReference == current.reference && + newStamp == current.integer) || + atomicRef.weakCompareAndSet(current, + new ReferenceIntegerPair<V>(newReference, + newStamp))); + } + + /** + * Atomically sets the value of both the reference and stamp + * to the given update values if the + * current reference is <tt>==</tt> to the expected reference + * and the current stamp is equal to the expected stamp. + * + * @param expectedReference the expected value of the reference + * @param newReference the new value for the reference + * @param expectedStamp the expected value of the stamp + * @param newStamp the new value for the stamp + * @return true if successful + */ + public boolean compareAndSet(V expectedReference, + V newReference, + int expectedStamp, + int newStamp) { + ReferenceIntegerPair current = atomicRef.get(); + return expectedReference == current.reference && + expectedStamp == current.integer && + ((newReference == current.reference && + newStamp == current.integer) || + atomicRef.compareAndSet(current, + new ReferenceIntegerPair<V>(newReference, + newStamp))); + } + + + /** + * Unconditionally sets the value of both the reference and stamp. + * + * @param newReference the new value for the reference + * @param newStamp the new value for the stamp + */ + public void set(V newReference, int newStamp) { + ReferenceIntegerPair current = atomicRef.get(); + if (newReference != current.reference || newStamp != current.integer) + atomicRef.set(new ReferenceIntegerPair<V>(newReference, newStamp)); + } + + /** + * Atomically sets the value of the stamp to the given update value + * if the current reference is <tt>==</tt> to the expected + * reference. Any given invocation of this operation may fail + * (return <tt>false</tt>) spuriously, but repeated invocation + * when the current value holds the expected value and no other + * thread is also attempting to set the value will eventually + * succeed. + * + * @param expectedReference the expected value of the reference + * @param newStamp the new value for the stamp + * @return true if successful + */ + public boolean attemptStamp(V expectedReference, int newStamp) { + ReferenceIntegerPair current = atomicRef.get(); + return expectedReference == current.reference && + (newStamp == current.integer || + atomicRef.compareAndSet(current, + new ReferenceIntegerPair<V>(expectedReference, + newStamp))); + } +} diff --git a/concurrent/src/main/java/java/util/concurrent/atomic/UnsafeAccess.java b/concurrent/src/main/java/java/util/concurrent/atomic/UnsafeAccess.java new file mode 100644 index 0000000..96fff17 --- /dev/null +++ b/concurrent/src/main/java/java/util/concurrent/atomic/UnsafeAccess.java @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.util.concurrent.atomic; + +import sun.misc.Unsafe; + +/** + * Easy access to {@link Unsafe} for the rest of this package. + */ +/*package*/ final class UnsafeAccess { + /** non-null; unique instance of {@link Unsafe} */ + /*package*/ static final Unsafe THE_ONE = Unsafe.getUnsafe(); + + /** + * This class is uninstantiable. + */ + private UnsafeAccess() { + // This space intentionally left blank. + } +} diff --git a/concurrent/src/main/java/java/util/concurrent/atomic/package.html b/concurrent/src/main/java/java/util/concurrent/atomic/package.html new file mode 100644 index 0000000..5316e22 --- /dev/null +++ b/concurrent/src/main/java/java/util/concurrent/atomic/package.html @@ -0,0 +1,133 @@ +<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN"> +<html> <head> +<title>Atomics</title> +</head> + +<body> + +A small toolkit of classes that support lock-free thread-safe +programming on single variables. In essence, the classes in this +package extend the notion of <tt>volatile</tt> values, fields, and +array elements to those that also provide an atomic conditional update +operation of the form: + +<pre> + boolean compareAndSet(expectedValue, updateValue); +</pre> + +<p> This method (which varies in argument types across different +classes) atomically sets a variable to the <tt>updateValue</tt> if it +currently holds the <tt>expectedValue</tt>, reporting <tt>true</tt> on +success. The classes in this package also contain methods to get and +unconditionally set values, as well as a weaker conditional atomic +update operation <tt> weakCompareAndSet</tt>. The weak version may be +more efficient in the normal case, but differs in that any given +invocation of <tt>weakCompareAndSet</tt> method may fail, even +spuriously (that is, for no apparent reason). A <tt>false</tt> return +means only that the operation may be retried if desired, relying on +the guarantee that repeated invocation when the variable holds +<tt>expectedValue</tt> and no other thread is also attempting to set +the variable will eventually succeed. + +<p> The specifications of these methods enable implementations to +employ efficient machine-level atomic instructions that are available +on contemporary processors. However on some platforms, support may +entail some form of internal locking. Thus the methods are not +strictly guaranteed to be non-blocking -- +a thread may block transiently before performing the operation. + +<p> Instances of classes {@link +java.util.concurrent.atomic.AtomicBoolean}, {@link +java.util.concurrent.atomic.AtomicInteger}, {@link +java.util.concurrent.atomic.AtomicLong}, and {@link +java.util.concurrent.atomic.AtomicReference} each provide access and +updates to a single variable of the corresponding type. Each class +also provides appropriate utility methods for that type. For example, +classes <tt>AtomicLong</tt> and <tt>AtomicInteger</tt> provide atomic +increment methods. One application is to generate sequence numbers, +as in: + +<pre> +class Sequencer { + private AtomicLong sequenceNumber = new AtomicLong(0); + public long next() { return sequenceNumber.getAndIncrement(); } +} +</pre> + +<p>The memory effects for accesses and updates of atomics generally follow the +rules for volatiles: + +<ul> + + <li> <tt>get</tt> has the memory effects of reading a +<tt>volatile</tt> variable. + + <li> <tt>set</tt> has the memory effects of writing (assigning) a +<tt>volatile</tt> variable. + + <li><tt>weakCompareAndSet</tt> atomically reads and conditionally + writes a variable, is ordered with respect to other + memory operations on that variable, but otherwise acts as an + ordinary non-volatile memory operation. + + <li> <tt>compareAndSet</tt> + and all other read-and-update operations such as <tt>getAndIncrement</tt> + have the memory effects of both reading and + writing <tt>volatile</tt> variables. +</ul> + +<p>In addition to classes representing single values, this package +contains <em>Updater</em> classes that can be used to obtain +<tt>compareAndSet</tt> operations on any selected <tt>volatile</tt> +field of any selected class. {@link +java.util.concurrent.atomic.AtomicReferenceFieldUpdater}, {@link +java.util.concurrent.atomic.AtomicIntegerFieldUpdater}, and {@link +java.util.concurrent.atomic.AtomicLongFieldUpdater} are +reflection-based utilities that provide access to the associated field +types. These are mainly of use in atomic data structures in which +several <tt>volatile</tt> fields of the same node (for example, the +links of a tree node) are independently subject to atomic +updates. These classes enable greater flexibility in how and when to +use atomic updates, at the expense of more awkward reflection-based +setup, less convenient usage, and weaker guarantees. + +<p>The {@link java.util.concurrent.atomic.AtomicIntegerArray}, {@link +java.util.concurrent.atomic.AtomicLongArray}, and {@link +java.util.concurrent.atomic.AtomicReferenceArray} classes further +extend atomic operation support to arrays of these types. These +classes are also notable in providing <tt>volatile</tt> access +semantics for their array elements, which is not supported for +ordinary arrays. + +<p> The {@link java.util.concurrent.atomic.AtomicMarkableReference} +class associates a single boolean with a reference. For example, this +bit might be used inside a data structure to mean that the object +being referenced has logically been deleted. The {@link +java.util.concurrent.atomic.AtomicStampedReference} class associates +an integer value with a reference. This may be used for example, to +represent version numbers corresponding to series of updates. + +<p> Atomic classes are designed primarily as building blocks for +implementing non-blocking data structures and related infrastructure +classes. The <tt>compareAndSet</tt> method is not a general +replacement for locking. It applies only when critical updates for an +object are confined to a <em>single</em> variable. + +<p> Atomic classes are not general purpose replacements for +<tt>java.lang.Integer</tt> and related classes. They do <em>not</em> +define methods such as <tt>hashCode</tt> and +<tt>compareTo</tt>. (Because atomic variables are expected to be +mutated, they are poor choices for hash table keys.) Additionally, +classes are provided only for those types that are commonly useful in +intended applications. For example, there is no atomic class for +representing <tt>byte</tt>. In those infrequent cases where you would +like to do so, you can use an <tt>AtomicInteger</tt> to hold +<tt>byte</tt> values, and cast appropriately. You can also hold floats +using <tt>Float.floatToIntBits</tt> and <tt>Float.intBitstoFloat</tt> +conversions, and doubles using <tt>Double.doubleToLongBits</tt> and +<tt>Double.longBitsToDouble</tt> conversions. + +@since 1.5 +@since Android 1.0 + +</body> </html> diff --git a/concurrent/src/main/java/java/util/concurrent/locks/AbstractQueuedSynchronizer.java b/concurrent/src/main/java/java/util/concurrent/locks/AbstractQueuedSynchronizer.java new file mode 100644 index 0000000..da9d84d --- /dev/null +++ b/concurrent/src/main/java/java/util/concurrent/locks/AbstractQueuedSynchronizer.java @@ -0,0 +1,2064 @@ +/* + * 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/licenses/publicdomain + */ + +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 <tt>int</tt> 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 <tt>int</tt> + * value manipulated using methods {@link #getState}, {@link + * #setState} and {@link #compareAndSetState} is tracked with respect + * to synchronization. + * + * <p>Subclasses should be defined as non-public internal helper + * classes that are used to implement the synchronization properties + * of their enclosing class. Class + * <tt>AbstractQueuedSynchronizer</tt> 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. + * + * <p>This class supports either or both a default <em>exclusive</em> + * mode and a <em>shared</em> 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. + * + * <p>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 + * <tt>AbstractQueuedSynchronizer</tt> 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. + * + * <p> 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 <tt>AbstractQueuedSynchronizer</tt> for their + * synchronization mechanics. + * + * <p> 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 <tt>readObject</tt> method that restores this to a known + * initial state upon deserialization. + * + * <h3>Usage</h3> + * + * <p> 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}: + * + * <ul> + * <li> {@link #tryAcquire} + * <li> {@link #tryRelease} + * <li> {@link #tryAcquireShared} + * <li> {@link #tryReleaseShared} + * <li> {@link #isHeldExclusively} + *</ul> + * + * 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 <em>only</em> supported + * means of using this class. All other methods are declared + * <tt>final</tt> because they cannot be independently varied. + * + * <p> 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: + * + * <pre> + * Acquire: + * while (!tryAcquire(arg)) { + * <em>enqueue thread if it is not already queued</em>; + * <em>possibly block current thread</em>; + * } + * + * Release: + * if (tryRelease(arg)) + * <em>unblock the first queued thread</em>; + * </pre> + * + * (Shared mode is similar but may involve cascading signals.) + * + * <p> Because checks in acquire are invoked before enqueuing, a newly + * acquiring thread may <em>barge</em> ahead of others that are + * blocked and queued. However, you can, if desired, define + * <tt>tryAcquire</tt> and/or <tt>tryAcquireShared</tt> to disable + * barging by internally invoking one or more of the inspection + * methods. In particular, a strict FIFO lock can define + * <tt>tryAcquire</tt> to immediately return <tt>false</tt> if {@link + * #getFirstQueuedThread} does not return the current thread. A + * normally preferable non-strict fair version can immediately return + * <tt>false</tt> only if {@link #hasQueuedThreads} returns + * <tt>true</tt> and <tt>getFirstQueuedThread</tt> is not the current + * thread; or equivalently, that <tt>getFirstQueuedThread</tt> is both + * non-null and not the current thread. Further variations are + * possible. + * + * <p> Throughput and scalability are generally highest for the + * default barging (also known as <em>greedy</em>, + * <em>renouncement</em>, and <em>convoy-avoidance</em>) 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 <tt>tryAcquire</tt> 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. + * + * <p> This class provides an efficient and scalable basis for + * synchronization in part by specializing its range of use to + * synchronizers that can rely on <tt>int</tt> 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. + * + * <h3>Usage Examples</h3> + * + * <p>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. It also supports conditions and exposes + * one of the instrumentation methods: + * + * <pre> + * 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 + * return compareAndSetState(0, 1); + * } + * + * // Release the lock by setting state to zero + * protected boolean tryRelease(int releases) { + * assert releases == 1; // Otherwise unused + * if (getState() == 0) throw new IllegalMonitorStateException(); + * 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)); + * } + * } + * </pre> + * + * <p> Here is a latch class that is like a {@link CountDownLatch} + * except that it only requires a single <tt>signal</tt> to + * fire. Because a latch is non-exclusive, it uses the <tt>shared</tt> + * acquire and release methods. + * + * <pre> + * 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); + * } + * } + * + * </pre> + * + * @since 1.5 + * @author Doug Lea + */ +public abstract class AbstractQueuedSynchronizer implements java.io.Serializable { + private static final long serialVersionUID = 7373984972572414691L; + + /** + * Creates a new <tt>AbstractQueuedSynchronizer</tt> instance + * with initial synchronization state of zero. + */ + protected AbstractQueuedSynchronizer() { } + + /** + * Wait queue node class. + * + * <p> 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. + * + * <p>To enqueue into a CLH lock, you atomically splice it in as new + * tail. To dequeue, you just set the head field. + * <pre> + * +------+ prev +-----+ +-----+ + * head | | <---- | | <---- | | tail + * +------+ +-----+ +-----+ + * </pre> + * + * <p>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. + * + * <p>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/ + * + * <p>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.) + * + * <p>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. + * + * <p>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. + * + * <p>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. + * + * <p>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 { + /** waitStatus value to indicate thread has cancelled */ + static final int CANCELLED = 1; + /** waitStatus value to indicate thread needs unparking */ + static final int SIGNAL = -1; + /** waitStatus value to indicate thread is waiting on condition */ + static final int CONDITION = -2; + /** 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; + + /** + * 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: Node is cancelled due to timeout or interrupt + * Nodes never leave this state. In particular, + * a thread with cancelled node never again blocks. + * CONDITION: Node is currently on a condition queue + * It will not be used as a sync queue node until + * transferred. (Use of this value here + * has nothing to do with the other uses + * of the field, but simplifies mechanics.) + * 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 only using + * CAS. + */ + 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 once during enqueuing, and + * nulled out (for sake of GC) when no longer needed. Upon + * cancellation, we cannot adjust this field, but can notice + * status and bypass the node if cancelled. 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. + */ + 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. + * @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 <tt>volatile</tt> read. + * @return current state value + */ + protected final int getState() { + return state; + } + + /** + * Sets the value of synchronization state. + * This operation has memory semantics of a <tt>volatile</tt> 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 <tt>volatile</tt> 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 + + /** + * Insert 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 + Node h = new Node(); // Dummy header + h.next = node; + node.prev = h; + if (compareAndSetHead(h)) { + tail = node; + return h; + } + } + else { + node.prev = t; + if (compareAndSetTail(t, node)) { + t.next = node; + return t; + } + } + } + } + + /** + * Create and enq node for given thread and mode + * @param current the thread + * @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; + } + + /** + * Set 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; + } + + /** + * Wake up node's successor, if one exists. + * @param node the node + */ + private void unparkSuccessor(Node node) { + /* + * Try to clear status in anticipation of signalling. It is + * OK if this fails or if status is changed by waiting thread. + */ + compareAndSetWaitStatus(node, Node.SIGNAL, 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. + */ + Thread thread; + Node s = node.next; + if (s != null && s.waitStatus <= 0) + thread = s.thread; + else { + thread = null; + for (s = tail; s != null && s != node; s = s.prev) + if (s.waitStatus <= 0) + thread = s.thread; + } + LockSupport.unpark(thread); + } + + /** + * Set head of queue, and check if successor may be waiting + * in shared mode, if so propagating if propagate > 0. + * @param pred the node holding waitStatus for node + * @param node the node + * @param propagate the return value from a tryAcquireShared + */ + private void setHeadAndPropagate(Node node, int propagate) { + setHead(node); + if (propagate > 0 && node.waitStatus != 0) { + /* + * Don't bother fully figuring out successor. If it + * looks null, call unparkSuccessor anyway to be safe. + */ + Node s = node.next; + if (s == null || s.isShared()) + unparkSuccessor(node); + } + } + + // Utilities for various versions of acquire + + /** + * Cancel an ongoing attempt to acquire. + * @param node the node + */ + private void cancelAcquire(Node node) { + if (node != null) { // Ignore if node doesn't exist + node.thread = null; + // Can use unconditional write instead of CAS here + node.waitStatus = Node.CANCELLED; + unparkSuccessor(node); + } + } + + /** + * 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 true if thread should block + */ + private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) { + int s = pred.waitStatus; + if (s < 0) + /* + * This node has already set status asking a release + * to signal it, so it can safely park + */ + return true; + if (s > 0) + /* + * Predecessor was cancelled. Move up to its predecessor + * and indicate retry. + */ + node.prev = pred.prev; + else + /* + * 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, 0, 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 true if interrupted + */ + private static boolean parkAndCheckInterrupt() { + LockSupport.park(); + 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. + */ + + /** + * Acquire 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 true if interrupted while waiting + */ + final boolean acquireQueued(final Node node, int arg) { + try { + boolean interrupted = false; + for (;;) { + final Node p = node.predecessor(); + if (p == head && tryAcquire(arg)) { + setHead(node); + p.next = null; // help GC + return interrupted; + } + if (shouldParkAfterFailedAcquire(p, node) && + parkAndCheckInterrupt()) + interrupted = true; + } + } catch (RuntimeException ex) { + cancelAcquire(node); + throw ex; + } + } + + /** + * Acquire in exclusive interruptible mode + * @param arg the acquire argument + */ + private void doAcquireInterruptibly(int arg) + throws InterruptedException { + final Node node = addWaiter(Node.EXCLUSIVE); + try { + for (;;) { + final Node p = node.predecessor(); + if (p == head && tryAcquire(arg)) { + setHead(node); + p.next = null; // help GC + return; + } + if (shouldParkAfterFailedAcquire(p, node) && + parkAndCheckInterrupt()) + break; + } + } catch (RuntimeException ex) { + cancelAcquire(node); + throw ex; + } + // Arrive here only if interrupted + cancelAcquire(node); + throw new InterruptedException(); + } + + /** + * Acquire in exclusive timed mode + * @param arg the acquire argument + * @param nanosTimeout max wait time + * @return true if acquired + */ + private boolean doAcquireNanos(int arg, long nanosTimeout) + throws InterruptedException { + long lastTime = System.nanoTime(); + final Node node = addWaiter(Node.EXCLUSIVE); + try { + for (;;) { + final Node p = node.predecessor(); + if (p == head && tryAcquire(arg)) { + setHead(node); + p.next = null; // help GC + return true; + } + if (nanosTimeout <= 0) { + cancelAcquire(node); + return false; + } + if (shouldParkAfterFailedAcquire(p, node)) { + LockSupport.parkNanos(nanosTimeout); + if (Thread.interrupted()) + break; + long now = System.nanoTime(); + nanosTimeout -= now - lastTime; + lastTime = now; + } + } + } catch (RuntimeException ex) { + cancelAcquire(node); + throw ex; + } + // Arrive here only if interrupted + cancelAcquire(node); + throw new InterruptedException(); + } + + /** + * Acquire in shared uninterruptible mode + * @param arg the acquire argument + */ + private void doAcquireShared(int arg) { + final Node node = addWaiter(Node.SHARED); + 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(); + return; + } + } + if (shouldParkAfterFailedAcquire(p, node) && + parkAndCheckInterrupt()) + interrupted = true; + } + } catch (RuntimeException ex) { + cancelAcquire(node); + throw ex; + } + } + + /** + * Acquire in shared interruptible mode + * @param arg the acquire argument + */ + private void doAcquireSharedInterruptibly(int arg) + throws InterruptedException { + final Node node = addWaiter(Node.SHARED); + 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 + return; + } + } + if (shouldParkAfterFailedAcquire(p, node) && + parkAndCheckInterrupt()) + break; + } + } catch (RuntimeException ex) { + cancelAcquire(node); + throw ex; + } + // Arrive here only if interrupted + cancelAcquire(node); + throw new InterruptedException(); + } + + /** + * Acquire in shared timed mode + * @param arg the acquire argument + * @param nanosTimeout max wait time + * @return true if acquired + */ + private boolean doAcquireSharedNanos(int arg, long nanosTimeout) + throws InterruptedException { + + long lastTime = System.nanoTime(); + final Node node = addWaiter(Node.SHARED); + 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 + return true; + } + } + if (nanosTimeout <= 0) { + cancelAcquire(node); + return false; + } + if (shouldParkAfterFailedAcquire(p, node)) { + LockSupport.parkNanos(nanosTimeout); + if (Thread.interrupted()) + break; + long now = System.nanoTime(); + nanosTimeout -= now - lastTime; + lastTime = now; + } + } + } catch (RuntimeException ex) { + cancelAcquire(node); + throw ex; + } + // Arrive here only if interrupted + cancelAcquire(node); + throw new InterruptedException(); + } + + // 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. + * + * <p>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()}. + * + * <p>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 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. <p>This method is always invoked by the thread + * performing release. + * + * <p>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 <tt>true</tt> if this object is now in a fully released state, + * so that any waiting threads may attempt to acquire; and <tt>false</tt> + * 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. + * + * <p>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. + * + * <p>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 on exclusive success, + * and a positive value if non-exclusively successful, 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. + * <p>This method is always invoked by the thread performing release. + * <p> 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 <tt>true</tt> if this object is now in a fully released state, + * so that any waiting threads may attempt to acquire; and <tt>false</tt> + * 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 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}.) + * <p>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 true if synchronization is held exclusively; + * else false + * @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 true if acquired; 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 true if acquired; 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)) { + Node h = head; + if (h != null && h.waitStatus != 0) + unparkSuccessor(h); + 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 <tt>true</tt> return does not guarantee that any + * other thread will ever acquire. + * + * <p> In this implementation, this operation returns in + * constant time. + * + * @return true if there may be other threads waiting to acquire + * the lock. + */ + 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. + * + * <p> In this implementation, this operation returns in + * constant time. + * + * @return true if there has ever been contention + */ + public final boolean hasContended() { + return head != null; + } + + /** + * Returns the first (longest-waiting) thread in the queue, or + * <tt>null</tt> if no threads are currently queued. + * + * <p> 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 + * <tt>null</tt> 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() { + /* + * This loops only if the queue changes while we read sets of + * fields. + */ + for (;;) { + Node h = head; + if (h == null) // No queue + return null; + + /* + * The first node is normally h.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, so we must reread. + */ + Node s = h.next; + if (s != null) { + Thread st = s.thread; + Node sp = s.prev; + if (st != null && sp == head) + 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, in almost the same way + * as above. + */ + Node t = tail; + if (t == h) // Empty queue + return null; + + if (t != null) { + Thread tt = t.thread; + Node tp = t.prev; + if (tt != null && tp == head) + return tt; + } + } + } + + /** + * Returns true if the given thread is currently queued. + * + * <p> This implementation traverses the queue to determine + * presence of the given thread. + * + * @param thread the thread + * @return true if the given thread in on the queue + * @throws NullPointerException if thread 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; + } + + // 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 for this lock + */ + 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<Thread> getQueuedThreads() { + ArrayList<Thread> list = new ArrayList<Thread>(); + 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<Thread> getExclusiveQueuedThreads() { + ArrayList<Thread> list = new ArrayList<Thread>(); + 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<Thread> getSharedQueuedThreads() { + ArrayList<Thread> list = new ArrayList<Thread>(); + 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 "State + * =" followed by the current value of {@link #getState}, and + * either "nonempty" or "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 c = p.waitStatus; + if (c > 0 || !compareAndSetWaitStatus(p, c, 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; + } + + /** + * Invoke release with current state value; return saved state. + * Cancel node and throw exception on failure. + * @param node the condition node for this wait + * @return previous sync state + */ + final int fullyRelease(Node node) { + try { + int savedState = getState(); + if (release(savedState)) + return savedState; + } catch(RuntimeException ex) { + node.waitStatus = Node.CANCELLED; + throw ex; + } + // reach here if release fails + node.waitStatus = Node.CANCELLED; + throw new IllegalMonitorStateException(); + } + + // Instrumentation methods for conditions + + /** + * Queries whether the given ConditionObject + * uses this synchronizer as its lock. + * @param condition the condition + * @return <tt>true</tt> if owned + * @throws NullPointerException if condition 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 <tt>true</tt> return + * does not guarantee that a future <tt>signal</tt> will awaken + * any threads. This method is designed primarily for use in + * monitoring of the system state. + * @param condition the condition + * @return <tt>true</tt> 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 condition 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 condition 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 condition null + */ + public final Collection<Thread> 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. + * + * <p> 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 + * <tt>AbstractQueuedSynchronizer</tt>. + * + * <p> 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 <tt>ConditionObject</tt> instance. + */ + public ConditionObject() { } + + // Internal methods + + /** + * Add a new waiter to wait queue + * @return its new wait node + */ + private Node addConditionWaiter() { + Node node = new Node(Thread.currentThread(), Node.CONDITION); + Node t = lastWaiter; + if (t == null) + firstWaiter = node; + else + t.nextWaiter = node; + lastWaiter = node; + return node; + } + + /** + * Remove and transfer 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); + } + + /** + * Remove and transfer 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); + } + + // 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 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 false + */ + public final void signalAll() { + if (!isHeldExclusively()) + throw new IllegalMonitorStateException(); + Node first = firstWaiter; + if (first != null) + doSignalAll(first); + } + + /** + * Implements uninterruptible condition wait. + * <ol> + * <li> Save lock state returned by {@link #getState} + * <li> Invoke {@link #release} with + * saved state as argument, throwing + * IllegalMonitorStateException if it fails. + * <li> Block until signalled + * <li> Reacquire by invoking specialized version of + * {@link #acquire} with saved state as argument. + * </ol> + */ + public final void awaitUninterruptibly() { + Node node = addConditionWaiter(); + int savedState = fullyRelease(node); + boolean interrupted = false; + while (!isOnSyncQueue(node)) { + LockSupport.park(); + 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; + + /** + * Check 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; + } + + /** + * Throw InterruptedException, reinterrupt current thread, or + * do nothing, depending on mode. + */ + private void reportInterruptAfterWait(int interruptMode) + throws InterruptedException { + if (interruptMode == THROW_IE) + throw new InterruptedException(); + else if (interruptMode == REINTERRUPT) + Thread.currentThread().interrupt(); + } + + /** + * Implements interruptible condition wait. + * <ol> + * <li> If current thread is interrupted, throw InterruptedException + * <li> Save lock state returned by {@link #getState} + * <li> Invoke {@link #release} with + * saved state as argument, throwing + * IllegalMonitorStateException if it fails. + * <li> Block until signalled or interrupted + * <li> Reacquire by invoking specialized version of + * {@link #acquire} with saved state as argument. + * <li> If interrupted while blocked in step 4, throw exception + * </ol> + * + * @throws InterruptedException if the current thread is interrupted (and + * interruption of thread suspension is supported). + */ + 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(); + if ((interruptMode = checkInterruptWhileWaiting(node)) != 0) + break; + } + if (acquireQueued(node, savedState) && interruptMode != THROW_IE) + interruptMode = REINTERRUPT; + if (interruptMode != 0) + reportInterruptAfterWait(interruptMode); + } + + /** + * Implements timed condition wait. + * <ol> + * <li> If current thread is interrupted, throw InterruptedException + * <li> Save lock state returned by {@link #getState} + * <li> Invoke {@link #release} with + * saved state as argument, throwing + * IllegalMonitorStateException if it fails. + * <li> Block until signalled, interrupted, or timed out + * <li> Reacquire by invoking specialized version of + * {@link #acquire} with saved state as argument. + * <li> If interrupted while blocked in step 4, throw InterruptedException + * </ol> + * + * + * @param nanosTimeout the maximum time to wait, in nanoseconds + * @return A value less than or equal to zero if the wait has + * timed out; otherwise an estimate, that + * is strictly less than the <tt>nanosTimeout</tt> argument, + * of the time still remaining when this method returned. + * + * @throws InterruptedException if the current thread is interrupted (and + * interruption of thread suspension is supported). + */ + 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(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 (interruptMode != 0) + reportInterruptAfterWait(interruptMode); + return nanosTimeout - (System.nanoTime() - lastTime); + } + + /** + * Implements absolute timed condition wait. + * <ol> + * <li> If current thread is interrupted, throw InterruptedException + * <li> Save lock state returned by {@link #getState} + * <li> Invoke {@link #release} with + * saved state as argument, throwing + * IllegalMonitorStateException if it fails. + * <li> Block until signalled, interrupted, or timed out + * <li> Reacquire by invoking specialized version of + * {@link #acquire} with saved state as argument. + * <li> If interrupted while blocked in step 4, throw InterruptedException + * <li> If timed out while blocked in step 4, return false, else true + * </ol> + * + * + * @param deadline the absolute time to wait until + * @return <tt>false</tt> if the deadline has + * elapsed upon return, else <tt>true</tt>. + * + * @throws InterruptedException if the current thread is interrupted (and + * interruption of thread suspension is supported). + */ + 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(abstime); + if ((interruptMode = checkInterruptWhileWaiting(node)) != 0) + break; + } + if (acquireQueued(node, savedState) && interruptMode != THROW_IE) + interruptMode = REINTERRUPT; + if (interruptMode != 0) + reportInterruptAfterWait(interruptMode); + return !timedout; + } + + /** + * Implements timed condition wait. + * <ol> + * <li> If current thread is interrupted, throw InterruptedException + * <li> Save lock state returned by {@link #getState} + * <li> Invoke {@link #release} with + * saved state as argument, throwing + * IllegalMonitorStateException if it fails. + * <li> Block until signalled, interrupted, or timed out + * <li> Reacquire by invoking specialized version of + * {@link #acquire} with saved state as argument. + * <li> If interrupted while blocked in step 4, throw InterruptedException + * <li> If timed out while blocked in step 4, return false, else true + * </ol> + * + * + * + * @param time the maximum time to wait + * @param unit the time unit of the <tt>time</tt> argument. + * @return <tt>false</tt> if the waiting time detectably elapsed + * before return from the method, else <tt>true</tt>. + * @throws InterruptedException if the current thread is interrupted (and + * interruption of thread suspension is supported). + */ + 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; + } + LockSupport.parkNanos(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 (interruptMode != 0) + reportInterruptAfterWait(interruptMode); + return !timedout; + } + + // support for instrumentation + + /** + * Returns true if this condition was created by the given + * synchronization object + * @return 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 <tt>true</tt> if there are any waiting threads. + * @throws IllegalMonitorStateException if {@link #isHeldExclusively} + * returns 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 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 false + */ + protected final Collection<Thread> getWaitingThreads() { + if (!isHeldExclusively()) + throw new IllegalMonitorStateException(); + ArrayList<Thread> list = new ArrayList<Thread>(); + 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). + */ + + // BEGIN android-changed + private static final Unsafe unsafe = UnsafeAccess.THE_ONE; + // END android-changed + + private static final long stateOffset; + private static final long headOffset; + private static final long tailOffset; + private static final long waitStatusOffset; + + 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")); + + } 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 final static boolean compareAndSetWaitStatus(Node node, + int expect, + int update) { + return unsafe.compareAndSwapInt(node, waitStatusOffset, + expect, update); + } + +} diff --git a/concurrent/src/main/java/java/util/concurrent/locks/Condition.java b/concurrent/src/main/java/java/util/concurrent/locks/Condition.java new file mode 100644 index 0000000..7a8ca5b --- /dev/null +++ b/concurrent/src/main/java/java/util/concurrent/locks/Condition.java @@ -0,0 +1,439 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent.locks; +import java.util.concurrent.*; +import java.util.Date; + +/** + * <tt>Condition</tt> factors out the <tt>Object</tt> 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 <tt>Lock</tt> replaces the use of <tt>synchronized</tt> methods + * and statements, a <tt>Condition</tt> replaces the use of the Object + * monitor methods. + * + * <p>Conditions (also known as <em>condition queues</em> or + * <em>condition variables</em>) 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 <em>atomically</em> releases the associated lock and + * suspends the current thread, just like <tt>Object.wait</tt>. + * + * <p>A <tt>Condition</tt> instance is intrinsically bound to a lock. + * To obtain a <tt>Condition</tt> instance for a particular {@link Lock} + * instance use its {@link Lock#newCondition newCondition()} method. + * + * <p>As an example, suppose we have a bounded buffer which supports + * <tt>put</tt> and <tt>take</tt> methods. If a + * <tt>take</tt> is attempted on an empty buffer, then the thread will block + * until an item becomes available; if a <tt>put</tt> is attempted on a + * full buffer, then the thread will block until a space becomes available. + * We would like to keep waiting <tt>put</tt> threads and <tt>take</tt> + * 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. + * <pre> + * class BoundedBuffer { + * <b>Lock lock = new ReentrantLock();</b> + * final Condition notFull = <b>lock.newCondition(); </b> + * final Condition notEmpty = <b>lock.newCondition(); </b> + * + * Object[] items = new Object[100]; + * int putptr, takeptr, count; + * + * public void put(Object x) throws InterruptedException { + * <b>lock.lock(); + * try {</b> + * while (count == items.length) + * <b>notFull.await();</b> + * items[putptr] = x; + * if (++putptr == items.length) putptr = 0; + * ++count; + * <b>notEmpty.signal();</b> + * <b>} finally { + * lock.unlock(); + * }</b> + * } + * + * public Object take() throws InterruptedException { + * <b>lock.lock(); + * try {</b> + * while (count == 0) + * <b>notEmpty.await();</b> + * Object x = items[takeptr]; + * if (++takeptr == items.length) takeptr = 0; + * --count; + * <b>notFull.signal();</b> + * return x; + * <b>} finally { + * lock.unlock(); + * }</b> + * } + * } + * </pre> + * + * (The {@link java.util.concurrent.ArrayBlockingQueue} class provides + * this functionality, so there is no reason to implement this + * sample usage class.) + * + * <p>A <tt>Condition</tt> implementation can provide behavior and semantics + * that is + * different from that of the <tt>Object</tt> 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. + * + * <p>Note that <tt>Condition</tt> instances are just normal objects and can + * themselves be used as the target in a <tt>synchronized</tt> statement, + * and can have their own monitor {@link Object#wait wait} and + * {@link Object#notify notification} methods invoked. + * Acquiring the monitor lock of a <tt>Condition</tt> instance, or using its + * monitor methods, has no specified relationship with acquiring the + * {@link Lock} associated with that <tt>Condition</tt> or the use of its + * {@link #await waiting} and {@link #signal signalling} methods. + * It is recommended that to avoid confusion you never use <tt>Condition</tt> + * instances in this way, except perhaps within their own implementation. + * + * <p>Except where noted, passing a <tt>null</tt> value for any parameter + * will result in a {@link NullPointerException} being thrown. + * + * <h3>Implementation Considerations</h3> + * + * <p>When waiting upon a <tt>Condition</tt>, a "<em>spurious + * wakeup</em>" 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 + * <tt>Condition</tt> 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. + * + * <p>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. + * <p>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. + * <p>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. + * <p>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. + * + * + * @since 1.5 + * @author Doug Lea + */ +public interface Condition { + + /** + * Causes the current thread to wait until it is signalled or + * {@link Thread#interrupt interrupted}. + * + * <p>The lock associated with this <tt>Condition</tt> is atomically + * released and the current thread becomes disabled for thread scheduling + * purposes and lies dormant until <em>one</em> of four things happens: + * <ul> + * <li>Some other thread invokes the {@link #signal} method for this + * <tt>Condition</tt> and the current thread happens to be chosen as the + * thread to be awakened; or + * <li>Some other thread invokes the {@link #signalAll} method for this + * <tt>Condition</tt>; or + * <li>Some other thread {@link Thread#interrupt interrupts} the current + * thread, and interruption of thread suspension is supported; or + * <li>A "<em>spurious wakeup</em>" occurs + * </ul> + * + * <p>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 <em>guaranteed</em> to hold this lock. + * + * <p>If the current thread: + * <ul> + * <li>has its interrupted status set on entry to this method; or + * <li>is {@link Thread#interrupt interrupted} while waiting + * and interruption of thread suspension is supported, + * </ul> + * 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. + * + * <p><b>Implementation Considerations</b> + * <p>The current thread is assumed to hold the lock associated with this + * <tt>Condition</tt> 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. + * + * <p>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. + * + * <p>The lock associated with this condition is atomically + * released and the current thread becomes disabled for thread scheduling + * purposes and lies dormant until <em>one</em> of three things happens: + * <ul> + * <li>Some other thread invokes the {@link #signal} method for this + * <tt>Condition</tt> and the current thread happens to be chosen as the + * thread to be awakened; or + * <li>Some other thread invokes the {@link #signalAll} method for this + * <tt>Condition</tt>; or + * <li>A "<em>spurious wakeup</em>" occurs + * </ul> + * + * <p>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 <em>guaranteed</em> to hold this lock. + * + * <p>If the current thread's interrupt status is set when it enters + * this method, or it is {@link Thread#interrupt interrupted} + * while waiting, it will continue to wait until signalled. When it finally + * returns from this method its <em>interrupted status</em> will still + * be set. + * + * <p><b>Implementation Considerations</b> + * <p>The current thread is assumed to hold the lock associated with this + * <tt>Condition</tt> 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. + * + * <p>The lock associated with this condition is atomically + * released and the current thread becomes disabled for thread scheduling + * purposes and lies dormant until <em>one</em> of five things happens: + * <ul> + * <li>Some other thread invokes the {@link #signal} method for this + * <tt>Condition</tt> and the current thread happens to be chosen as the + * thread to be awakened; or + * <li>Some other thread invokes the {@link #signalAll} method for this + * <tt>Condition</tt>; or + * <li>Some other thread {@link Thread#interrupt interrupts} the current + * thread, and interruption of thread suspension is supported; or + * <li>The specified waiting time elapses; or + * <li>A "<em>spurious wakeup</em>" occurs. + * </ul> + * + * <p>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 <em>guaranteed</em> to hold this lock. + * + * <p>If the current thread: + * <ul> + * <li>has its interrupted status set on entry to this method; or + * <li>is {@link Thread#interrupt interrupted} while waiting + * and interruption of thread suspension is supported, + * </ul> + * 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. + * + * <p>The method returns an estimate of the number of nanoseconds + * remaining to wait given the supplied <tt>nanosTimeout</tt> + * 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: + * + * <pre> + * synchronized boolean aMethod(long timeout, TimeUnit unit) { + * long nanosTimeout = unit.toNanos(timeout); + * while (!conditionBeingWaitedFor) { + * if (nanosTimeout > 0) + * nanosTimeout = theCondition.awaitNanos(nanosTimeout); + * else + * return false; + * } + * // ... + * } + * </pre> + * + * <p> 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. + * + * <p><b>Implementation Considerations</b> + * <p>The current thread is assumed to hold the lock associated with this + * <tt>Condition</tt> 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. + * + * <p>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 A value less than or equal to zero if the wait has + * timed out; otherwise an estimate, that + * is strictly less than the <tt>nanosTimeout</tt> argument, + * of the time still remaining when this method returned. + * + * @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:<br> + * <pre> + * awaitNanos(unit.toNanos(time)) > 0 + * </pre> + * @param time the maximum time to wait + * @param unit the time unit of the <tt>time</tt> argument. + * @return <tt>false</tt> if the waiting time detectably elapsed + * before return from the method, else <tt>true</tt>. + * @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. + * + * <p>The lock associated with this condition is atomically + * released and the current thread becomes disabled for thread scheduling + * purposes and lies dormant until <em>one</em> of five things happens: + * <ul> + * <li>Some other thread invokes the {@link #signal} method for this + * <tt>Condition</tt> and the current thread happens to be chosen as the + * thread to be awakened; or + * <li>Some other thread invokes the {@link #signalAll} method for this + * <tt>Condition</tt>; or + * <li>Some other thread {@link Thread#interrupt interrupts} the current + * thread, and interruption of thread suspension is supported; or + * <li>The specified deadline elapses; or + * <li>A "<em>spurious wakeup</em>" occurs. + * </ul> + * + * <p>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 <em>guaranteed</em> to hold this lock. + * + * + * <p>If the current thread: + * <ul> + * <li>has its interrupted status set on entry to this method; or + * <li>is {@link Thread#interrupt interrupted} while waiting + * and interruption of thread suspension is supported, + * </ul> + * 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. + * + * + * <p>The return value indicates whether the deadline has elapsed, + * which can be used as follows: + * <pre> + * synchronized boolean aMethod(Date deadline) { + * boolean stillWaiting = true; + * while (!conditionBeingWaitedFor) { + * if (stillwaiting) + * stillWaiting = theCondition.awaitUntil(deadline); + * else + * return false; + * } + * // ... + * } + * </pre> + * + * <p><b>Implementation Considerations</b> + * <p>The current thread is assumed to hold the lock associated with this + * <tt>Condition</tt> 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. + * + * <p>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 <tt>false</tt> if the deadline has + * elapsed upon return, else <tt>true</tt>. + * + * @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. + * + * <p>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 <tt>await</tt>. + **/ + void signal(); + + /** + * Wakes up all waiting threads. + * + * <p>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 <tt>await</tt>. + **/ + void signalAll(); + +} + + + + + + + diff --git a/concurrent/src/main/java/java/util/concurrent/locks/Lock.java b/concurrent/src/main/java/java/util/concurrent/locks/Lock.java new file mode 100644 index 0000000..f07b72e --- /dev/null +++ b/concurrent/src/main/java/java/util/concurrent/locks/Lock.java @@ -0,0 +1,329 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent.locks; +import java.util.concurrent.TimeUnit; + +/** + * <tt>Lock</tt> implementations provide more extensive locking + * operations than can be obtained using <tt>synchronized</tt> methods + * and statements. They allow more flexible structuring, may have + * quite different properties, and may support multiple associated + * {@link Condition} objects. + * + * <p>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}. + * + * <p>The use of <tt>synchronized</tt> 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. + * + * <p>While the scoping mechanism for <tt>synchronized</tt> 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 + * <tt>Lock</tt> 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. + * + * <p>With this increased flexibility comes additional + * responsibility. The absence of block-structured locking removes the + * automatic release of locks that occurs with <tt>synchronized</tt> + * methods and statements. In most cases, the following idiom + * should be used: + * + * <pre><tt> Lock l = ...; + * l.lock(); + * try { + * // access the resource protected by this lock + * } finally { + * l.unlock(); + * } + * </tt></pre> + * + * 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. + * + * <p><tt>Lock</tt> implementations provide additional functionality + * over the use of <tt>synchronized</tt> 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)}). + * + * <p>A <tt>Lock</tt> 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. + * + * <p>Note that <tt>Lock</tt> instances are just normal objects and can + * themselves be used as the target in a <tt>synchronized</tt> statement. + * Acquiring the + * monitor lock of a <tt>Lock</tt> 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 <tt>Lock</tt> + * instances in this way, except within their own implementation. + * + * <p>Except where noted, passing a <tt>null</tt> value for any + * parameter will result in a {@link NullPointerException} being + * thrown. + * + * <h3>Memory Synchronization</h3> + * <p>All <tt>Lock</tt> implementations <em>must</em> enforce the same + * memory synchronization semantics as provided by the built-in monitor lock: + * <ul> + * <li>A successful lock operation acts like a successful + * <tt>monitorEnter</tt> action + * <li>A successful <tt>unlock</tt> operation acts like a successful + * <tt>monitorExit</tt> action + * </ul> + * + * Unsuccessful locking and unlocking operations, and reentrant + * locking/unlocking operations, do not require any memory + * synchronization effects. + * + * <h3>Implementation Considerations</h3> + * + * <p> 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 <em>ongoing</em> + * acquisition of a lock may not be available in a given <tt>Lock</tt> + * 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. + * + * <p>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. + * <p>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. + * <p><b>Implementation Considerations</b> + * <p>A <tt>Lock</tt> 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 + * <tt>Lock</tt> implementation. + * + **/ + void lock(); + + /** + * Acquires the lock unless the current thread is + * {@link Thread#interrupt interrupted}. + * <p>Acquires the lock if it is available and returns immediately. + * <p>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: + * <ul> + * <li>The lock is acquired by the current thread; or + * <li>Some other thread {@link Thread#interrupt interrupts} the current + * thread, and interruption of lock acquisition is supported. + * </ul> + * <p>If the current thread: + * <ul> + * <li>has its interrupted status set on entry to this method; or + * <li>is {@link Thread#interrupt interrupted} while acquiring + * the lock, and interruption of lock acquisition is supported, + * </ul> + * then {@link InterruptedException} is thrown and the current thread's + * interrupted status is cleared. + * + * <p><b>Implementation Considerations</b> + * + * <p>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. + * + * <p>An implementation can favor responding to an interrupt over + * normal method return. + * + * <p>A <tt>Lock</tt> 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 <tt>Lock</tt> implementation. + * + * @throws InterruptedException if the current thread is interrupted + * while acquiring the lock (and interruption of lock acquisition is + * supported). + * + * @see Thread#interrupt + * + **/ + void lockInterruptibly() throws InterruptedException; + + + /** + * Acquires the lock only if it is free at the time of invocation. + * <p>Acquires the lock if it is available and returns immediately + * with the value <tt>true</tt>. + * If the lock is not available then this method will return + * immediately with the value <tt>false</tt>. + * <p>A typical usage idiom for this method would be: + * <pre> + * Lock lock = ...; + * if (lock.tryLock()) { + * try { + * // manipulate protected state + * } finally { + * lock.unlock(); + * } + * } else { + * // perform alternative actions + * } + * </pre> + * 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 <tt>true</tt> if the lock was acquired and <tt>false</tt> + * otherwise. + **/ + boolean tryLock(); + + /** + * Acquires the lock if it is free within the given waiting time and the + * current thread has not been {@link Thread#interrupt interrupted}. + * + * <p>If the lock is available this method returns immediately + * with the value <tt>true</tt>. + * 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: + * <ul> + * <li>The lock is acquired by the current thread; or + * <li>Some other thread {@link Thread#interrupt interrupts} the current + * thread, and interruption of lock acquisition is supported; or + * <li>The specified waiting time elapses + * </ul> + * <p>If the lock is acquired then the value <tt>true</tt> is returned. + * <p>If the current thread: + * <ul> + * <li>has its interrupted status set on entry to this method; or + * <li>is {@link Thread#interrupt interrupted} while acquiring + * the lock, and interruption of lock acquisition is supported, + * </ul> + * then {@link InterruptedException} is thrown and the current thread's + * interrupted status is cleared. + * <p>If the specified waiting time elapses then the value <tt>false</tt> + * is returned. + * If the time is + * less than or equal to zero, the method will not wait at all. + * + * <p><b>Implementation Considerations</b> + * <p>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. + * <p>An implementation can favor responding to an interrupt over normal + * method return, or reporting a timeout. + * <p>A <tt>Lock</tt> 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 + * <tt>Lock</tt> implementation. + * + * @param time the maximum time to wait for the lock + * @param unit the time unit of the <tt>time</tt> argument. + * @return <tt>true</tt> if the lock was acquired and <tt>false</tt> + * 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). + * + * @see Thread#interrupt + * + **/ + boolean tryLock(long time, TimeUnit unit) throws InterruptedException; + + /** + * Releases the lock. + * <p><b>Implementation Considerations</b> + * <p>A <tt>Lock</tt> 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 <tt>Lock</tt> implementation. + **/ + void unlock(); + + /** + * Returns a new {@link Condition} instance that is bound to this + * <tt>Lock</tt> instance. + * <p>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. + * <p><b>Implementation Considerations</b> + * <p>The exact operation of the {@link Condition} instance depends on the + * <tt>Lock</tt> implementation and must be documented by that + * implementation. + * + * @return A new {@link Condition} instance for this <tt>Lock</tt> + * instance. + * @throws UnsupportedOperationException if this <tt>Lock</tt> + * implementation does not support conditions. + **/ + Condition newCondition(); + +} + + + + + + + + + + + + diff --git a/concurrent/src/main/java/java/util/concurrent/locks/LockSupport.java b/concurrent/src/main/java/java/util/concurrent/locks/LockSupport.java new file mode 100644 index 0000000..8603785 --- /dev/null +++ b/concurrent/src/main/java/java/util/concurrent/locks/LockSupport.java @@ -0,0 +1,178 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent.locks; +import java.util.concurrent.*; +import sun.misc.Unsafe; + + +/** + * Basic thread blocking primitives for creating locks and other + * synchronization classes. + * + * <p>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 <tt>park</tt> will return immediately + * if the permit is available, consuming it in the process; otherwise + * it <em>may</em> block. A call to <tt>unpark</tt> makes the permit + * available, if it was not already available. (Unlike with Semaphores + * though, permits do not accumulate. There is at most one.) + * + * <p>Methods <tt>park</tt> and <tt>unpark</tt> provide efficient + * means of blocking and unblocking threads that do not encounter the + * problems that cause the deprecated methods <tt>Thread.suspend</tt> + * and <tt>Thread.resume</tt> to be unusable for such purposes: Races + * between one thread invoking <tt>park</tt> and another thread trying + * to <tt>unpark</tt> it will preserve liveness, due to the + * permit. Additionally, <tt>park</tt> will return if the caller's + * thread was interrupted, and timeout versions are supported. The + * <tt>park</tt> 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 <tt>park</tt> serves as an + * optimization of a "busy wait" that does not waste as much time + * spinning, but must be paired with an <tt>unpark</tt> to be + * effective. + * + * <p>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. + * + * <p><b>Sample Usage.</b> Here is a sketch of a First-in-first-out + * non-reentrant lock class. + * <pre> + * private AtomicBoolean locked = new AtomicBoolean(false); + * private Queue<Thread> waiters = new ConcurrentLinkedQueue<Thread>(); + * + * 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(); + * 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()); + * } + * } + * </pre> + */ +@SuppressWarnings("all") +public class LockSupport { + private LockSupport() {} // Cannot be instantiated. + + // BEGIN android-changed + private static final Unsafe unsafe = UnsafeAccess.THE_ONE; + // END android-changed + + /** + * Make available the permit for the given thread, if it + * was not already available. If the thread was blocked on + * <tt>park</tt> then it will unblock. Otherwise, its next call + * to <tt>park</tt> 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 <tt>null</tt>, 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. + * <p>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: + * <ul> + * <li>Some other thread invokes <tt>unpark</tt> with the current thread + * as the target; or + * <li>Some other thread {@link Thread#interrupt interrupts} the current + * thread; or + * <li>The call spuriously (that is, for no reason) returns. + * </ul> + * <p>This method does <em>not</em> 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. + * <p>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: + * <ul> + * <li>Some other thread invokes <tt>unpark</tt> with the current thread + * as the target; or + * <li>Some other thread {@link Thread#interrupt interrupts} the current + * thread; or + * <li>The specified waiting time elapses; or + * <li>The call spuriously (that is, for no reason) returns. + * </ul> + * <p>This method does <em>not</em> 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. + * <p>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: + * <ul> + * <li>Some other thread invokes <tt>unpark</tt> with the current thread + * as the target; or + * <li>Some other thread {@link Thread#interrupt interrupts} the current + * thread; or + * <li>The specified deadline passes; or + * <li>The call spuriously (that is, for no reason) returns. + * </ul> + * <p>This method does <em>not</em> 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 --git a/concurrent/src/main/java/java/util/concurrent/locks/ReadWriteLock.java b/concurrent/src/main/java/java/util/concurrent/locks/ReadWriteLock.java new file mode 100644 index 0000000..c7116d5 --- /dev/null +++ b/concurrent/src/main/java/java/util/concurrent/locks/ReadWriteLock.java @@ -0,0 +1,97 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent.locks; + +/** + * A <tt>ReadWriteLock</tt> 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. + * + * <p>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 + * <em>writer</em> thread) can modify the shared data, in many cases any + * number of threads can concurrently read the data (hence <em>reader</em> + * 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. + * + * <p>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. + * + * + * <p>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: + * <ul> + * <li>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. + * + * <li>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 write can reduce the potential for concurrency. + * + * <li>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? + * + * <li>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? + * + * </ul> + * 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 --git a/concurrent/src/main/java/java/util/concurrent/locks/ReentrantLock.java b/concurrent/src/main/java/java/util/concurrent/locks/ReentrantLock.java new file mode 100644 index 0000000..bf3d653 --- /dev/null +++ b/concurrent/src/main/java/java/util/concurrent/locks/ReentrantLock.java @@ -0,0 +1,727 @@ +/* + * 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/licenses/publicdomain + */ + +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 + * <tt>synchronized</tt> methods and statements, but with extended + * capabilities. + * + * <p> A <tt>ReentrantLock</tt> is <em>owned</em> by the thread last + * successfully locking, but not yet unlocking it. A thread invoking + * <tt>lock</tt> 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}. + * + * <p> The constructor for this class accepts an optional + * <em>fairness</em> parameter. When set <tt>true</tt>, 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. + * + * <p> It is recommended practice to <em>always</em> immediately + * follow a call to <tt>lock</tt> with a <tt>try</tt> block, most + * typically in a before/after construction such as: + * + * <pre> + * class X { + * private final ReentrantLock lock = new ReentrantLock(); + * // ... + * + * public void m() { + * lock.lock(); // block until condition holds + * try { + * // ... method body + * } finally { + * lock.unlock() + * } + * } + * } + * </pre> + * + * <p>In addition to implementing the {@link Lock} interface, this + * class defines methods <tt>isLocked</tt> and + * <tt>getLockQueueLength</tt>, as well as some associated + * <tt>protected</tt> access methods that may be useful for + * instrumentation and monitoring. + * + * <p> 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. + * + * <p> This lock supports a maximum of 2147483648 recursive locks by + * the same thread. + * + * @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. + */ + static abstract class Sync extends AbstractQueuedSynchronizer { + /** Current owner thread */ + transient Thread owner; + + /** + * Perform {@link Lock#lock}. The main reason for subclassing + * is to allow fast path for nonfair version. + */ + abstract void lock(); + + /** + * Perform 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)) { + owner = current; + return true; + } + } + else if (current == owner) { + setState(c+acquires); + return true; + } + return false; + } + + protected final boolean tryRelease(int releases) { + int c = getState() - releases; + if (Thread.currentThread() != owner) + throw new IllegalMonitorStateException(); + boolean free = false; + if (c == 0) { + free = true; + owner = null; + } + setState(c); + return free; + } + + protected final boolean isHeldExclusively() { + return getState() != 0 && owner == Thread.currentThread(); + } + + final ConditionObject newCondition() { + return new ConditionObject(); + } + + // Methods relayed from outer class + + final Thread getOwner() { + int c = getState(); + Thread o = owner; + return (c == 0)? null : o; + } + + final int getHoldCount() { + int c = getState(); + Thread o = owner; + return (o == Thread.currentThread())? c : 0; + } + + final boolean isLocked() { + return getState() != 0; + } + + /** + * 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(); + setState(0); // reset to unlocked state + } + } + + /** + * Sync object for non-fair locks + */ + final static class NonfairSync extends Sync { + /** + * Perform lock. Try immediate barge, backing up to normal + * acquire on failure. + */ + final void lock() { + if (compareAndSetState(0, 1)) + owner = Thread.currentThread(); + else + acquire(1); + } + + protected final boolean tryAcquire(int acquires) { + return nonfairTryAcquire(acquires); + } + } + + /** + * Sync object for fair locks + */ + final static class FairSync extends Sync { + 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) { + Thread first = getFirstQueuedThread(); + if ((first == null || first == current) && + compareAndSetState(0, acquires)) { + owner = current; + return true; + } + } + else if (current == owner) { + setState(c+acquires); + return true; + } + return false; + } + } + + /** + * Creates an instance of <tt>ReentrantLock</tt>. + * This is equivalent to using <tt>ReentrantLock(false)</tt>. + */ + public ReentrantLock() { + sync = new NonfairSync(); + } + + /** + * Creates an instance of <tt>ReentrantLock</tt> with the + * given fairness policy. + * @param fair true if this lock will be fair; else false + */ + public ReentrantLock(boolean fair) { + sync = (fair)? new FairSync() : new NonfairSync(); + } + + /** + * Acquires the lock. + * + * <p>Acquires the lock if it is not held by another thread and returns + * immediately, setting the lock hold count to one. + * + * <p>If the current thread + * already holds the lock then the hold count is incremented by one and + * the method returns immediately. + * + * <p>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 + * {@link Thread#interrupt interrupted}. + * + * <p>Acquires the lock if it is not held by another thread and returns + * immediately, setting the lock hold count to one. + * + * <p>If the current thread already holds this lock then the hold count + * is incremented by one and the method returns immediately. + * + * <p>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: + * + * <ul> + * + * <li>The lock is acquired by the current thread; or + * + * <li>Some other thread {@link Thread#interrupt interrupts} the current + * thread. + * + * </ul> + * + * <p>If the lock is acquired by the current thread then the lock hold + * count is set to one. + * + * <p>If the current thread: + * + * <ul> + * + * <li>has its interrupted status set on entry to this method; or + * + * <li>is {@link Thread#interrupt interrupted} while acquiring + * the lock, + * + * </ul> + * + * then {@link InterruptedException} is thrown and the current thread's + * interrupted status is cleared. + * + * <p>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. + * + * <p>Acquires the lock if it is not held by another thread and + * returns immediately with the value <tt>true</tt>, setting the + * lock hold count to one. Even when this lock has been set to use a + * fair ordering policy, a call to <tt>tryLock()</tt> <em>will</em> + * 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). + * + * <p> If the current thread + * already holds this lock then the hold count is incremented by one and + * the method returns <tt>true</tt>. + * + * <p>If the lock is held by another thread then this method will return + * immediately with the value <tt>false</tt>. + * + * @return <tt>true</tt> if the lock was free and was acquired by the + * current thread, or the lock was already held by the current thread; and + * <tt>false</tt> 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 + * {@link Thread#interrupt interrupted}. + * + * <p>Acquires the lock if it is not held by another thread and returns + * immediately with the value <tt>true</tt>, setting the lock hold count + * to one. If this lock has been set to use a fair ordering policy then + * an available lock <em>will not</em> 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 <tt>tryLock</tt> that does permit barging on + * a fair lock then combine the timed and un-timed forms together: + * + * <pre>if (lock.tryLock() || lock.tryLock(timeout, unit) ) { ... } + * </pre> + * + * <p>If the current thread + * already holds this lock then the hold count is incremented by one and + * the method returns <tt>true</tt>. + * + * <p>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: + * + * <ul> + * + * <li>The lock is acquired by the current thread; or + * + * <li>Some other thread {@link Thread#interrupt interrupts} the current + * thread; or + * + * <li>The specified waiting time elapses + * + * </ul> + * + * <p>If the lock is acquired then the value <tt>true</tt> is returned and + * the lock hold count is set to one. + * + * <p>If the current thread: + * + * <ul> + * + * <li>has its interrupted status set on entry to this method; or + * + * <li>is {@link Thread#interrupt interrupted} while acquiring + * the lock, + * + * </ul> + * then {@link InterruptedException} is thrown and the current thread's + * interrupted status is cleared. + * + * <p>If the specified waiting time elapses then the value <tt>false</tt> + * is returned. + * If the time is + * less than or equal to zero, the method will not wait at all. + * + * <p>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 <tt>true</tt> if the lock was free and was acquired by the + * current thread, or the lock was already held by the current thread; and + * <tt>false</tt> if the waiting time elapsed before the lock could be + * acquired. + * + * @throws InterruptedException if the current thread is interrupted + * @throws NullPointerException if unit is null + * + */ + public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException { + return sync.tryAcquireNanos(1, unit.toNanos(timeout)); + } + + /** + * Attempts to release this lock. + * + * <p>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. + * + * <p>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. + * + * <ul> + * + * <li>If this lock is not held when any of the {@link Condition} + * {@link Condition#await() waiting} or {@link Condition#signal + * signalling} methods are called, then an {@link + * IllegalMonitorStateException} is thrown. + * + * <li>When the condition {@link 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. + * + * <li>If a thread is {@link 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. + * + * <li> Waiting threads are signalled in FIFO order + * + * <li>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 <em>fair</em> locks favors those threads that have been + * waiting the longest. + * + * </ul> + * + * @return the Condition object + */ + public Condition newCondition() { + return sync.newCondition(); + } + + /** + * Queries the number of holds on this lock by the current thread. + * + * <p>A thread has a hold on a lock for each lock action that is not + * matched by an unlock action. + * + * <p>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: + * + * <pre> + * class X { + * ReentrantLock lock = new ReentrantLock(); + * // ... + * public void m() { + * assert lock.getHoldCount() == 0; + * lock.lock(); + * try { + * // ... method body + * } finally { + * lock.unlock(); + * } + * } + * } + * </pre> + * + * @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. + * + * <p>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: + * + * <pre> + * class X { + * ReentrantLock lock = new ReentrantLock(); + * // ... + * + * public void m() { + * assert lock.isHeldByCurrentThread(); + * // ... method body + * } + * } + * </pre> + * + * <p>It can also be used to ensure that a reentrant lock is used + * in a non-reentrant manner, for example: + * + * <pre> + * class X { + * ReentrantLock lock = new ReentrantLock(); + * // ... + * + * public void m() { + * assert !lock.isHeldByCurrentThread(); + * lock.lock(); + * try { + * // ... method body + * } finally { + * lock.unlock(); + * } + * } + * } + * </pre> + * @return <tt>true</tt> if current thread holds this lock and + * <tt>false</tt> 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 <tt>true</tt> if any thread holds this lock and + * <tt>false</tt> otherwise. + */ + public boolean isLocked() { + return sync.isLocked(); + } + + /** + * Returns true if this lock has fairness set true. + * @return true if this lock has fairness set true. + */ + public final boolean isFair() { + return sync instanceof FairSync; + } + + /** + * Returns the thread that currently owns the exclusive lock, or + * <tt>null</tt> if not owned. Note that the owner may be + * momentarily <tt>null</tt> 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 <tt>null</tt> if not owned. + */ + protected Thread getOwner() { + return sync.getOwner(); + } + + /** + * Queries whether any threads are waiting to acquire. Note that + * because cancellations may occur at any time, a <tt>true</tt> + * 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 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 + * <tt>true</tt> return does not guarantee that this thread + * will ever acquire. This method is designed primarily for use + * in monitoring of the system state. + * + * @param thread the thread + * @return true if the given thread is queued waiting for this lock. + * @throws NullPointerException if thread is null + */ + public final boolean hasQueuedThread(Thread thread) { + return sync.isQueued(thread); + } + + + /** + * 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<Thread> 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 <tt>true</tt> return does + * not guarantee that a future <tt>signal</tt> will awaken any + * threads. This method is designed primarily for use in + * monitoring of the system state. + * @param condition the condition + * @return <tt>true</tt> 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 condition 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 condition 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 condition null + */ + protected Collection<Thread> 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 + * "Unlocked" or the String "Locked by" + * followed by the {@link Thread#getName} of the owning thread. + * @return a string identifying this lock, as well as its lock state. + */ + public String toString() { + Thread owner = sync.getOwner(); + return super.toString() + ((owner == null) ? + "[Unlocked]" : + "[Locked by thread " + owner.getName() + "]"); + } +} diff --git a/concurrent/src/main/java/java/util/concurrent/locks/ReentrantReadWriteLock.java b/concurrent/src/main/java/java/util/concurrent/locks/ReentrantReadWriteLock.java new file mode 100644 index 0000000..95fc7af --- /dev/null +++ b/concurrent/src/main/java/java/util/concurrent/locks/ReentrantReadWriteLock.java @@ -0,0 +1,1119 @@ +/* + * 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/licenses/publicdomain + */ + +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}. + * <p>This class has the following properties: + * + * <ul> + * <li><b>Acquisition order</b> + * + * <p> This class does not impose a reader or writer preference + * ordering for lock access. However, it does support an optional + * <em>fairness</em> policy. When constructed as fair, threads + * contend for entry using an approximately arrival-order policy. When + * the write lock is released either the longest-waiting single writer + * will be assigned the write lock, or if there is a reader waiting + * longer than any writer, the set of readers will be assigned the + * read lock. When constructed as non-fair, the order of entry to the + * lock need not be in arrival order. In either case, if readers are + * active and a writer enters the lock then no subsequent readers will + * be granted the read lock until after that writer has acquired and + * released the write lock. + * + * <li><b>Reentrancy</b> + * <p>This lock allows both readers and writers to reacquire read or + * write locks in the style of a {@link ReentrantLock}. Readers are not + * allowed until all write locks held by the writing thread have been + * released. + * <p>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. + * + * <li><b>Lock downgrading</b> + * <p>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 + * <b>not</b> possible. + * + * <li><b>Interruption of lock acquisition</b> + * <p>The read lock and write lock both support interruption during lock + * acquisition. + * + * <li><b>{@link Condition} support</b> + * <p>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. + * <p>The read lock does not support a {@link Condition} and + * <tt>readLock().newCondition()</tt> throws + * <tt>UnsupportedOperationException</tt>. + * + * <li><b>Instrumentation</b> + * <P> This class supports methods to determine whether locks + * are held or contended. These methods are designed for monitoring + * system state, not for synchronization control. + * </ul> + * + * <p> 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. + * + * <p><b>Sample usages</b>. Here is a code sketch showing how to exploit + * reentrancy to perform lock downgrading after updating a cache (exception + * handling is elided for simplicity): + * <pre> + * class CachedData { + * Object data; + * volatile boolean cacheValid; + * ReentrantReadWriteLock rwl = new ReentrantReadWriteLock(); + * + * void processCachedData() { + * rwl.readLock().lock(); + * if (!cacheValid) { + * // upgrade lock manually + * rwl.readLock().unlock(); // must unlock first to obtain writelock + * rwl.writeLock().lock(); + * if (!cacheValid) { // recheck + * data = ... + * cacheValid = true; + * } + * // downgrade lock + * rwl.readLock().lock(); // reacquire read without giving up write lock + * rwl.writeLock().unlock(); // unlock write, still hold read + * } + * + * use(data); + * rwl.readLock().unlock(); + * } + * } + * </pre> + * + * 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. + * + * <pre> + * class RWDictionary { + * private final Map<String, Data> m = new TreeMap<String, Data>(); + * 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(); } + * } + * } + * </pre> + * + * + * <h3>Implementation Notes</h3> + * + * <p>A reentrant write lock intrinsically defines an owner and can + * only be released by the thread that acquired it. In contrast, in + * this implementation, the read lock has no concept of ownership, and + * there is no requirement that the thread releasing a read lock is + * the same as the one that acquired it. However, this property is + * not guaranteed to hold in future implementations of this class. + * + * <p> This lock supports a maximum of 65536 recursive write locks + * and 65536 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 */ + private final Sync sync; + + /** + * Creates a new <tt>ReentrantReadWriteLock</tt> with + * default ordering properties. + */ + public ReentrantReadWriteLock() { + sync = new NonfairSync(); + readerLock = new ReadLock(this); + writerLock = new WriteLock(this); + } + + /** + * Creates a new <tt>ReentrantReadWriteLock</tt> with + * the given fairness policy. + * + * @param fair 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; } + + /* + * Read vs write count extraction constants and functions. + * Lock state is logically divided into two 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 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; } + + /** + * Synchronization implementation for ReentrantReadWriteLock. + * Subclassed into fair and nonfair versions. + */ + abstract static class Sync extends AbstractQueuedSynchronizer { + /** Current (exclusive) owner thread */ + transient Thread owner; + + /** + * Perform write lock. Allows fast path in non-fair version. + */ + abstract void wlock(); + + /** + * Perform non-fair tryLock for write. tryAcquire is + * implemented in subclasses, but both versions need nonfair + * try for trylock method + */ + final boolean nonfairTryAcquire(int acquires) { + // mask out readlocks if called from condition methods + acquires = exclusiveCount(acquires); + Thread current = Thread.currentThread(); + int c = getState(); + int w = exclusiveCount(c); + if (w + acquires >= SHARED_UNIT) + throw new Error("Maximum lock count exceeded"); + if (c != 0 && (w == 0 || current != owner)) + return false; + if (!compareAndSetState(c, c + acquires)) + return false; + owner = current; + return true; + } + + /** + * Perform nonfair tryLock for read. + */ + final int nonfairTryAcquireShared(int acquires) { + for (;;) { + int c = getState(); + int nextc = c + (acquires << SHARED_SHIFT); + if (nextc < c) + throw new Error("Maximum lock count exceeded"); + if (exclusiveCount(c) != 0 && + owner != Thread.currentThread()) + return -1; + if (compareAndSetState(c, nextc)) + return 1; + // Recheck count if lost CAS + } + } + + protected final boolean tryRelease(int releases) { + Thread current = Thread.currentThread(); + int c = getState(); + if (owner != current) + throw new IllegalMonitorStateException(); + int nextc = c - releases; + boolean free = false; + if (exclusiveCount(c) == releases) { + free = true; + owner = null; + } + setState(nextc); + return free; + } + + protected final boolean tryReleaseShared(int releases) { + for (;;) { + int c = getState(); + int nextc = c - (releases << SHARED_SHIFT); + if (nextc < 0) + throw new IllegalMonitorStateException(); + if (compareAndSetState(c, nextc)) + return nextc == 0; + } + } + + protected final boolean isHeldExclusively() { + return exclusiveCount(getState()) != 0 && + owner == Thread.currentThread(); + } + + // Methods relayed to outer class + + final ConditionObject newCondition() { + return new ConditionObject(); + } + + final Thread getOwner() { + int c = exclusiveCount(getState()); + Thread o = owner; + return (c == 0)? null : o; + } + + final int getReadLockCount() { + return sharedCount(getState()); + } + + final boolean isWriteLocked() { + return exclusiveCount(getState()) != 0; + } + + final int getWriteHoldCount() { + int c = exclusiveCount(getState()); + Thread o = owner; + return (o == Thread.currentThread())? c : 0; + } + + /** + * 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(); + setState(0); // reset to unlocked state + } + + final int getCount() { return getState(); } + } + + /** + * Nonfair version of Sync + */ + final static class NonfairSync extends Sync { + protected final boolean tryAcquire(int acquires) { + return nonfairTryAcquire(acquires); + } + + protected final int tryAcquireShared(int acquires) { + return nonfairTryAcquireShared(acquires); + } + + // Use fastpath for main write lock method + final void wlock() { + if (compareAndSetState(0, 1)) + owner = Thread.currentThread(); + else + acquire(1); + } + } + + /** + * Fair version of Sync + */ + final static class FairSync extends Sync { + protected final boolean tryAcquire(int acquires) { + // mask out readlocks if called from condition methods + acquires = exclusiveCount(acquires); + Thread current = Thread.currentThread(); + Thread first; + int c = getState(); + int w = exclusiveCount(c); + if (w + acquires >= SHARED_UNIT) + throw new Error("Maximum lock count exceeded"); + if ((w == 0 || current != owner) && + (c != 0 || + ((first = getFirstQueuedThread()) != null && + first != current))) + return false; + if (!compareAndSetState(c, c + acquires)) + return false; + owner = current; + return true; + } + + protected final int tryAcquireShared(int acquires) { + Thread current = Thread.currentThread(); + for (;;) { + Thread first = getFirstQueuedThread(); + if (first != null && first != current) + return -1; + int c = getState(); + int nextc = c + (acquires << SHARED_SHIFT); + if (nextc < c) + throw new Error("Maximum lock count exceeded"); + if (exclusiveCount(c) != 0 && + owner != Thread.currentThread()) + return -1; + if (compareAndSetState(c, nextc)) + return 1; + // Recheck count if lost CAS + } + } + + final void wlock() { // no fast path + acquire(1); + } + } + + /** + * 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 lock null + */ + protected ReadLock(ReentrantReadWriteLock lock) { + sync = lock.sync; + } + + /** + * Acquires the shared lock. + * + * <p>Acquires the lock if it is not held exclusively by + * another thread and returns immediately. + * + * <p>If the lock is held exclusively by another thread then + * the current thread becomes disabled for thread scheduling + * purposes and lies dormant until the lock has been acquired. + */ + public void lock() { + sync.acquireShared(1); + } + + /** + * Acquires the shared lock unless the current thread is + * {@link Thread#interrupt interrupted}. + * + * <p>Acquires the shared lock if it is not held exclusively + * by another thread and returns immediately. + * + * <p>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: + * + * <ul> + * + * <li>The lock is acquired by the current thread; or + * + * <li>Some other thread {@link Thread#interrupt interrupts} + * the current thread. + * + * </ul> + * + * <p>If the current thread: + * + * <ul> + * + * <li>has its interrupted status set on entry to this method; or + * + * <li>is {@link Thread#interrupt interrupted} while acquiring + * the lock, + * + * </ul> + * + * then {@link InterruptedException} is thrown and the current + * thread's interrupted status is cleared. + * + * <p>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 shared lock only if it is not held exclusively by + * another thread at the time of invocation. + * + * <p>Acquires the lock if it is not held exclusively by + * another thread and returns immediately with the value + * <tt>true</tt>. Even when this lock has been set to use a + * fair ordering policy, a call to <tt>tryLock()</tt> + * <em>will</em> 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). + * + * <p>If the lock is held exclusively by another thread then + * this method will return immediately with the value + * <tt>false</tt>. + * + * @return <tt>true</tt> if the lock was acquired. + */ + public boolean tryLock() { + return sync.nonfairTryAcquireShared(1) >= 0; + } + + /** + * Acquires the shared lock if it is not held exclusively by + * another thread within the given waiting time and the + * current thread has not been {@link Thread#interrupt + * interrupted}. + * + * <p>Acquires the lock if it is not held exclusively by + * another thread and returns immediately with the value + * <tt>true</tt>. If this lock has been set to use a fair + * ordering policy then an available lock <em>will not</em> 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 <tt>tryLock</tt> that does + * permit barging on a fair lock then combine the timed and + * un-timed forms together: + * + * <pre>if (lock.tryLock() || lock.tryLock(timeout, unit) ) { ... } + * </pre> + * + * <p>If the lock is held exclusively by another thread then the + * current thread becomes disabled for thread scheduling + * purposes and lies dormant until one of three things happens: + * + * <ul> + * + * <li>The lock is acquired by the current thread; or + * + * <li>Some other thread {@link Thread#interrupt interrupts} the current + * thread; or + * + * <li>The specified waiting time elapses + * + * </ul> + * + * <p>If the lock is acquired then the value <tt>true</tt> is + * returned. + * + * <p>If the current thread: + * + * <ul> + * + * <li>has its interrupted status set on entry to this method; or + * + * <li>is {@link Thread#interrupt interrupted} while acquiring + * the lock, + * + * </ul> then {@link InterruptedException} is thrown and the + * current thread's interrupted status is cleared. + * + * <p>If the specified waiting time elapses then the value + * <tt>false</tt> is returned. If the time is less than or + * equal to zero, the method will not wait at all. + * + * <p>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 <tt>true</tt> if the lock was acquired. + * + * @throws InterruptedException if the current thread is interrupted + * @throws NullPointerException if unit is null + * + */ + public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException { + return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout)); + } + + /** + * Attempts to release this lock. + * + * <p> If the number of readers is now zero then the lock + * is made available for other lock attempts. + */ + public void unlock() { + sync.releaseShared(1); + } + + /** + * Throws UnsupportedOperationException because ReadLocks + * do not support conditions. + * @return A new {@link Condition} instance for this <tt>Lock</tt> + * instance. + * @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 + * "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 lock null + */ + protected WriteLock(ReentrantReadWriteLock lock) { + sync = lock.sync; + } + + /** + * Acquire the lock. + * + * <p>Acquires the lock if it is not held by another thread + * and returns immediately, setting the lock hold count to + * one. + * + * <p>If the current thread already holds the lock then the + * hold count is incremented by one and the method returns + * immediately. + * + * <p>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.wlock(); + } + + /** + * Acquires the lock unless the current thread is {@link + * Thread#interrupt interrupted}. + * + * <p>Acquires the lock if it is not held by another thread + * and returns immediately, setting the lock hold count to + * one. + * + * <p>If the current thread already holds this lock then the + * hold count is incremented by one and the method returns + * immediately. + * + * <p>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: + * + * <ul> + * + * <li>The lock is acquired by the current thread; or + * + * <li>Some other thread {@link Thread#interrupt interrupts} + * the current thread. + * + * </ul> + * + * <p>If the lock is acquired by the current thread then the + * lock hold count is set to one. + * + * <p>If the current thread: + * + * <ul> + * + * <li>has its interrupted status set on entry to this method; + * or + * + * <li>is {@link Thread#interrupt interrupted} while acquiring + * the lock, + * + * </ul> + * + * then {@link InterruptedException} is thrown and the current + * thread's interrupted status is cleared. + * + * <p>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. + * + * <p>Acquires the lock if it is not held by another thread + * and returns immediately with the value <tt>true</tt>, + * setting the lock hold count to one. Even when this lock has + * been set to use a fair ordering policy, a call to + * <tt>tryLock()</tt> <em>will</em> 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). + * + * <p> If the current thread already holds this lock then the + * hold count is incremented by one and the method returns + * <tt>true</tt>. + * + * <p>If the lock is held by another thread then this method + * will return immediately with the value <tt>false</tt>. + * + * @return <tt>true</tt> if the lock was free and was acquired by the + * current thread, or the lock was already held by the current thread; and + * <tt>false</tt> 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 {@link Thread#interrupt interrupted}. + * + * <p>Acquires the lock if it is not held by another thread + * and returns immediately with the value <tt>true</tt>, + * setting the lock hold count to one. If this lock has been + * set to use a fair ordering policy then an available lock + * <em>will not</em> 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 <tt>tryLock</tt> + * that does permit barging on a fair lock then combine the + * timed and un-timed forms together: + * + * <pre>if (lock.tryLock() || lock.tryLock(timeout, unit) ) { ... } + * </pre> + * + * <p>If the current thread already holds this lock then the + * hold count is incremented by one and the method returns + * <tt>true</tt>. + * + * <p>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: + * + * <ul> + * + * <li>The lock is acquired by the current thread; or + * + * <li>Some other thread {@link Thread#interrupt interrupts} + * the current thread; or + * + * <li>The specified waiting time elapses + * + * </ul> + * + * <p>If the lock is acquired then the value <tt>true</tt> is + * returned and the lock hold count is set to one. + * + * <p>If the current thread: + * + * <ul> + * + * <li>has its interrupted status set on entry to this method; + * or + * + * <li>is {@link Thread#interrupt interrupted} while acquiring + * the lock, + * + * </ul> + * + * then {@link InterruptedException} is thrown and the current + * thread's interrupted status is cleared. + * + * <p>If the specified waiting time elapses then the value + * <tt>false</tt> is returned. If the time is less than or + * equal to zero, the method will not wait at all. + * + * <p>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 <tt>true</tt> if the lock was free and was acquired + * by the current thread, or the lock was already held by the + * current thread; and <tt>false</tt> if the waiting time + * elapsed before the lock could be acquired. + * + * @throws InterruptedException if the current thread is interrupted + * @throws NullPointerException if unit is null + * + */ + public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException { + return sync.tryAcquireNanos(1, unit.toNanos(timeout)); + } + + /** + * Attempts to release this lock. + * + * <p>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. + * <p>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. + * + * <ul> + * + * <li>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 access the write + * lock.) + * + * <li>When the condition {@link 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. + * + * <li>If a thread is {@link 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. + * + * <li> Waiting threads are signalled in FIFO order + * + * <li>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 <em>fair</em> locks favors those threads that have been + * waiting the longest. + * + * </ul> + * @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 + * "Unlocked" or the String "Locked by" + * followed by the {@link Thread#getName} of the owning thread. + * @return a string identifying this lock, as well as its lock state. + */ + public String toString() { + Thread owner = sync.getOwner(); + return super.toString() + ((owner == null) ? + "[Unlocked]" : + "[Locked by thread " + owner.getName() + "]"); + } + + } + + + // Instrumentation and status + + /** + * Returns true if this lock has fairness set true. + * @return true if this lock has fairness set true. + */ + public final boolean isFair() { + return sync instanceof FairSync; + } + + /** + * Returns the thread that currently owns the exclusive lock, or + * <tt>null</tt> if not owned. Note that the owner may be + * momentarily <tt>null</tt> 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 <tt>null</tt> 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 <tt>true</tt> if any thread holds write lock and + * <tt>false</tt> otherwise. + */ + public boolean isWriteLocked() { + return sync.isWriteLocked(); + } + + /** + * Queries if the write lock is held by the current thread. + * @return <tt>true</tt> if current thread holds this lock and + * <tt>false</tt> 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 this lock by the current thread, + * or zero if this lock is not held by the current thread. + */ + public int getWriteHoldCount() { + return sync.getWriteHoldCount(); + } + + /** + * 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<Thread> 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<Thread> getQueuedReaderThreads() { + return sync.getSharedQueuedThreads(); + } + + /** + * Queries whether any threads are waiting to acquire. Note that + * because cancellations may occur at any time, a <tt>true</tt> + * 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 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 + * <tt>true</tt> return does not guarantee that this thread + * will ever acquire. This method is designed primarily for use + * in monitoring of the system state. + * + * @param thread the thread + * @return true if the given thread is queued waiting for this lock. + * @throws NullPointerException if thread is null + */ + public final boolean hasQueuedThread(Thread thread) { + return sync.isQueued(thread); + } + + /** + * 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<Thread> 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 <tt>true</tt> return does + * not guarantee that a future <tt>signal</tt> will awaken any + * threads. This method is designed primarily for use in + * monitoring of the system state. + * @param condition the condition + * @return <tt>true</tt> 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 condition 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 condition 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 condition null + */ + protected Collection<Thread> 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 "Write locks =" + * follwed by the number of reentrantly held write locks, and the + * String "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 = exclusiveCount(c); + int r = sharedCount(c); + + return super.toString() + + "[Write locks = " + w + ", Read locks = " + r + "]"; + } + +} diff --git a/concurrent/src/main/java/java/util/concurrent/locks/UnsafeAccess.java b/concurrent/src/main/java/java/util/concurrent/locks/UnsafeAccess.java new file mode 100644 index 0000000..07f64e4 --- /dev/null +++ b/concurrent/src/main/java/java/util/concurrent/locks/UnsafeAccess.java @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.util.concurrent.locks; + +import sun.misc.Unsafe; + +/** + * Easy access to {@link Unsafe} for the rest of this package. + */ +/*package*/ final class UnsafeAccess { + /** non-null; unique instance of {@link Unsafe} */ + /*package*/ static final Unsafe THE_ONE = Unsafe.getUnsafe(); + + /** + * This class is uninstantiable. + */ + private UnsafeAccess() { + // This space intentionally left blank. + } +} diff --git a/concurrent/src/main/java/java/util/concurrent/locks/package.html b/concurrent/src/main/java/java/util/concurrent/locks/package.html new file mode 100644 index 0000000..5d3b3fc --- /dev/null +++ b/concurrent/src/main/java/java/util/concurrent/locks/package.html @@ -0,0 +1,45 @@ +<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN"> +<html> <head> +<title>Locks</title> +</head> + +<body> + +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. + +<p> 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}. + +<p> 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. + +<p> 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 +<tt>Object.wait</tt>, but offer extended capabilities. In particular, +multiple <tt>Condition</tt> objects may be associated with a single +<tt>Lock</tt>. To avoid compatibility issues, the names of +<tt>Condition</tt> methods are different than the corresponding +<tt>Object</tt> versions. + +<p> 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.LockSupport} class provides lower-level +blocking and unblocking support that is useful for those developers +implementing their own customized lock classes. + +@since 1.5 +@since Android 1.0 + +</body> </html> diff --git a/concurrent/src/main/java/java/util/concurrent/package.html b/concurrent/src/main/java/java/util/concurrent/package.html new file mode 100644 index 0000000..f7a4ad3 --- /dev/null +++ b/concurrent/src/main/java/java/util/concurrent/package.html @@ -0,0 +1,126 @@ +<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN"> +<html> <head> +<title>Concurrency Utilities</title> +</head> + +<body> + +<p> 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 <tt>locks</tt> and +<tt>atomic</tt> packages. + +<h2>Executors</h2> + +<b>Interfaces.</b> {@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 <tt>execute()</tt>, 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 +adds 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. + +<p> + +<b>Implementations.</b> 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 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. + +<h2>Queues</h2> + +The java.util.concurrent {@link +java.util.concurrent.ConcurrentLinkedQueue} class supplies an +efficient scalable thread-safe non-blocking FIFO queue. Five +implementations in 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. + + +<h2>Timing</h2> + +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. + +<h2>Synchronizers</h2> + +Four 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. An {@link java.util.concurrent.Exchanger} allows +two threads to exchange objects at a rendezvous point, and is useful +in several pipeline designs. + +<h2>Concurrent Collections</h2> + +Besides Queues, this package supplies a few Collection implementations +designed for use in multithreaded contexts: {@link +java.util.concurrent.ConcurrentHashMap}, {@link +java.util.concurrent.CopyOnWriteArrayList}, and {@link +java.util.concurrent.CopyOnWriteArraySet}. + +<p>The "Concurrent" prefix used with some classes in this package is a +shorthand indicating several differences from similar "synchronized" +classes. For example <tt>java.util.Hashtable</tt> and +<tt>Collections.synchronizedMap(new HashMap())</tt> 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. + +<p> Most concurrent Collection implementations (including most Queues) +also differ from the usual java.util conventions in that their Iterators +provide <em>weakly consistent</em> 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. + +@since 1.5 +@since Android 1.0 + +</body> </html> |