summaryrefslogtreecommitdiffstats
path: root/concurrent/src/main/java
diff options
context:
space:
mode:
authorJesse Wilson <jessewilson@google.com>2010-04-07 15:07:54 -0700
committerJesse Wilson <jessewilson@google.com>2010-04-09 12:15:23 -0700
commit6232a5efed0ea103e35aec73206e5e03a8b82e0c (patch)
tree1063168102abba77194c174b27f997f8508b104f /concurrent/src/main/java
parent5ce230557f6d172654868465c6ef9f99564701a8 (diff)
downloadlibcore-6232a5efed0ea103e35aec73206e5e03a8b82e0c.zip
libcore-6232a5efed0ea103e35aec73206e5e03a8b82e0c.tar.gz
libcore-6232a5efed0ea103e35aec73206e5e03a8b82e0c.tar.bz2
Latest java.util.concurrent from the JSR 166 project.
Code was downloaded from CVS on 2010-april-7 at 10:00pst http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/src/main/java/util/concurrent/ The new interfaces and ArrayDeque class are all from Harmony.
Diffstat (limited to 'concurrent/src/main/java')
-rw-r--r--concurrent/src/main/java/java/util/concurrent/AbstractExecutorService.java82
-rw-r--r--concurrent/src/main/java/java/util/concurrent/ArrayBlockingQueue.java4
-rw-r--r--concurrent/src/main/java/java/util/concurrent/BlockingDeque.java613
-rw-r--r--concurrent/src/main/java/java/util/concurrent/BlockingQueue.java4
-rw-r--r--concurrent/src/main/java/java/util/concurrent/ConcurrentHashMap.java75
-rw-r--r--concurrent/src/main/java/java/util/concurrent/ConcurrentLinkedDeque.java1246
-rw-r--r--concurrent/src/main/java/java/util/concurrent/ConcurrentLinkedQueue.java151
-rw-r--r--concurrent/src/main/java/java/util/concurrent/ConcurrentNavigableMap.java148
-rw-r--r--concurrent/src/main/java/java/util/concurrent/ConcurrentSkipListMap.java3115
-rw-r--r--concurrent/src/main/java/java/util/concurrent/ConcurrentSkipListSet.java456
-rw-r--r--concurrent/src/main/java/java/util/concurrent/CopyOnWriteArrayList.java31
-rw-r--r--concurrent/src/main/java/java/util/concurrent/Delayed.java9
-rw-r--r--concurrent/src/main/java/java/util/concurrent/Exchanger.java4
-rw-r--r--concurrent/src/main/java/java/util/concurrent/ExecutorCompletionService.java20
-rw-r--r--concurrent/src/main/java/java/util/concurrent/ExecutorService.java16
-rw-r--r--concurrent/src/main/java/java/util/concurrent/Executors.java17
-rw-r--r--concurrent/src/main/java/java/util/concurrent/FutureTask.java2
-rw-r--r--concurrent/src/main/java/java/util/concurrent/Java6Arrays.java77
-rw-r--r--concurrent/src/main/java/java/util/concurrent/LinkedBlockingDeque.java1137
-rw-r--r--concurrent/src/main/java/java/util/concurrent/LinkedBlockingQueue.java406
-rw-r--r--concurrent/src/main/java/java/util/concurrent/PriorityBlockingQueue.java1
-rw-r--r--concurrent/src/main/java/java/util/concurrent/RunnableFuture.java25
-rw-r--r--concurrent/src/main/java/java/util/concurrent/RunnableScheduledFuture.java29
-rw-r--r--concurrent/src/main/java/java/util/concurrent/ScheduledThreadPoolExecutor.java284
-rw-r--r--concurrent/src/main/java/java/util/concurrent/Semaphore.java4
-rw-r--r--concurrent/src/main/java/java/util/concurrent/SynchronousQueue.java23
-rw-r--r--concurrent/src/main/java/java/util/concurrent/ThreadPoolExecutor.java85
-rw-r--r--concurrent/src/main/java/java/util/concurrent/TimeUnit.java46
-rw-r--r--concurrent/src/main/java/java/util/concurrent/atomic/AtomicBoolean.java16
-rw-r--r--concurrent/src/main/java/java/util/concurrent/atomic/AtomicInteger.java14
-rw-r--r--concurrent/src/main/java/java/util/concurrent/atomic/AtomicIntegerArray.java121
-rw-r--r--concurrent/src/main/java/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java32
-rw-r--r--concurrent/src/main/java/java/util/concurrent/atomic/AtomicLong.java14
-rw-r--r--concurrent/src/main/java/java/util/concurrent/atomic/AtomicLongArray.java130
-rw-r--r--concurrent/src/main/java/java/util/concurrent/atomic/AtomicLongFieldUpdater.java49
-rw-r--r--concurrent/src/main/java/java/util/concurrent/atomic/AtomicReference.java14
-rw-r--r--concurrent/src/main/java/java/util/concurrent/atomic/AtomicReferenceArray.java85
-rw-r--r--concurrent/src/main/java/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java37
-rw-r--r--concurrent/src/main/java/java/util/concurrent/atomic/package-info.java8
-rw-r--r--concurrent/src/main/java/java/util/concurrent/locks/AbstractOwnableSynchronizer.java7
-rw-r--r--concurrent/src/main/java/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java2073
-rw-r--r--concurrent/src/main/java/java/util/concurrent/locks/AbstractQueuedSynchronizer.java43
-rw-r--r--concurrent/src/main/java/java/util/concurrent/locks/Condition.java18
-rw-r--r--concurrent/src/main/java/java/util/concurrent/locks/LockSupport.java159
-rw-r--r--concurrent/src/main/java/java/util/concurrent/locks/ReentrantReadWriteLock.java39
-rw-r--r--concurrent/src/main/java/java/util/concurrent/locks/package-info.java14
-rw-r--r--concurrent/src/main/java/java/util/concurrent/package-info.java67
47 files changed, 10236 insertions, 814 deletions
diff --git a/concurrent/src/main/java/java/util/concurrent/AbstractExecutorService.java b/concurrent/src/main/java/java/util/concurrent/AbstractExecutorService.java
index f7ed15c..a7c8fe5 100644
--- a/concurrent/src/main/java/java/util/concurrent/AbstractExecutorService.java
+++ b/concurrent/src/main/java/java/util/concurrent/AbstractExecutorService.java
@@ -10,26 +10,74 @@ import java.util.*;
/**
* Provides default implementations 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,
+ * <tt>invokeAny</tt> and <tt>invokeAll</tt> methods using a
+ * {@link RunnableFuture} returned by <tt>newTaskFor</tt>, which defaults
+ * to the {@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.
+ * associated <tt>RunnableFuture</tt> that is executed and
+ * returned. Subclasses may override the <tt>newTaskFor</tt> methods
+ * to return <tt>RunnableFuture</tt> implementations other than
+ * <tt>FutureTask</tt>.
*
+ * <p> <b>Extension example</b>. Here is a sketch of a class
+ * that customizes {@link ThreadPoolExecutor} to use
+ * a <tt>CustomTask</tt> class instead of the default <tt>FutureTask</tt>:
+ * <pre>
+ * public class CustomThreadPoolExecutor extends ThreadPoolExecutor {
+ *
+ * static class CustomTask&lt;V&gt; implements RunnableFuture&lt;V&gt; {...}
+ *
+ * protected &lt;V&gt; RunnableFuture&lt;V&gt; newTaskFor(Callable&lt;V&gt; c) {
+ * return new CustomTask&lt;V&gt;(c);
+ * }
+ * protected &lt;V&gt; RunnableFuture&lt;V&gt; newTaskFor(Runnable r, V v) {
+ * return new CustomTask&lt;V&gt;(r, v);
+ * }
+ * // ... add constructors, etc.
+ * }
+ * </pre>
* @since 1.5
* @author Doug Lea
*/
public abstract class AbstractExecutorService implements ExecutorService {
/**
+ * Returns a <tt>RunnableFuture</tt> for the given runnable and default
+ * value.
+ *
+ * @param runnable the runnable task being wrapped
+ * @param value the default value for the returned future
+ * @return a <tt>RunnableFuture</tt> which when run will run the
+ * underlying runnable and which, as a <tt>Future</tt>, will yield
+ * the given value as its result and provide for cancellation of
+ * the underlying task.
+ * @since 1.6
+ */
+ protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
+ return new FutureTask<T>(runnable, value);
+ }
+
+ /**
+ * Returns a <tt>RunnableFuture</tt> for the given callable task.
+ *
+ * @param callable the callable task being wrapped
+ * @return a <tt>RunnableFuture</tt> which when run will call the
+ * underlying callable and which, as a <tt>Future</tt>, will yield
+ * the callable's result as its result and provide for
+ * cancellation of the underlying task.
+ * @since 1.6
+ */
+ protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
+ return new FutureTask<T>(callable);
+ }
+
+ /**
* @throws RejectedExecutionException {@inheritDoc}
* @throws NullPointerException {@inheritDoc}
*/
public Future<?> submit(Runnable task) {
if (task == null) throw new NullPointerException();
- FutureTask<Object> ftask = new FutureTask<Object>(task, null);
+ RunnableFuture<Object> ftask = newTaskFor(task, null);
execute(ftask);
return ftask;
}
@@ -40,7 +88,7 @@ public abstract class AbstractExecutorService implements ExecutorService {
*/
public <T> Future<T> submit(Runnable task, T result) {
if (task == null) throw new NullPointerException();
- FutureTask<T> ftask = new FutureTask<T>(task, result);
+ RunnableFuture<T> ftask = newTaskFor(task, result);
execute(ftask);
return ftask;
}
@@ -51,7 +99,7 @@ public abstract class AbstractExecutorService implements ExecutorService {
*/
public <T> Future<T> submit(Callable<T> task) {
if (task == null) throw new NullPointerException();
- FutureTask<T> ftask = new FutureTask<T>(task);
+ RunnableFuture<T> ftask = newTaskFor(task);
execute(ftask);
return ftask;
}
@@ -59,7 +107,7 @@ public abstract class AbstractExecutorService implements ExecutorService {
/**
* the main mechanics of invokeAny.
*/
- private <T> T doInvokeAny(Collection<Callable<T>> tasks,
+ private <T> T doInvokeAny(Collection<? extends Callable<T>> tasks,
boolean timed, long nanos)
throws InterruptedException, ExecutionException, TimeoutException {
if (tasks == null)
@@ -82,7 +130,7 @@ public abstract class AbstractExecutorService implements ExecutorService {
// result, we can throw the last exception we got.
ExecutionException ee = null;
long lastTime = (timed)? System.nanoTime() : 0;
- Iterator<Callable<T>> it = tasks.iterator();
+ Iterator<? extends Callable<T>> it = tasks.iterator();
// Start one task for sure; the rest incrementally
futures.add(ecs.submit(it.next()));
@@ -134,7 +182,7 @@ public abstract class AbstractExecutorService implements ExecutorService {
}
}
- public <T> T invokeAny(Collection<Callable<T>> tasks)
+ public <T> T invokeAny(Collection<? extends Callable<T>> tasks)
throws InterruptedException, ExecutionException {
try {
return doInvokeAny(tasks, false, 0);
@@ -144,13 +192,13 @@ public abstract class AbstractExecutorService implements ExecutorService {
}
}
- public <T> T invokeAny(Collection<Callable<T>> tasks,
+ public <T> T invokeAny(Collection<? extends 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)
+ public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
throws InterruptedException {
if (tasks == null)
throw new NullPointerException();
@@ -158,7 +206,7 @@ public abstract class AbstractExecutorService implements ExecutorService {
boolean done = false;
try {
for (Callable<T> t : tasks) {
- FutureTask<T> f = new FutureTask<T>(t);
+ RunnableFuture<T> f = newTaskFor(t);
futures.add(f);
execute(f);
}
@@ -180,7 +228,7 @@ public abstract class AbstractExecutorService implements ExecutorService {
}
}
- public <T> List<Future<T>> invokeAll(Collection<Callable<T>> tasks,
+ public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
long timeout, TimeUnit unit)
throws InterruptedException {
if (tasks == null || unit == null)
@@ -190,7 +238,7 @@ public abstract class AbstractExecutorService implements ExecutorService {
boolean done = false;
try {
for (Callable<T> t : tasks)
- futures.add(new FutureTask<T>(t));
+ futures.add(newTaskFor(t));
long lastTime = System.nanoTime();
diff --git a/concurrent/src/main/java/java/util/concurrent/ArrayBlockingQueue.java b/concurrent/src/main/java/java/util/concurrent/ArrayBlockingQueue.java
index 0082f07..1c6f613 100644
--- a/concurrent/src/main/java/java/util/concurrent/ArrayBlockingQueue.java
+++ b/concurrent/src/main/java/java/util/concurrent/ArrayBlockingQueue.java
@@ -189,8 +189,8 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
if (capacity < c.size())
throw new IllegalArgumentException();
- for (Iterator<? extends E> it = c.iterator(); it.hasNext();)
- add(it.next());
+ for (E e : c)
+ add(e);
}
/**
diff --git a/concurrent/src/main/java/java/util/concurrent/BlockingDeque.java b/concurrent/src/main/java/java/util/concurrent/BlockingDeque.java
new file mode 100644
index 0000000..d77a965
--- /dev/null
+++ b/concurrent/src/main/java/java/util/concurrent/BlockingDeque.java
@@ -0,0 +1,613 @@
+/*
+ * 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 {@link Deque} that additionally supports blocking operations that wait
+ * for the deque to become non-empty when retrieving an element, and wait for
+ * space to become available in the deque when storing an element.
+ *
+ * <p><tt>BlockingDeque</tt> methods come in four forms, with different ways
+ * of handling operations that cannot be satisfied immediately, but may be
+ * satisfied at some point in the future:
+ * one throws an exception, the second returns a special value (either
+ * <tt>null</tt> or <tt>false</tt>, depending on the operation), the third
+ * blocks the current thread indefinitely until the operation can succeed,
+ * and the fourth blocks for only a given maximum time limit before giving
+ * up. These methods are summarized in the following table:
+ *
+ * <p>
+ * <table BORDER CELLPADDING=3 CELLSPACING=1>
+ * <tr>
+ * <td ALIGN=CENTER COLSPAN = 5> <b>First Element (Head)</b></td>
+ * </tr>
+ * <tr>
+ * <td></td>
+ * <td ALIGN=CENTER><em>Throws exception</em></td>
+ * <td ALIGN=CENTER><em>Special value</em></td>
+ * <td ALIGN=CENTER><em>Blocks</em></td>
+ * <td ALIGN=CENTER><em>Times out</em></td>
+ * </tr>
+ * <tr>
+ * <td><b>Insert</b></td>
+ * <td>{@link #addFirst addFirst(e)}</td>
+ * <td>{@link #offerFirst(Object) offerFirst(e)}</td>
+ * <td>{@link #putFirst putFirst(e)}</td>
+ * <td>{@link #offerFirst(Object, long, TimeUnit) offerFirst(e, time, unit)}</td>
+ * </tr>
+ * <tr>
+ * <td><b>Remove</b></td>
+ * <td>{@link #removeFirst removeFirst()}</td>
+ * <td>{@link #pollFirst pollFirst()}</td>
+ * <td>{@link #takeFirst takeFirst()}</td>
+ * <td>{@link #pollFirst(long, TimeUnit) pollFirst(time, unit)}</td>
+ * </tr>
+ * <tr>
+ * <td><b>Examine</b></td>
+ * <td>{@link #getFirst getFirst()}</td>
+ * <td>{@link #peekFirst peekFirst()}</td>
+ * <td><em>not applicable</em></td>
+ * <td><em>not applicable</em></td>
+ * </tr>
+ * <tr>
+ * <td ALIGN=CENTER COLSPAN = 5> <b>Last Element (Tail)</b></td>
+ * </tr>
+ * <tr>
+ * <td></td>
+ * <td ALIGN=CENTER><em>Throws exception</em></td>
+ * <td ALIGN=CENTER><em>Special value</em></td>
+ * <td ALIGN=CENTER><em>Blocks</em></td>
+ * <td ALIGN=CENTER><em>Times out</em></td>
+ * </tr>
+ * <tr>
+ * <td><b>Insert</b></td>
+ * <td>{@link #addLast addLast(e)}</td>
+ * <td>{@link #offerLast(Object) offerLast(e)}</td>
+ * <td>{@link #putLast putLast(e)}</td>
+ * <td>{@link #offerLast(Object, long, TimeUnit) offerLast(e, time, unit)}</td>
+ * </tr>
+ * <tr>
+ * <td><b>Remove</b></td>
+ * <td>{@link #removeLast() removeLast()}</td>
+ * <td>{@link #pollLast() pollLast()}</td>
+ * <td>{@link #takeLast takeLast()}</td>
+ * <td>{@link #pollLast(long, TimeUnit) pollLast(time, unit)}</td>
+ * </tr>
+ * <tr>
+ * <td><b>Examine</b></td>
+ * <td>{@link #getLast getLast()}</td>
+ * <td>{@link #peekLast peekLast()}</td>
+ * <td><em>not applicable</em></td>
+ * <td><em>not applicable</em></td>
+ * </tr>
+ * </table>
+ *
+ * <p>Like any {@link BlockingQueue}, a <tt>BlockingDeque</tt> is thread safe,
+ * does not permit null elements, and may (or may not) be
+ * capacity-constrained.
+ *
+ * <p>A <tt>BlockingDeque</tt> implementation may be used directly as a FIFO
+ * <tt>BlockingQueue</tt>. The methods inherited from the
+ * <tt>BlockingQueue</tt> interface are precisely equivalent to
+ * <tt>BlockingDeque</tt> methods as indicated in the following table:
+ *
+ * <p>
+ * <table BORDER CELLPADDING=3 CELLSPACING=1>
+ * <tr>
+ * <td ALIGN=CENTER> <b><tt>BlockingQueue</tt> Method</b></td>
+ * <td ALIGN=CENTER> <b>Equivalent <tt>BlockingDeque</tt> Method</b></td>
+ * </tr>
+ * <tr>
+ * <td ALIGN=CENTER COLSPAN = 2> <b>Insert</b></td>
+ * </tr>
+ * <tr>
+ * <td>{@link #add(Object) add(e)}</td>
+ * <td>{@link #addLast(Object) addLast(e)}</td>
+ * </tr>
+ * <tr>
+ * <td>{@link #offer(Object) offer(e)}</td>
+ * <td>{@link #offerLast(Object) offerLast(e)}</td>
+ * </tr>
+ * <tr>
+ * <td>{@link #put(Object) put(e)}</td>
+ * <td>{@link #putLast(Object) putLast(e)}</td>
+ * </tr>
+ * <tr>
+ * <td>{@link #offer(Object, long, TimeUnit) offer(e, time, unit)}</td>
+ * <td>{@link #offerLast(Object, long, TimeUnit) offerLast(e, time, unit)}</td>
+ * </tr>
+ * <tr>
+ * <td ALIGN=CENTER COLSPAN = 2> <b>Remove</b></td>
+ * </tr>
+ * <tr>
+ * <td>{@link #remove() remove()}</td>
+ * <td>{@link #removeFirst() removeFirst()}</td>
+ * </tr>
+ * <tr>
+ * <td>{@link #poll() poll()}</td>
+ * <td>{@link #pollFirst() pollFirst()}</td>
+ * </tr>
+ * <tr>
+ * <td>{@link #take() take()}</td>
+ * <td>{@link #takeFirst() takeFirst()}</td>
+ * </tr>
+ * <tr>
+ * <td>{@link #poll(long, TimeUnit) poll(time, unit)}</td>
+ * <td>{@link #pollFirst(long, TimeUnit) pollFirst(time, unit)}</td>
+ * </tr>
+ * <tr>
+ * <td ALIGN=CENTER COLSPAN = 2> <b>Examine</b></td>
+ * </tr>
+ * <tr>
+ * <td>{@link #element() element()}</td>
+ * <td>{@link #getFirst() getFirst()}</td>
+ * </tr>
+ * <tr>
+ * <td>{@link #peek() peek()}</td>
+ * <td>{@link #peekFirst() peekFirst()}</td>
+ * </tr>
+ * </table>
+ *
+ * <p>Memory consistency effects: As with other concurrent
+ * collections, actions in a thread prior to placing an object into a
+ * {@code BlockingDeque}
+ * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a>
+ * actions subsequent to the access or removal of that element from
+ * the {@code BlockingDeque} in another thread.
+ *
+ * <p>This interface is a member of the
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
+ * Java Collections Framework</a>.
+ *
+ * @since 1.6
+ * @author Doug Lea
+ * @param <E> the type of elements held in this collection
+ */
+public interface BlockingDeque<E> extends BlockingQueue<E>, Deque<E> {
+ /*
+ * We have "diamond" multiple interface inheritance here, and that
+ * introduces ambiguities. Methods might end up with different
+ * specs depending on the branch chosen by javadoc. Thus a lot of
+ * methods specs here are copied from superinterfaces.
+ */
+
+ /**
+ * Inserts the specified element at the front of this deque if it is
+ * possible to do so immediately without violating capacity restrictions,
+ * throwing an <tt>IllegalStateException</tt> if no space is currently
+ * available. When using a capacity-restricted deque, it is generally
+ * preferable to use {@link #offerFirst(Object) offerFirst}.
+ *
+ * @param e the element to add
+ * @throws IllegalStateException {@inheritDoc}
+ * @throws ClassCastException {@inheritDoc}
+ * @throws NullPointerException if the specified element is null
+ * @throws IllegalArgumentException {@inheritDoc}
+ */
+ void addFirst(E e);
+
+ /**
+ * Inserts the specified element at the end of this deque if it is
+ * possible to do so immediately without violating capacity restrictions,
+ * throwing an <tt>IllegalStateException</tt> if no space is currently
+ * available. When using a capacity-restricted deque, it is generally
+ * preferable to use {@link #offerLast(Object) offerLast}.
+ *
+ * @param e the element to add
+ * @throws IllegalStateException {@inheritDoc}
+ * @throws ClassCastException {@inheritDoc}
+ * @throws NullPointerException if the specified element is null
+ * @throws IllegalArgumentException {@inheritDoc}
+ */
+ void addLast(E e);
+
+ /**
+ * Inserts the specified element at the front of this deque if it is
+ * possible to do so immediately without violating capacity restrictions,
+ * returning <tt>true</tt> upon success and <tt>false</tt> if no space is
+ * currently available.
+ * When using a capacity-restricted deque, this method is generally
+ * preferable to the {@link #addFirst(Object) addFirst} method, which can
+ * fail to insert an element only by throwing an exception.
+ *
+ * @param e the element to add
+ * @throws ClassCastException {@inheritDoc}
+ * @throws NullPointerException if the specified element is null
+ * @throws IllegalArgumentException {@inheritDoc}
+ */
+ boolean offerFirst(E e);
+
+ /**
+ * Inserts the specified element at the end of this deque if it is
+ * possible to do so immediately without violating capacity restrictions,
+ * returning <tt>true</tt> upon success and <tt>false</tt> if no space is
+ * currently available.
+ * When using a capacity-restricted deque, this method is generally
+ * preferable to the {@link #addLast(Object) addLast} method, which can
+ * fail to insert an element only by throwing an exception.
+ *
+ * @param e the element to add
+ * @throws ClassCastException {@inheritDoc}
+ * @throws NullPointerException if the specified element is null
+ * @throws IllegalArgumentException {@inheritDoc}
+ */
+ boolean offerLast(E e);
+
+ /**
+ * Inserts the specified element at the front of this deque,
+ * waiting if necessary for space to become available.
+ *
+ * @param e the element to add
+ * @throws InterruptedException if interrupted while waiting
+ * @throws ClassCastException if the class of the specified element
+ * prevents it from being added to this deque
+ * @throws NullPointerException if the specified element is null
+ * @throws IllegalArgumentException if some property of the specified
+ * element prevents it from being added to this deque
+ */
+ void putFirst(E e) throws InterruptedException;
+
+ /**
+ * Inserts the specified element at the end of this deque,
+ * waiting if necessary for space to become available.
+ *
+ * @param e the element to add
+ * @throws InterruptedException if interrupted while waiting
+ * @throws ClassCastException if the class of the specified element
+ * prevents it from being added to this deque
+ * @throws NullPointerException if the specified element is null
+ * @throws IllegalArgumentException if some property of the specified
+ * element prevents it from being added to this deque
+ */
+ void putLast(E e) throws InterruptedException;
+
+ /**
+ * Inserts the specified element at the front of this deque,
+ * waiting up to the specified wait time if necessary for space to
+ * become available.
+ *
+ * @param e the element to add
+ * @param timeout how long to wait before giving up, in units of
+ * <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 ClassCastException if the class of the specified element
+ * prevents it from being added to this deque
+ * @throws NullPointerException if the specified element is null
+ * @throws IllegalArgumentException if some property of the specified
+ * element prevents it from being added to this deque
+ */
+ boolean offerFirst(E e, long timeout, TimeUnit unit)
+ throws InterruptedException;
+
+ /**
+ * Inserts the specified element at the end of this deque,
+ * waiting up to the specified wait time if necessary for space to
+ * become available.
+ *
+ * @param e the element to add
+ * @param timeout how long to wait before giving up, in units of
+ * <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 ClassCastException if the class of the specified element
+ * prevents it from being added to this deque
+ * @throws NullPointerException if the specified element is null
+ * @throws IllegalArgumentException if some property of the specified
+ * element prevents it from being added to this deque
+ */
+ boolean offerLast(E e, long timeout, TimeUnit unit)
+ throws InterruptedException;
+
+ /**
+ * Retrieves and removes the first element of this deque, waiting
+ * if necessary until an element becomes available.
+ *
+ * @return the head of this deque
+ * @throws InterruptedException if interrupted while waiting
+ */
+ E takeFirst() throws InterruptedException;
+
+ /**
+ * Retrieves and removes the last element of this deque, waiting
+ * if necessary until an element becomes available.
+ *
+ * @return the tail of this deque
+ * @throws InterruptedException if interrupted while waiting
+ */
+ E takeLast() throws InterruptedException;
+
+ /**
+ * Retrieves and removes the first element of this deque, waiting
+ * up to the specified wait time if necessary for an element to
+ * become available.
+ *
+ * @param timeout how long to wait before giving up, in units of
+ * <tt>unit</tt>
+ * @param unit a <tt>TimeUnit</tt> determining how to interpret the
+ * <tt>timeout</tt> parameter
+ * @return the head of this deque, or <tt>null</tt> if the specified
+ * waiting time elapses before an element is available
+ * @throws InterruptedException if interrupted while waiting
+ */
+ E pollFirst(long timeout, TimeUnit unit)
+ throws InterruptedException;
+
+ /**
+ * Retrieves and removes the last element of this deque, waiting
+ * up to the specified wait time if necessary for an element to
+ * become available.
+ *
+ * @param timeout how long to wait before giving up, in units of
+ * <tt>unit</tt>
+ * @param unit a <tt>TimeUnit</tt> determining how to interpret the
+ * <tt>timeout</tt> parameter
+ * @return the tail of this deque, or <tt>null</tt> if the specified
+ * waiting time elapses before an element is available
+ * @throws InterruptedException if interrupted while waiting
+ */
+ E pollLast(long timeout, TimeUnit unit)
+ throws InterruptedException;
+
+ /**
+ * Removes the first occurrence of the specified element from this deque.
+ * If the deque does not contain the element, it is unchanged.
+ * More formally, removes the first element <tt>e</tt> such that
+ * <tt>o.equals(e)</tt> (if such an element exists).
+ * Returns <tt>true</tt> if this deque contained the specified element
+ * (or equivalently, if this deque changed as a result of the call).
+ *
+ * @param o element to be removed from this deque, if present
+ * @return <tt>true</tt> if an element was removed as a result of this call
+ * @throws ClassCastException if the class of the specified element
+ * is incompatible with this deque (optional)
+ * @throws NullPointerException if the specified element is null (optional)
+ */
+ boolean removeFirstOccurrence(Object o);
+
+ /**
+ * Removes the last occurrence of the specified element from this deque.
+ * If the deque does not contain the element, it is unchanged.
+ * More formally, removes the last element <tt>e</tt> such that
+ * <tt>o.equals(e)</tt> (if such an element exists).
+ * Returns <tt>true</tt> if this deque contained the specified element
+ * (or equivalently, if this deque changed as a result of the call).
+ *
+ * @param o element to be removed from this deque, if present
+ * @return <tt>true</tt> if an element was removed as a result of this call
+ * @throws ClassCastException if the class of the specified element
+ * is incompatible with this deque (optional)
+ * @throws NullPointerException if the specified element is null (optional)
+ */
+ boolean removeLastOccurrence(Object o);
+
+ // *** BlockingQueue methods ***
+
+ /**
+ * Inserts the specified element into the queue represented by this deque
+ * (in other words, at the tail of this deque) if it is possible to do so
+ * immediately without violating capacity restrictions, returning
+ * <tt>true</tt> upon success and throwing an
+ * <tt>IllegalStateException</tt> if no space is currently available.
+ * When using a capacity-restricted deque, it is generally preferable to
+ * use {@link #offer(Object) offer}.
+ *
+ * <p>This method is equivalent to {@link #addLast(Object) addLast}.
+ *
+ * @param e the element to add
+ * @throws IllegalStateException {@inheritDoc}
+ * @throws ClassCastException if the class of the specified element
+ * prevents it from being added to this deque
+ * @throws NullPointerException if the specified element is null
+ * @throws IllegalArgumentException if some property of the specified
+ * element prevents it from being added to this deque
+ */
+ boolean add(E e);
+
+ /**
+ * Inserts the specified element into the queue represented by this deque
+ * (in other words, at the tail of this deque) if it is possible to do so
+ * immediately without violating capacity restrictions, returning
+ * <tt>true</tt> upon success and <tt>false</tt> if no space is currently
+ * available. When using a capacity-restricted deque, this method is
+ * generally preferable to the {@link #add} method, which can fail to
+ * insert an element only by throwing an exception.
+ *
+ * <p>This method is equivalent to {@link #offerLast(Object) offerLast}.
+ *
+ * @param e the element to add
+ * @throws ClassCastException if the class of the specified element
+ * prevents it from being added to this deque
+ * @throws NullPointerException if the specified element is null
+ * @throws IllegalArgumentException if some property of the specified
+ * element prevents it from being added to this deque
+ */
+ boolean offer(E e);
+
+ /**
+ * Inserts the specified element into the queue represented by this deque
+ * (in other words, at the tail of this deque), waiting if necessary for
+ * space to become available.
+ *
+ * <p>This method is equivalent to {@link #putLast(Object) putLast}.
+ *
+ * @param e the element to add
+ * @throws InterruptedException {@inheritDoc}
+ * @throws ClassCastException if the class of the specified element
+ * prevents it from being added to this deque
+ * @throws NullPointerException if the specified element is null
+ * @throws IllegalArgumentException if some property of the specified
+ * element prevents it from being added to this deque
+ */
+ void put(E e) throws InterruptedException;
+
+ /**
+ * Inserts the specified element into the queue represented by this deque
+ * (in other words, at the tail of this deque), waiting up to the
+ * specified wait time if necessary for space to become available.
+ *
+ * <p>This method is equivalent to
+ * {@link #offerLast(Object,long,TimeUnit) offerLast}.
+ *
+ * @param e the element to add
+ * @return <tt>true</tt> if the element was added to this deque, else
+ * <tt>false</tt>
+ * @throws InterruptedException {@inheritDoc}
+ * @throws ClassCastException if the class of the specified element
+ * prevents it from being added to this deque
+ * @throws NullPointerException if the specified element is null
+ * @throws IllegalArgumentException if some property of the specified
+ * element prevents it from being added to this deque
+ */
+ boolean offer(E e, long timeout, TimeUnit unit)
+ throws InterruptedException;
+
+ /**
+ * Retrieves and removes the head of the queue represented by this deque
+ * (in other words, the first element of this deque).
+ * This method differs from {@link #poll poll} only in that it
+ * throws an exception if this deque is empty.
+ *
+ * <p>This method is equivalent to {@link #removeFirst() removeFirst}.
+ *
+ * @return the head of the queue represented by this deque
+ * @throws NoSuchElementException if this deque is empty
+ */
+ E remove();
+
+ /**
+ * Retrieves and removes the head of the queue represented by this deque
+ * (in other words, the first element of this deque), or returns
+ * <tt>null</tt> if this deque is empty.
+ *
+ * <p>This method is equivalent to {@link #pollFirst()}.
+ *
+ * @return the head of this deque, or <tt>null</tt> if this deque is empty
+ */
+ E poll();
+
+ /**
+ * Retrieves and removes the head of the queue represented by this deque
+ * (in other words, the first element of this deque), waiting if
+ * necessary until an element becomes available.
+ *
+ * <p>This method is equivalent to {@link #takeFirst() takeFirst}.
+ *
+ * @return the head of this deque
+ * @throws InterruptedException if interrupted while waiting
+ */
+ E take() throws InterruptedException;
+
+ /**
+ * Retrieves and removes the head of the queue represented by this deque
+ * (in other words, the first element of this deque), waiting up to the
+ * specified wait time if necessary for an element to become available.
+ *
+ * <p>This method is equivalent to
+ * {@link #pollFirst(long,TimeUnit) pollFirst}.
+ *
+ * @return the head of this deque, or <tt>null</tt> if the
+ * specified waiting time elapses before an element is available
+ * @throws InterruptedException if interrupted while waiting
+ */
+ E poll(long timeout, TimeUnit unit)
+ throws InterruptedException;
+
+ /**
+ * Retrieves, but does not remove, the head of the queue represented by
+ * this deque (in other words, the first element of this deque).
+ * This method differs from {@link #peek peek} only in that it throws an
+ * exception if this deque is empty.
+ *
+ * <p>This method is equivalent to {@link #getFirst() getFirst}.
+ *
+ * @return the head of this deque
+ * @throws NoSuchElementException if this deque is empty
+ */
+ E element();
+
+ /**
+ * Retrieves, but does not remove, the head of the queue represented by
+ * this deque (in other words, the first element of this deque), or
+ * returns <tt>null</tt> if this deque is empty.
+ *
+ * <p>This method is equivalent to {@link #peekFirst() peekFirst}.
+ *
+ * @return the head of this deque, or <tt>null</tt> if this deque is empty
+ */
+ E peek();
+
+ /**
+ * Removes the first occurrence of the specified element from this deque.
+ * If the deque does not contain the element, it is unchanged.
+ * More formally, removes the first element <tt>e</tt> such that
+ * <tt>o.equals(e)</tt> (if such an element exists).
+ * Returns <tt>true</tt> if this deque contained the specified element
+ * (or equivalently, if this deque changed as a result of the call).
+ *
+ * <p>This method is equivalent to
+ * {@link #removeFirstOccurrence(Object) removeFirstOccurrence}.
+ *
+ * @param o element to be removed from this deque, if present
+ * @return <tt>true</tt> if this deque changed as a result of the call
+ * @throws ClassCastException if the class of the specified element
+ * is incompatible with this deque (optional)
+ * @throws NullPointerException if the specified element is null (optional)
+ */
+ boolean remove(Object o);
+
+ /**
+ * Returns <tt>true</tt> if this deque contains the specified element.
+ * More formally, returns <tt>true</tt> if and only if this deque contains
+ * at least one element <tt>e</tt> such that <tt>o.equals(e)</tt>.
+ *
+ * @param o object to be checked for containment in this deque
+ * @return <tt>true</tt> if this deque contains the specified element
+ * @throws ClassCastException if the class of the specified element
+ * is incompatible with this deque (optional)
+ * @throws NullPointerException if the specified element is null (optional)
+ */
+ public boolean contains(Object o);
+
+ /**
+ * Returns the number of elements in this deque.
+ *
+ * @return the number of elements in this deque
+ */
+ public int size();
+
+ /**
+ * Returns an iterator over the elements in this deque in proper sequence.
+ * The elements will be returned in order from first (head) to last (tail).
+ *
+ * @return an iterator over the elements in this deque in proper sequence
+ */
+ Iterator<E> iterator();
+
+ // *** Stack methods ***
+
+ /**
+ * Pushes an element onto the stack represented by this deque. In other
+ * words, inserts the element at the front of this deque unless it would
+ * violate capacity restrictions.
+ *
+ * <p>This method is equivalent to {@link #addFirst(Object) addFirst}.
+ *
+ * @throws IllegalStateException {@inheritDoc}
+ * @throws ClassCastException {@inheritDoc}
+ * @throws NullPointerException if the specified element is null
+ * @throws IllegalArgumentException {@inheritDoc}
+ */
+ void push(E e);
+}
diff --git a/concurrent/src/main/java/java/util/concurrent/BlockingQueue.java b/concurrent/src/main/java/java/util/concurrent/BlockingQueue.java
index d01c097..85945b9 100644
--- a/concurrent/src/main/java/java/util/concurrent/BlockingQueue.java
+++ b/concurrent/src/main/java/java/util/concurrent/BlockingQueue.java
@@ -42,7 +42,7 @@ import java.util.Queue;
* <td>{@link #add add(e)}</td>
* <td>{@link #offer offer(e)}</td>
* <td>{@link #put put(e)}</td>
- * <td>{@link #offer offer(e, time, unit)}</td>
+ * <td>{@link #offer(Object, long, TimeUnit) offer(e, time, unit)}</td>
* </tr>
* <tr>
* <td><b>Remove</b></td>
@@ -156,7 +156,7 @@ public interface BlockingQueue<E> extends Queue<E> {
* <tt>true</tt> upon success and throwing an
* <tt>IllegalStateException</tt> if no space is currently available.
* When using a capacity-restricted queue, it is generally preferable to
- * use {@link #offer offer}.
+ * use {@link #offer(Object) offer}.
*
* @param e the element to add
* @return <tt>true</tt> (as specified by {@link Collection#add})
diff --git a/concurrent/src/main/java/java/util/concurrent/ConcurrentHashMap.java b/concurrent/src/main/java/java/util/concurrent/ConcurrentHashMap.java
index cb5fb3f..1c157b4 100644
--- a/concurrent/src/main/java/java/util/concurrent/ConcurrentHashMap.java
+++ b/concurrent/src/main/java/java/util/concurrent/ConcurrentHashMap.java
@@ -613,6 +613,24 @@ public class ConcurrentHashMap<K, V> extends AbstractMap<K, V>
}
/**
+ * Creates a new, empty map with the specified initial capacity
+ * and load factor and with the default concurrencyLevel (16).
+ *
+ * @param initialCapacity The implementation performs internal
+ * sizing to accommodate this many elements.
+ * @param loadFactor the load factor threshold, used to control resizing.
+ * Resizing may be performed when the average number of elements per
+ * bin exceeds this threshold.
+ * @throws IllegalArgumentException if the initial capacity of
+ * elements is negative or the load factor is nonpositive
+ *
+ * @since 1.6
+ */
+ public ConcurrentHashMap(int initialCapacity, float loadFactor) {
+ this(initialCapacity, loadFactor, DEFAULT_CONCURRENCY_LEVEL);
+ }
+
+ /**
* Creates a new, empty map with the specified initial capacity,
* and with default load factor (0.75) and concurrencyLevel (16).
*
@@ -1112,7 +1130,7 @@ public class ConcurrentHashMap<K, V> extends AbstractMap<K, V>
* setValue changes to the underlying map.
*/
final class WriteThroughEntry
- extends SimpleEntry<K,V>
+ extends AbstractMap.SimpleEntry<K,V>
{
WriteThroughEntry(K k, V v) {
super(k,v);
@@ -1212,60 +1230,7 @@ public class ConcurrentHashMap<K, V> extends AbstractMap<K, V>
}
}
- /**
- * This duplicates java.util.AbstractMap.SimpleEntry until this class
- * is made accessible.
- */
- static 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 -------------- */
+ /* ---------------- Serialization Support -------------- */
/**
* Save the state of the <tt>ConcurrentHashMap</tt> instance to a
diff --git a/concurrent/src/main/java/java/util/concurrent/ConcurrentLinkedDeque.java b/concurrent/src/main/java/java/util/concurrent/ConcurrentLinkedDeque.java
new file mode 100644
index 0000000..ee3534e
--- /dev/null
+++ b/concurrent/src/main/java/java/util/concurrent/ConcurrentLinkedDeque.java
@@ -0,0 +1,1246 @@
+/*
+ * Written by Doug Lea and Martin Buchholz with assistance from members of
+ * JCP JSR-166 Expert Group and released to the public domain, as explained
+ * at http://creativecommons.org/licenses/publicdomain
+ */
+
+package java.util.concurrent;
+
+import java.util.AbstractCollection;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Deque;
+import java.util.Iterator;
+import java.util.ConcurrentModificationException;
+import java.util.NoSuchElementException;
+import java.util.concurrent.atomic.AtomicReference;
+
+/**
+ * A concurrent linked-list implementation of a {@link Deque}
+ * (double-ended queue). Concurrent insertion, removal, and access
+ * operations execute safely across multiple threads. Iterators are
+ * <i>weakly consistent</i>, returning elements reflecting the state
+ * of the deque at some point at or since the creation of the
+ * iterator. They do <em>not</em> throw {@link
+ * ConcurrentModificationException}, and may proceed concurrently with
+ * other operations.
+ *
+ * <p>This class and its iterators implement all of the
+ * <em>optional</em> methods of the {@link Collection} and {@link
+ * Iterator} interfaces. Like most other concurrent collection
+ * implementations, this class does not permit the use of
+ * {@code null} elements. because some null arguments and return
+ * values cannot be reliably distinguished from the absence of
+ * elements. Arbitrarily, the {@link Collection#remove} method is
+ * mapped to {@code removeFirstOccurrence}, and {@link
+ * Collection#add} is mapped to {@code addLast}.
+ *
+ * <p>Beware that, unlike in most collections, the {@code size}
+ * method is <em>NOT</em> a constant-time operation. Because of the
+ * asynchronous nature of these deques, determining the current number
+ * of elements requires a traversal of the elements.
+ *
+ * <p>This class is {@code Serializable}, but relies on default
+ * serialization mechanisms. Usually, it is a better idea for any
+ * serializable class using a {@code ConcurrentLinkedDeque} to instead
+ * serialize a snapshot of the elements obtained by method
+ * {@code toArray}.
+ *
+ * @author Doug Lea
+ * @author Martin Buchholz
+ * @param <E> the type of elements held in this collection
+ */
+
+public class ConcurrentLinkedDeque<E>
+ extends AbstractCollection<E>
+ implements Deque<E>, java.io.Serializable {
+
+ /*
+ * This is an implementation of a concurrent lock-free deque
+ * supporting interior removes but not interior insertions, as
+ * required to fully support the Deque interface.
+ *
+ * We extend the techniques developed for
+ * ConcurrentLinkedQueue and LinkedTransferQueue
+ * (see the internal docs for those classes).
+ *
+ * At any time, there is precisely one "first" active node with a
+ * null prev pointer. Similarly there is one "last" active node
+ * with a null next pointer. New nodes are simply enqueued by
+ * null-CASing.
+ *
+ * A node p is considered "active" if it either contains an
+ * element, or is an end node and neither next nor prev pointers
+ * are self-links:
+ *
+ * p.item != null ||
+ * (p.prev == null && p.next != p) ||
+ * (p.next == null && p.prev != p)
+ *
+ * The head and tail pointers are only approximations to the start
+ * and end of the deque. The first node can always be found by
+ * following prev pointers from head; likewise for tail. However,
+ * head and tail may be pointing at deleted nodes that have been
+ * unlinked and so may not be reachable from any live node.
+ *
+ * There are 3 levels of node deletion:
+ * - logical deletion atomically removes the element
+ * - "unlinking" makes a deleted node unreachable from active
+ * nodes, and thus eventually reclaimable by GC
+ * - "gc-unlinking" further does the reverse of making active
+ * nodes unreachable from deleted nodes, making it easier for
+ * the GC to reclaim future deleted nodes
+ *
+ * TODO: find a better name for "gc-unlinked"
+ *
+ * Logical deletion of a node simply involves CASing its element
+ * to null. Physical deletion is merely an optimization (albeit a
+ * critical one), and can be performed at our convenience. At any
+ * time, the set of non-logically-deleted nodes maintained by prev
+ * and next links are identical, that is the live elements found
+ * via next links from the first node is equal to the elements
+ * found via prev links from the last node. However, this is not
+ * true for nodes that have already been logically deleted - such
+ * nodes may only be reachable in one direction.
+ *
+ * When a node is dequeued at either end, e.g. via poll(), we
+ * would like to break any references from the node to live nodes,
+ * to stop old garbage from causing retention of new garbage with
+ * a generational or conservative GC. We develop further the
+ * self-linking trick that was very effective in other concurrent
+ * collection classes. The idea is to replace prev and next
+ * pointers to active nodes with special values that are
+ * interpreted to mean off-the-list-at-one-end. These are
+ * approximations, but good enough to preserve the properties we
+ * want in our traversals, e.g. we guarantee that a traversal will
+ * never hit the same element twice, but we don't guarantee
+ * whether a traversal that runs out of elements will be able to
+ * see more elements later after more elements are added at that
+ * end. Doing gc-unlinking safely is particularly tricky, since
+ * any node can be in use indefinitely (for example by an
+ * iterator). We must make sure that the nodes pointed at by
+ * head/tail do not get gc-unlinked, since head/tail are needed to
+ * get "back on track" by other nodes that are gc-unlinked.
+ * gc-unlinking accounts for much of the implementation complexity.
+ *
+ * Since neither unlinking nor gc-unlinking are necessary for
+ * correctness, there are many implementation choices regarding
+ * frequency (eagerness) of these operations. Since volatile
+ * reads are likely to be much cheaper than CASes, saving CASes by
+ * unlinking multiple adjacent nodes at a time may be a win.
+ * gc-unlinking can be performed rarely and still be effective,
+ * since it is most important that long chains of deleted nodes
+ * are occasionally broken.
+ *
+ * The actual representation we use is that p.next == p means to
+ * goto the first node, and p.next == null && p.prev == p means
+ * that the iteration is at an end and that p is a (final static)
+ * dummy node, NEXT_TERMINATOR, and not the last active node.
+ * Finishing the iteration when encountering such a TERMINATOR is
+ * good enough for read-only traversals. When the last active
+ * node is desired, for example when enqueueing, goto tail and
+ * continue traversal.
+ *
+ * The implementation is completely directionally symmetrical,
+ * except that most public methods that iterate through the list
+ * follow next pointers ("forward" direction).
+ *
+ * There is one desirable property we would like to have, but
+ * don't: it is possible, when an addFirst(A) is racing with
+ * pollFirst() removing B, for an iterating observer to see A B C
+ * and subsequently see A C, even though no interior removes are
+ * ever performed. I believe this wart can only be removed at
+ * significant runtime cost.
+ *
+ * Empirically, microbenchmarks suggest that this class adds about
+ * 40% overhead relative to ConcurrentLinkedQueue, which feels as
+ * good as we can hope for.
+ */
+
+ /**
+ * A node from which the first node on list (that is, the unique
+ * node with node.prev == null) can be reached in O(1) time.
+ * Invariants:
+ * - the first node is always O(1) reachable from head via prev links
+ * - all live nodes are reachable from the first node via succ()
+ * - head != null
+ * - (tmp = head).next != tmp || tmp != head
+ * Non-invariants:
+ * - head.item may or may not be null
+ * - head may not be reachable from the first or last node, or from tail
+ */
+ private transient volatile Node<E> head = new Node<E>(null);
+
+ private final static Node<Object> PREV_TERMINATOR, NEXT_TERMINATOR;
+
+ static {
+ PREV_TERMINATOR = new Node<Object>(null);
+ PREV_TERMINATOR.next = PREV_TERMINATOR;
+ NEXT_TERMINATOR = new Node<Object>(null);
+ NEXT_TERMINATOR.prev = NEXT_TERMINATOR;
+ }
+
+ @SuppressWarnings("unchecked")
+ Node<E> prevTerminator() {
+ return (Node<E>) PREV_TERMINATOR;
+ }
+
+ @SuppressWarnings("unchecked")
+ Node<E> nextTerminator() {
+ return (Node<E>) NEXT_TERMINATOR;
+ }
+
+ /**
+ * A node from which the last node on list (that is, the unique
+ * node with node.next == null) can be reached in O(1) time.
+ * Invariants:
+ * - the last node is always O(1) reachable from tail via next links
+ * - all live nodes are reachable from the last node via pred()
+ * - tail != null
+ * Non-invariants:
+ * - tail.item may or may not be null
+ * - tail may not be reachable from the first or last node, or from head
+ */
+ private transient volatile Node<E> tail = head;
+
+ static final class Node<E> {
+ volatile Node<E> prev;
+ volatile E item;
+ volatile Node<E> next;
+
+ Node(E item) {
+ // Piggyback on imminent casNext() or casPrev()
+ lazySetItem(item);
+ }
+
+ boolean casItem(E cmp, E val) {
+ return UNSAFE.compareAndSwapObject(this, itemOffset, cmp, val);
+ }
+
+ void lazySetItem(E val) {
+ UNSAFE.putOrderedObject(this, itemOffset, val);
+ }
+
+ void lazySetNext(Node<E> val) {
+ UNSAFE.putOrderedObject(this, nextOffset, val);
+ }
+
+ boolean casNext(Node<E> cmp, Node<E> val) {
+ return UNSAFE.compareAndSwapObject(this, nextOffset, cmp, val);
+ }
+
+ void lazySetPrev(Node<E> val) {
+ UNSAFE.putOrderedObject(this, prevOffset, val);
+ }
+
+ boolean casPrev(Node<E> cmp, Node<E> val) {
+ return UNSAFE.compareAndSwapObject(this, prevOffset, cmp, val);
+ }
+
+ // Unsafe mechanics
+
+ private static final sun.misc.Unsafe UNSAFE =
+ sun.misc.Unsafe.getUnsafe();
+ private static final long prevOffset =
+ objectFieldOffset(UNSAFE, "prev", Node.class);
+ private static final long itemOffset =
+ objectFieldOffset(UNSAFE, "item", Node.class);
+ private static final long nextOffset =
+ objectFieldOffset(UNSAFE, "next", Node.class);
+ }
+
+ /**
+ * Links e as first element.
+ */
+ private void linkFirst(E e) {
+ checkNotNull(e);
+ final Node<E> newNode = new Node<E>(e);
+
+ retry:
+ for (;;) {
+ for (Node<E> h = head, p = h;;) {
+ Node<E> q = p.prev;
+ if (q == null) {
+ if (p.next == p)
+ continue retry;
+ newNode.lazySetNext(p); // CAS piggyback
+ if (p.casPrev(null, newNode)) {
+ if (p != h) // hop two nodes at a time
+ casHead(h, newNode);
+ return;
+ } else {
+ p = p.prev; // lost CAS race to another thread
+ }
+ }
+ else if (p == q)
+ continue retry;
+ else
+ p = q;
+ }
+ }
+ }
+
+ /**
+ * Links e as last element.
+ */
+ private void linkLast(E e) {
+ checkNotNull(e);
+ final Node<E> newNode = new Node<E>(e);
+
+ retry:
+ for (;;) {
+ for (Node<E> t = tail, p = t;;) {
+ Node<E> q = p.next;
+ if (q == null) {
+ if (p.prev == p)
+ continue retry;
+ newNode.lazySetPrev(p); // CAS piggyback
+ if (p.casNext(null, newNode)) {
+ if (p != t) // hop two nodes at a time
+ casTail(t, newNode);
+ return;
+ } else {
+ p = p.next; // lost CAS race to another thread
+ }
+ }
+ else if (p == q)
+ continue retry;
+ else
+ p = q;
+ }
+ }
+ }
+
+ // TODO: Is there a better cheap way of performing some cleanup
+ // operation "occasionally"?
+ static class Count {
+ int count = 0;
+ }
+ private final static ThreadLocal<Count> tlc =
+ new ThreadLocal<Count>() {
+ protected Count initialValue() { return new Count(); }
+ };
+ private static boolean shouldGCUnlinkOccasionally() {
+ return (tlc.get().count++ & 0x3) == 0;
+ }
+
+ private final static int HOPS = 2;
+
+ /**
+ * Unlinks non-null node x.
+ */
+ void unlink(Node<E> x) {
+ assert x != null;
+ assert x.item == null;
+ assert x != PREV_TERMINATOR;
+ assert x != NEXT_TERMINATOR;
+
+ final Node<E> prev = x.prev;
+ final Node<E> next = x.next;
+ if (prev == null) {
+ unlinkFirst(x, next);
+ } else if (next == null) {
+ unlinkLast(x, prev);
+ } else {
+ // Unlink interior node.
+ //
+ // This is the common case, since a series of polls at the
+ // same end will be "interior" removes, except perhaps for
+ // the first one, since end nodes cannot be physically removed.
+ //
+ // At any time, all active nodes are mutually reachable by
+ // following a sequence of either next or prev pointers.
+ //
+ // Our strategy is to find the unique active predecessor
+ // and successor of x. Try to fix up their links so that
+ // they point to each other, leaving x unreachable from
+ // active nodes. If successful, and if x has no live
+ // predecessor/successor, we additionally try to leave
+ // active nodes unreachable from x, by rechecking that
+ // the status of predecessor and successor are unchanged
+ // and ensuring that x is not reachable from tail/head,
+ // before setting x's prev/next links to their logical
+ // approximate replacements, self/TERMINATOR.
+ Node<E> activePred, activeSucc;
+ boolean isFirst, isLast;
+ int hops = 1;
+
+ // Find active predecessor
+ for (Node<E> p = prev;; ++hops) {
+ if (p.item != null) {
+ activePred = p;
+ isFirst = false;
+ break;
+ }
+ Node<E> q = p.prev;
+ if (q == null) {
+ if (p == p.next)
+ return;
+ activePred = p;
+ isFirst = true;
+ break;
+ }
+ else if (p == q)
+ return;
+ else
+ p = q;
+ }
+
+ // Find active successor
+ for (Node<E> p = next;; ++hops) {
+ if (p.item != null) {
+ activeSucc = p;
+ isLast = false;
+ break;
+ }
+ Node<E> q = p.next;
+ if (q == null) {
+ if (p == p.prev)
+ return;
+ activeSucc = p;
+ isLast = true;
+ break;
+ }
+ else if (p == q)
+ return;
+ else
+ p = q;
+ }
+
+ // TODO: better HOP heuristics
+ if (hops < HOPS
+ // always squeeze out interior deleted nodes
+ && (isFirst | isLast))
+ return;
+
+ // Squeeze out deleted nodes between activePred and
+ // activeSucc, including x.
+ skipDeletedSuccessors(activePred);
+ skipDeletedPredecessors(activeSucc);
+
+ // Try to gc-unlink, if possible
+ if ((isFirst | isLast) &&
+ //shouldGCUnlinkOccasionally() &&
+
+ // Recheck expected state of predecessor and successor
+ (activePred.next == activeSucc) &&
+ (activeSucc.prev == activePred) &&
+ (isFirst ? activePred.prev == null : activePred.item != null) &&
+ (isLast ? activeSucc.next == null : activeSucc.item != null)) {
+
+ // Ensure x is not reachable from head or tail
+ updateHead();
+ updateTail();
+ x.lazySetPrev(isFirst ? prevTerminator() : x);
+ x.lazySetNext(isLast ? nextTerminator() : x);
+ }
+ }
+ }
+
+ /**
+ * Unlinks non-null first node.
+ */
+ private void unlinkFirst(Node<E> first, Node<E> next) {
+ assert first != null && next != null && first.item == null;
+ Node<E> o = null, p = next;
+ for (int hops = 0;; ++hops) {
+ Node<E> q;
+ if (p.item != null || (q = p.next) == null) {
+ if (hops >= HOPS) {
+ if (p == p.prev)
+ return;
+ if (first.casNext(next, p)) {
+ skipDeletedPredecessors(p);
+ if (//shouldGCUnlinkOccasionally() &&
+ first.prev == null &&
+ (p.next == null || p.item != null) &&
+ p.prev == first) {
+
+ updateHead();
+ updateTail();
+ o.lazySetNext(o);
+ o.lazySetPrev(prevTerminator());
+ }
+ }
+ }
+ return;
+ }
+ else if (p == q)
+ return;
+ else {
+ o = p;
+ p = q;
+ }
+ }
+ }
+
+ /**
+ * Unlinks non-null last node.
+ */
+ private void unlinkLast(Node<E> last, Node<E> prev) {
+ assert last != null && prev != null && last.item == null;
+ Node<E> o = null, p = prev;
+ for (int hops = 0;; ++hops) {
+ Node<E> q;
+ if (p.item != null || (q = p.prev) == null) {
+ if (hops >= HOPS) {
+ if (p == p.next)
+ return;
+ if (last.casPrev(prev, p)) {
+ skipDeletedSuccessors(p);
+ if (//shouldGCUnlinkOccasionally() &&
+ last.next == null &&
+ (p.prev == null || p.item != null) &&
+ p.next == last) {
+
+ updateHead();
+ updateTail();
+ o.lazySetPrev(o);
+ o.lazySetNext(nextTerminator());
+ }
+ }
+ }
+ return;
+ }
+ else if (p == q)
+ return;
+ else {
+ o = p;
+ p = q;
+ }
+ }
+ }
+
+ private final void updateHead() {
+ first();
+ }
+
+ private final void updateTail() {
+ last();
+ }
+
+ private void skipDeletedPredecessors(Node<E> x) {
+ whileActive:
+ do {
+ Node<E> prev = x.prev;
+ assert prev != null;
+ assert x != NEXT_TERMINATOR;
+ assert x != PREV_TERMINATOR;
+ Node<E> p = prev;
+ findActive:
+ for (;;) {
+ if (p.item != null)
+ break findActive;
+ Node<E> q = p.prev;
+ if (q == null) {
+ if (p.next == p)
+ continue whileActive;
+ break findActive;
+ }
+ else if (p == q)
+ continue whileActive;
+ else
+ p = q;
+ }
+
+ // found active CAS target
+ if (prev == p || x.casPrev(prev, p))
+ return;
+
+ } while (x.item != null || x.next == null);
+ }
+
+ private void skipDeletedSuccessors(Node<E> x) {
+ whileActive:
+ do {
+ Node<E> next = x.next;
+ assert next != null;
+ assert x != NEXT_TERMINATOR;
+ assert x != PREV_TERMINATOR;
+ Node<E> p = next;
+ findActive:
+ for (;;) {
+ if (p.item != null)
+ break findActive;
+ Node<E> q = p.next;
+ if (q == null) {
+ if (p.prev == p)
+ continue whileActive;
+ break findActive;
+ }
+ else if (p == q)
+ continue whileActive;
+ else
+ p = q;
+ }
+
+ // found active CAS target
+ if (next == p || x.casNext(next, p))
+ return;
+
+ } while (x.item != null || x.prev == null);
+ }
+
+ /**
+ * Returns the successor of p, or the first node if p.next has been
+ * linked to self, which will only be true if traversing with a
+ * stale pointer that is now off the list.
+ */
+ final Node<E> succ(Node<E> p) {
+ // TODO: should we skip deleted nodes here?
+ Node<E> q = p.next;
+ return (p == q) ? first() : q;
+ }
+
+ /**
+ * Returns the predecessor of p, or the last node if p.prev has been
+ * linked to self, which will only be true if traversing with a
+ * stale pointer that is now off the list.
+ */
+ final Node<E> pred(Node<E> p) {
+ Node<E> q = p.prev;
+ return (p == q) ? last() : q;
+ }
+
+ /**
+ * Returns the first node, the unique node which has a null prev link.
+ * The returned node may or may not be logically deleted.
+ * Guarantees that head is set to the returned node.
+ */
+ Node<E> first() {
+ retry:
+ for (;;) {
+ for (Node<E> h = head, p = h;;) {
+ Node<E> q = p.prev;
+ if (q == null) {
+ if (p == h
+ // It is possible that p is PREV_TERMINATOR,
+ // but if so, the CAS will fail.
+ || casHead(h, p))
+ return p;
+ else
+ continue retry;
+ } else if (p == q) {
+ continue retry;
+ } else {
+ p = q;
+ }
+ }
+ }
+ }
+
+ /**
+ * Returns the last node, the unique node which has a null next link.
+ * The returned node may or may not be logically deleted.
+ * Guarantees that tail is set to the returned node.
+ */
+ Node<E> last() {
+ retry:
+ for (;;) {
+ for (Node<E> t = tail, p = t;;) {
+ Node<E> q = p.next;
+ if (q == null) {
+ if (p == t
+ // It is possible that p is NEXT_TERMINATOR,
+ // but if so, the CAS will fail.
+ || casTail(t, p))
+ return p;
+ else
+ continue retry;
+ } else if (p == q) {
+ continue retry;
+ } else {
+ p = q;
+ }
+ }
+ }
+ }
+
+ // Minor convenience utilities
+
+ /**
+ * Throws NullPointerException if argument is null.
+ *
+ * @param v the element
+ */
+ private static void checkNotNull(Object v) {
+ if (v == null)
+ throw new NullPointerException();
+ }
+
+ /**
+ * Returns element unless it is null, in which case throws
+ * NoSuchElementException.
+ *
+ * @param v the element
+ * @return the element
+ */
+ private E screenNullResult(E v) {
+ if (v == null)
+ throw new NoSuchElementException();
+ return v;
+ }
+
+ /**
+ * Creates an array list and fills it with elements of this list.
+ * Used by toArray.
+ *
+ * @return the arrayList
+ */
+ private ArrayList<E> toArrayList() {
+ ArrayList<E> c = new ArrayList<E>();
+ for (Node<E> p = first(); p != null; p = succ(p)) {
+ E item = p.item;
+ if (item != null)
+ c.add(item);
+ }
+ return c;
+ }
+
+ // Fields and constructors
+
+ private static final long serialVersionUID = 876323262645176354L;
+
+ /**
+ * Constructs an empty deque.
+ */
+ public ConcurrentLinkedDeque() {}
+
+ /**
+ * Constructs a deque initially containing the elements of
+ * the given collection, added in traversal order of the
+ * collection's iterator.
+ *
+ * @param c the collection of elements to initially contain
+ * @throws NullPointerException if the specified collection or any
+ * of its elements are null
+ */
+ public ConcurrentLinkedDeque(Collection<? extends E> c) {
+ this();
+ addAll(c);
+ }
+
+ /**
+ * Inserts the specified element at the front of this deque.
+ *
+ * @throws NullPointerException {@inheritDoc}
+ */
+ public void addFirst(E e) {
+ linkFirst(e);
+ }
+
+ /**
+ * Inserts the specified element at the end of this deque.
+ * This is identical in function to the {@code add} method.
+ *
+ * @throws NullPointerException {@inheritDoc}
+ */
+ public void addLast(E e) {
+ linkLast(e);
+ }
+
+ /**
+ * Inserts the specified element at the front of this deque.
+ *
+ * @return {@code true} always
+ * @throws NullPointerException {@inheritDoc}
+ */
+ public boolean offerFirst(E e) {
+ linkFirst(e);
+ return true;
+ }
+
+ /**
+ * Inserts the specified element at the end of this deque.
+ *
+ * <p>This method is equivalent to {@link #add}.
+ *
+ * @return {@code true} always
+ * @throws NullPointerException {@inheritDoc}
+ */
+ public boolean offerLast(E e) {
+ linkLast(e);
+ return true;
+ }
+
+ public E peekFirst() {
+ for (Node<E> p = first(); p != null; p = succ(p)) {
+ E item = p.item;
+ if (item != null)
+ return item;
+ }
+ return null;
+ }
+
+ public E peekLast() {
+ for (Node<E> p = last(); p != null; p = pred(p)) {
+ E item = p.item;
+ if (item != null)
+ return item;
+ }
+ return null;
+ }
+
+ /**
+ * @throws NoSuchElementException {@inheritDoc}
+ */
+ public E getFirst() {
+ return screenNullResult(peekFirst());
+ }
+
+ /**
+ * @throws NoSuchElementException {@inheritDoc}
+ */
+ public E getLast() {
+ return screenNullResult(peekLast());
+ }
+
+ public E pollFirst() {
+ for (Node<E> p = first(); p != null; p = succ(p)) {
+ E item = p.item;
+ if (item != null && p.casItem(item, null)) {
+ unlink(p);
+ return item;
+ }
+ }
+ return null;
+ }
+
+ public E pollLast() {
+ for (Node<E> p = last(); p != null; p = pred(p)) {
+ E item = p.item;
+ if (item != null && p.casItem(item, null)) {
+ unlink(p);
+ return item;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * @throws NoSuchElementException {@inheritDoc}
+ */
+ public E removeFirst() {
+ return screenNullResult(pollFirst());
+ }
+
+ /**
+ * @throws NoSuchElementException {@inheritDoc}
+ */
+ public E removeLast() {
+ return screenNullResult(pollLast());
+ }
+
+ // *** Queue and stack methods ***
+
+ /**
+ * Inserts the specified element at the tail of this deque.
+ *
+ * @return {@code true} (as specified by {@link Queue#offer})
+ * @throws NullPointerException if the specified element is null
+ */
+ public boolean offer(E e) {
+ return offerLast(e);
+ }
+
+ /**
+ * Inserts the specified element at the tail of this deque.
+ *
+ * @return {@code true} (as specified by {@link Collection#add})
+ * @throws NullPointerException if the specified element is null
+ */
+ public boolean add(E e) {
+ return offerLast(e);
+ }
+
+ public E poll() { return pollFirst(); }
+ public E remove() { return removeFirst(); }
+ public E peek() { return peekFirst(); }
+ public E element() { return getFirst(); }
+ public void push(E e) { addFirst(e); }
+ public E pop() { return removeFirst(); }
+
+ /**
+ * Removes the first element {@code e} such that
+ * {@code o.equals(e)}, if such an element exists in this deque.
+ * If the deque does not contain the element, it is unchanged.
+ *
+ * @param o element to be removed from this deque, if present
+ * @return {@code true} if the deque contained the specified element
+ * @throws NullPointerException if the specified element is {@code null}
+ */
+ public boolean removeFirstOccurrence(Object o) {
+ checkNotNull(o);
+ for (Node<E> p = first(); p != null; p = succ(p)) {
+ E item = p.item;
+ if (item != null && o.equals(item) && p.casItem(item, null)) {
+ unlink(p);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Removes the last element {@code e} such that
+ * {@code o.equals(e)}, if such an element exists in this deque.
+ * If the deque does not contain the element, it is unchanged.
+ *
+ * @param o element to be removed from this deque, if present
+ * @return {@code true} if the deque contained the specified element
+ * @throws NullPointerException if the specified element is {@code null}
+ */
+ public boolean removeLastOccurrence(Object o) {
+ checkNotNull(o);
+ for (Node<E> p = last(); p != null; p = pred(p)) {
+ E item = p.item;
+ if (item != null && o.equals(item) && p.casItem(item, null)) {
+ unlink(p);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns {@code true} if this deque contains at least one
+ * element {@code e} such that {@code o.equals(e)}.
+ *
+ * @param o element whose presence in this deque is to be tested
+ * @return {@code true} if this deque contains the specified element
+ */
+ public boolean contains(Object o) {
+ if (o == null) return false;
+ for (Node<E> p = first(); p != null; p = succ(p)) {
+ E item = p.item;
+ if (item != null && o.equals(item))
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Returns {@code true} if this collection contains no elements.
+ *
+ * @return {@code true} if this collection contains no elements
+ */
+ public boolean isEmpty() {
+ return peekFirst() == null;
+ }
+
+ /**
+ * Returns the number of elements in this deque. If this deque
+ * contains more than {@code Integer.MAX_VALUE} elements, it
+ * returns {@code Integer.MAX_VALUE}.
+ *
+ * <p>Beware that, unlike in most collections, this method is
+ * <em>NOT</em> a constant-time operation. Because of the
+ * asynchronous nature of these deques, determining the current
+ * number of elements requires traversing them all to count them.
+ * Additionally, it is possible for the size to change during
+ * execution of this method, in which case the returned result
+ * will be inaccurate. Thus, this method is typically not very
+ * useful in concurrent applications.
+ *
+ * @return the number of elements in this deque
+ */
+ public int size() {
+ long count = 0;
+ for (Node<E> p = first(); p != null; p = succ(p))
+ if (p.item != null)
+ ++count;
+ return (count >= Integer.MAX_VALUE) ? Integer.MAX_VALUE : (int) count;
+ }
+
+ /**
+ * Removes the first element {@code e} such that
+ * {@code o.equals(e)}, if such an element exists in this deque.
+ * If the deque does not contain the element, it is unchanged.
+ *
+ * @param o element to be removed from this deque, if present
+ * @return {@code true} if the deque contained the specified element
+ * @throws NullPointerException if the specified element is {@code null}
+ */
+ public boolean remove(Object o) {
+ return removeFirstOccurrence(o);
+ }
+
+ /**
+ * Appends all of the elements in the specified collection to the end of
+ * this deque, in the order that they are returned by the specified
+ * collection's iterator. The behavior of this operation is undefined if
+ * the specified collection is modified while the operation is in
+ * progress. (This implies that the behavior of this call is undefined if
+ * the specified Collection is this deque, and this deque is nonempty.)
+ *
+ * @param c the elements to be inserted into this deque
+ * @return {@code true} if this deque changed as a result of the call
+ * @throws NullPointerException if {@code c} or any element within it
+ * is {@code null}
+ */
+ public boolean addAll(Collection<? extends E> c) {
+ Iterator<? extends E> it = c.iterator();
+ if (!it.hasNext())
+ return false;
+ do {
+ addLast(it.next());
+ } while (it.hasNext());
+ return true;
+ }
+
+ /**
+ * Removes all of the elements from this deque.
+ */
+ public void clear() {
+ while (pollFirst() != null)
+ ;
+ }
+
+ /**
+ * Returns an array containing all of the elements in this deque, in
+ * proper sequence (from first to last element).
+ *
+ * <p>The returned array will be "safe" in that no references to it are
+ * maintained by this deque. (In other words, this method must allocate
+ * a new array). The caller is thus free to modify the returned array.
+ *
+ * <p>This method acts as bridge between array-based and collection-based
+ * APIs.
+ *
+ * @return an array containing all of the elements in this deque
+ */
+ public Object[] toArray() {
+ return toArrayList().toArray();
+ }
+
+ /**
+ * Returns an array containing all of the elements in this deque,
+ * in proper sequence (from first to last element); the runtime
+ * type of the returned array is that of the specified array. If
+ * the deque fits in the specified array, it is returned therein.
+ * Otherwise, a new array is allocated with the runtime type of
+ * the specified array and the size of this deque.
+ *
+ * <p>If this deque fits in the specified array with room to spare
+ * (i.e., the array has more elements than this deque), the element in
+ * the array immediately following the end of the deque is set to
+ * {@code null}.
+ *
+ * <p>Like the {@link #toArray()} method, this method acts as bridge between
+ * array-based and collection-based APIs. Further, this method allows
+ * precise control over the runtime type of the output array, and may,
+ * under certain circumstances, be used to save allocation costs.
+ *
+ * <p>Suppose {@code x} is a deque known to contain only strings.
+ * The following code can be used to dump the deque into a newly
+ * allocated array of {@code String}:
+ *
+ * <pre>
+ * String[] y = x.toArray(new String[0]);</pre>
+ *
+ * Note that {@code toArray(new Object[0])} is identical in function to
+ * {@code toArray()}.
+ *
+ * @param a the array into which the elements of the deque are to
+ * be stored, if it is big enough; otherwise, a new array of the
+ * same runtime type is allocated for this purpose
+ * @return an array containing all of the elements in this deque
+ * @throws ArrayStoreException if the runtime type of the specified array
+ * is not a supertype of the runtime type of every element in
+ * this deque
+ * @throws NullPointerException if the specified array is null
+ */
+ public <T> T[] toArray(T[] a) {
+ return toArrayList().toArray(a);
+ }
+
+ /**
+ * Returns an iterator over the elements in this deque in proper sequence.
+ * The elements will be returned in order from first (head) to last (tail).
+ *
+ * <p>The returned {@code Iterator} is a "weakly consistent" iterator that
+ * will never throw {@link java.util.ConcurrentModificationException
+ * ConcurrentModificationException},
+ * and guarantees to traverse elements as they existed upon
+ * construction of the iterator, and may (but is not guaranteed to)
+ * reflect any modifications subsequent to construction.
+ *
+ * @return an iterator over the elements in this deque in proper sequence
+ */
+ public Iterator<E> iterator() {
+ return new Itr();
+ }
+
+ /**
+ * Returns an iterator over the elements in this deque in reverse
+ * sequential order. The elements will be returned in order from
+ * last (tail) to first (head).
+ *
+ * <p>The returned {@code Iterator} is a "weakly consistent" iterator that
+ * will never throw {@link java.util.ConcurrentModificationException
+ * ConcurrentModificationException},
+ * and guarantees to traverse elements as they existed upon
+ * construction of the iterator, and may (but is not guaranteed to)
+ * reflect any modifications subsequent to construction.
+ */
+ public Iterator<E> descendingIterator() {
+ return new DescendingItr();
+ }
+
+ private abstract class AbstractItr 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 returned by most recent call to next. Needed by remove.
+ * Reset to null if this element is deleted by a call to remove.
+ */
+ private Node<E> lastRet;
+
+ abstract Node<E> startNode();
+ abstract Node<E> nextNode(Node<E> p);
+
+ AbstractItr() {
+ advance();
+ }
+
+ /**
+ * Sets nextNode and nextItem to next valid node, or to null
+ * if no such.
+ */
+ private void advance() {
+ lastRet = nextNode;
+
+ Node<E> p = (nextNode == null) ? startNode() : nextNode(nextNode);
+ for (;; p = nextNode(p)) {
+ if (p == null) {
+ // p might be active end or TERMINATOR node; both are OK
+ nextNode = null;
+ nextItem = null;
+ break;
+ }
+ E item = p.item;
+ if (item != null) {
+ nextNode = p;
+ nextItem = item;
+ break;
+ }
+ }
+ }
+
+ public boolean hasNext() {
+ return nextItem != null;
+ }
+
+ public E next() {
+ E item = nextItem;
+ if (item == null) throw new NoSuchElementException();
+ advance();
+ return item;
+ }
+
+ public void remove() {
+ Node<E> l = lastRet;
+ if (l == null) throw new IllegalStateException();
+ l.item = null;
+ unlink(l);
+ lastRet = null;
+ }
+ }
+
+ /** Forward iterator */
+ private class Itr extends AbstractItr {
+ Node<E> startNode() { return first(); }
+ Node<E> nextNode(Node<E> p) { return succ(p); }
+ }
+
+ /** Descending iterator */
+ private class DescendingItr extends AbstractItr {
+ Node<E> startNode() { return last(); }
+ Node<E> nextNode(Node<E> p) { return pred(p); }
+ }
+
+ /**
+ * Save the state to a stream (that is, serialize it).
+ *
+ * @serialData All of the elements (each an {@code E}) in
+ * the proper order, followed by a null
+ * @param s the stream
+ */
+ private void writeObject(java.io.ObjectOutputStream s)
+ throws java.io.IOException {
+
+ // Write out any hidden stuff
+ s.defaultWriteObject();
+
+ // Write out all elements in the proper order.
+ for (Node<E> p = first(); p != null; p = succ(p)) {
+ Object item = p.item;
+ if (item != null)
+ s.writeObject(item);
+ }
+
+ // Use trailing null as sentinel
+ s.writeObject(null);
+ }
+
+ /**
+ * 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();
+ tail = head = new Node<E>(null);
+ // Read in all elements and place in queue
+ for (;;) {
+ @SuppressWarnings("unchecked")
+ E item = (E)s.readObject();
+ if (item == null)
+ break;
+ else
+ offer(item);
+ }
+ }
+
+ // Unsafe mechanics
+
+ private static final sun.misc.Unsafe UNSAFE =
+ sun.misc.Unsafe.getUnsafe();
+ private static final long headOffset =
+ objectFieldOffset(UNSAFE, "head", ConcurrentLinkedDeque.class);
+ private static final long tailOffset =
+ objectFieldOffset(UNSAFE, "tail", ConcurrentLinkedDeque.class);
+
+ private boolean casHead(Node<E> cmp, Node<E> val) {
+ return UNSAFE.compareAndSwapObject(this, headOffset, cmp, val);
+ }
+
+ private boolean casTail(Node<E> cmp, Node<E> val) {
+ return UNSAFE.compareAndSwapObject(this, tailOffset, cmp, val);
+ }
+
+ static long objectFieldOffset(sun.misc.Unsafe UNSAFE,
+ String field, Class<?> klazz) {
+ try {
+ return UNSAFE.objectFieldOffset(klazz.getDeclaredField(field));
+ } catch (NoSuchFieldException e) {
+ // Convert Exception to corresponding Error
+ NoSuchFieldError error = new NoSuchFieldError(field);
+ error.initCause(e);
+ throw error;
+ }
+ }
+}
diff --git a/concurrent/src/main/java/java/util/concurrent/ConcurrentLinkedQueue.java b/concurrent/src/main/java/java/util/concurrent/ConcurrentLinkedQueue.java
index 2253823..2d222c1 100644
--- a/concurrent/src/main/java/java/util/concurrent/ConcurrentLinkedQueue.java
+++ b/concurrent/src/main/java/java/util/concurrent/ConcurrentLinkedQueue.java
@@ -5,9 +5,13 @@
*/
package java.util.concurrent;
-import java.util.*;
-import java.util.concurrent.atomic.*;
+import java.util.AbstractQueue;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.Queue;
// BEGIN android-note
// removed link to collections framework docs
@@ -126,34 +130,34 @@ public class ConcurrentLinkedQueue<E> extends AbstractQueue<E>
* CAS, so they never regress, although again this is merely an
* optimization.
*/
+
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 item) { setItem(item); }
+ Node(E item) {
+ // Piggyback on imminent casNext()
+ lazySetItem(item);
+ }
E getItem() {
return item;
}
boolean casItem(E cmp, E val) {
- return itemUpdater.compareAndSet(this, cmp, val);
+ return UNSAFE.compareAndSwapObject(this, itemOffset, cmp, val);
}
void setItem(E val) {
- itemUpdater.set(this, val);
+ item = val;
+ }
+
+ void lazySetItem(E val) {
+ UNSAFE.putOrderedObject(this, itemOffset, val);
+ }
+
+ void lazySetNext(Node<E> val) {
+ UNSAFE.putOrderedObject(this, nextOffset, val);
}
Node<E> getNext() {
@@ -161,42 +165,45 @@ public class ConcurrentLinkedQueue<E> extends AbstractQueue<E>
}
boolean casNext(Node<E> cmp, Node<E> val) {
- return nextUpdater.compareAndSet(this, cmp, val);
+ return UNSAFE.compareAndSwapObject(this, nextOffset, cmp, val);
}
- void setNext(Node<E> val) {
- nextUpdater.set(this, val);
- }
+ // Unsafe mechanics
+ private static final sun.misc.Unsafe UNSAFE =
+ sun.misc.Unsafe.getUnsafe();
+ private static final long nextOffset =
+ objectFieldOffset(UNSAFE, "next", Node.class);
+ private static final long itemOffset =
+ objectFieldOffset(UNSAFE, "item", Node.class);
}
- 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 first node, initialized to a dummy node.
+ * A node from which the first live (non-deleted) node (if any)
+ * can be reached in O(1) time.
+ * Invariants:
+ * - all live nodes are reachable from head via succ()
+ * - head != null
+ * - (tmp = head).next != tmp || tmp != head
+ * Non-invariants:
+ * - head.item may or may not be null.
+ * - it is permitted for tail to lag behind head, that is, for tail
+ * to not be reachable from head!
*/
private transient volatile Node<E> head = new Node<E>(null);
- /** Pointer to last node on list */
+ /**
+ * A node from which the last node on list (that is, the unique
+ * node with node.next == null) can be reached in O(1) time.
+ * Invariants:
+ * - the last node is always reachable from tail via succ()
+ * - tail != null
+ * Non-invariants:
+ * - tail.item may or may not be null.
+ * - it is permitted for tail to lag behind head, that is, for tail
+ * to not be reachable from head!
+ * - tail.next may or may not be self-pointing to tail.
+ */
private transient volatile Node<E> tail = head;
@@ -214,8 +221,8 @@ public class ConcurrentLinkedQueue<E> extends AbstractQueue<E>
* of its elements are null
*/
public ConcurrentLinkedQueue(Collection<? extends E> c) {
- for (Iterator<? extends E> it = c.iterator(); it.hasNext();)
- add(it.next());
+ for (E e : c)
+ add(e);
}
// Have to override just to update the javadoc
@@ -231,7 +238,7 @@ public class ConcurrentLinkedQueue<E> extends AbstractQueue<E>
}
/**
- * We don't bother to update head or tail pointers if less than
+ * We don't bother to update head or tail pointers if fewer than
* HOPS links from "true" location. We assume that volatile
* writes are significantly more expensive than volatile reads.
*/
@@ -243,7 +250,7 @@ public class ConcurrentLinkedQueue<E> extends AbstractQueue<E>
*/
final void updateHead(Node<E> h, Node<E> p) {
if (h != p && casHead(h, p))
- h.setNext(h);
+ h.lazySetNext(h);
}
/**
@@ -328,10 +335,12 @@ public class ConcurrentLinkedQueue<E> extends AbstractQueue<E>
}
/**
- * 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.)
+ * Returns the first live (non-deleted) node on list, or null if none.
+ * This is yet another variant of poll/peek; here returning the
+ * first node, not element. We could make peek() a wrapper around
+ * first(), but that would cost an extra volatile read of item,
+ * and the need to add a retry loop to deal with the possibility
+ * of losing a race to a concurrent poll().
*/
Node<E> first() {
Node<E> h = head;
@@ -422,7 +431,9 @@ public class ConcurrentLinkedQueue<E> extends AbstractQueue<E>
Node<E> pred = null;
for (Node<E> p = first(); p != null; p = succ(p)) {
E item = p.getItem();
- if (item != null && o.equals(item) && p.casItem(item, null)) {
+ if (item != null &&
+ o.equals(item) &&
+ p.casItem(item, null)) {
Node<E> next = succ(p);
if (pred != null && next != null)
pred.casNext(p, next);
@@ -522,7 +533,8 @@ public class ConcurrentLinkedQueue<E> extends AbstractQueue<E>
/**
* 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 ConcurrentModificationException},
+ * will never throw {@link java.util.ConcurrentModificationException
+ * ConcurrentModificationException},
* and guarantees to traverse elements as they existed upon
* construction of the iterator, and may (but is not guaranteed to)
* reflect any modifications subsequent to construction.
@@ -658,4 +670,35 @@ public class ConcurrentLinkedQueue<E> extends AbstractQueue<E>
}
}
+ // Unsafe mechanics
+
+ private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe();
+ private static final long headOffset =
+ objectFieldOffset(UNSAFE, "head", ConcurrentLinkedQueue.class);
+ private static final long tailOffset =
+ objectFieldOffset(UNSAFE, "tail", ConcurrentLinkedQueue.class);
+
+ private boolean casTail(Node<E> cmp, Node<E> val) {
+ return UNSAFE.compareAndSwapObject(this, tailOffset, cmp, val);
+ }
+
+ private boolean casHead(Node<E> cmp, Node<E> val) {
+ return UNSAFE.compareAndSwapObject(this, headOffset, cmp, val);
+ }
+
+ private void lazySetHead(Node<E> val) {
+ UNSAFE.putOrderedObject(this, headOffset, val);
+ }
+
+ static long objectFieldOffset(sun.misc.Unsafe UNSAFE,
+ String field, Class<?> klazz) {
+ try {
+ return UNSAFE.objectFieldOffset(klazz.getDeclaredField(field));
+ } catch (NoSuchFieldException e) {
+ // Convert Exception to corresponding Error
+ NoSuchFieldError error = new NoSuchFieldError(field);
+ error.initCause(e);
+ throw error;
+ }
+ }
}
diff --git a/concurrent/src/main/java/java/util/concurrent/ConcurrentNavigableMap.java b/concurrent/src/main/java/java/util/concurrent/ConcurrentNavigableMap.java
new file mode 100644
index 0000000..7d86afb
--- /dev/null
+++ b/concurrent/src/main/java/java/util/concurrent/ConcurrentNavigableMap.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;
+import java.util.*;
+
+/**
+ * A {@link ConcurrentMap} supporting {@link NavigableMap} operations,
+ * and recursively so for its navigable sub-maps.
+ *
+ * <p>This interface is a member of the
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
+ * Java Collections Framework</a>.
+ *
+ * @author Doug Lea
+ * @param <K> the type of keys maintained by this map
+ * @param <V> the type of mapped values
+ * @since 1.6
+ */
+public interface ConcurrentNavigableMap<K,V>
+ extends ConcurrentMap<K,V>, NavigableMap<K,V>
+{
+ /**
+ * @throws ClassCastException {@inheritDoc}
+ * @throws NullPointerException {@inheritDoc}
+ * @throws IllegalArgumentException {@inheritDoc}
+ */
+ ConcurrentNavigableMap<K,V> subMap(K fromKey, boolean fromInclusive,
+ K toKey, boolean toInclusive);
+
+ /**
+ * @throws ClassCastException {@inheritDoc}
+ * @throws NullPointerException {@inheritDoc}
+ * @throws IllegalArgumentException {@inheritDoc}
+ */
+ ConcurrentNavigableMap<K,V> headMap(K toKey, boolean inclusive);
+
+
+ /**
+ * @throws ClassCastException {@inheritDoc}
+ * @throws NullPointerException {@inheritDoc}
+ * @throws IllegalArgumentException {@inheritDoc}
+ */
+ ConcurrentNavigableMap<K,V> tailMap(K fromKey, boolean inclusive);
+
+ /**
+ * @throws ClassCastException {@inheritDoc}
+ * @throws NullPointerException {@inheritDoc}
+ * @throws IllegalArgumentException {@inheritDoc}
+ */
+ ConcurrentNavigableMap<K,V> subMap(K fromKey, K toKey);
+
+ /**
+ * @throws ClassCastException {@inheritDoc}
+ * @throws NullPointerException {@inheritDoc}
+ * @throws IllegalArgumentException {@inheritDoc}
+ */
+ ConcurrentNavigableMap<K,V> headMap(K toKey);
+
+ /**
+ * @throws ClassCastException {@inheritDoc}
+ * @throws NullPointerException {@inheritDoc}
+ * @throws IllegalArgumentException {@inheritDoc}
+ */
+ ConcurrentNavigableMap<K,V> tailMap(K fromKey);
+
+ /**
+ * Returns a reverse order view of the mappings contained in this map.
+ * The descending map is backed by this map, so changes to the map are
+ * reflected in the descending map, and vice-versa.
+ *
+ * <p>The returned map has an ordering equivalent to
+ * <tt>{@link Collections#reverseOrder(Comparator) Collections.reverseOrder}(comparator())</tt>.
+ * The expression {@code m.descendingMap().descendingMap()} returns a
+ * view of {@code m} essentially equivalent to {@code m}.
+ *
+ * @return a reverse order view of this map
+ */
+ ConcurrentNavigableMap<K,V> descendingMap();
+
+ /**
+ * Returns a {@link NavigableSet} view of the keys contained in this map.
+ * The set's iterator returns the keys in ascending order.
+ * The set is backed by the map, so changes to the map are
+ * reflected in the set, and vice-versa. The set supports element
+ * removal, which removes the corresponding mapping from the map,
+ * via the {@code Iterator.remove}, {@code Set.remove},
+ * {@code removeAll}, {@code retainAll}, and {@code clear}
+ * operations. It does not support the {@code add} or {@code addAll}
+ * operations.
+ *
+ * <p>The view's {@code iterator} is a "weakly consistent" iterator
+ * that will never throw {@link ConcurrentModificationException},
+ * and guarantees to traverse elements as they existed upon
+ * construction of the iterator, and may (but is not guaranteed to)
+ * reflect any modifications subsequent to construction.
+ *
+ * @return a navigable set view of the keys in this map
+ */
+ public NavigableSet<K> navigableKeySet();
+
+ /**
+ * Returns a {@link NavigableSet} view of the keys contained in this map.
+ * The set's iterator returns the keys in ascending order.
+ * The set is backed by the map, so changes to the map are
+ * reflected in the set, and vice-versa. The set supports element
+ * removal, which removes the corresponding mapping from the map,
+ * via the {@code Iterator.remove}, {@code Set.remove},
+ * {@code removeAll}, {@code retainAll}, and {@code clear}
+ * operations. It does not support the {@code add} or {@code addAll}
+ * operations.
+ *
+ * <p>The view's {@code iterator} is a "weakly consistent" iterator
+ * that will never throw {@link ConcurrentModificationException},
+ * and guarantees to traverse elements as they existed upon
+ * construction of the iterator, and may (but is not guaranteed to)
+ * reflect any modifications subsequent to construction.
+ *
+ * <p>This method is equivalent to method {@code navigableKeySet}.
+ *
+ * @return a navigable set view of the keys in this map
+ */
+ NavigableSet<K> keySet();
+
+ /**
+ * Returns a reverse order {@link NavigableSet} view of the keys contained in this map.
+ * The set's iterator returns the keys in descending order.
+ * The set is backed by the map, so changes to the map are
+ * reflected in the set, and vice-versa. The set supports element
+ * removal, which removes the corresponding mapping from the map,
+ * via the {@code Iterator.remove}, {@code Set.remove},
+ * {@code removeAll}, {@code retainAll}, and {@code clear}
+ * operations. It does not support the {@code add} or {@code addAll}
+ * operations.
+ *
+ * <p>The view's {@code iterator} is a "weakly consistent" iterator
+ * that will never throw {@link ConcurrentModificationException},
+ * and guarantees to traverse elements as they existed upon
+ * construction of the iterator, and may (but is not guaranteed to)
+ * reflect any modifications subsequent to construction.
+ *
+ * @return a reverse order navigable set view of the keys in this map
+ */
+ public NavigableSet<K> descendingKeySet();
+}
diff --git a/concurrent/src/main/java/java/util/concurrent/ConcurrentSkipListMap.java b/concurrent/src/main/java/java/util/concurrent/ConcurrentSkipListMap.java
new file mode 100644
index 0000000..d73d163
--- /dev/null
+++ b/concurrent/src/main/java/java/util/concurrent/ConcurrentSkipListMap.java
@@ -0,0 +1,3115 @@
+/*
+ * 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.*;
+
+/**
+ * A scalable concurrent {@link ConcurrentNavigableMap} implementation.
+ * The map is sorted according to the {@linkplain Comparable natural
+ * ordering} of its keys, or by a {@link Comparator} provided at map
+ * creation time, depending on which constructor is used.
+ *
+ * <p>This class implements a concurrent variant of <a
+ * href="http://www.cs.umd.edu/~pugh/">SkipLists</a> providing
+ * expected average <i>log(n)</i> time cost for the
+ * <tt>containsKey</tt>, <tt>get</tt>, <tt>put</tt> and
+ * <tt>remove</tt> operations and their variants. Insertion, removal,
+ * update, and access operations safely execute concurrently by
+ * multiple threads. Iterators are <i>weakly consistent</i>, returning
+ * elements reflecting the state of the map at some point at or since
+ * the creation of the iterator. They do <em>not</em> throw {@link
+ * ConcurrentModificationException}, and may proceed concurrently with
+ * other operations. Ascending key ordered views and their iterators
+ * are faster than descending ones.
+ *
+ * <p>All <tt>Map.Entry</tt> pairs returned by methods in this class
+ * and its views represent snapshots of mappings at the time they were
+ * produced. They do <em>not</em> support the <tt>Entry.setValue</tt>
+ * method. (Note however that it is possible to change mappings in the
+ * associated map using <tt>put</tt>, <tt>putIfAbsent</tt>, or
+ * <tt>replace</tt>, depending on exactly which effect you need.)
+ *
+ * <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 maps, determining the current number
+ * of elements requires a traversal of the elements. Additionally,
+ * the bulk operations <tt>putAll</tt>, <tt>equals</tt>, and
+ * <tt>clear</tt> are <em>not</em> guaranteed to be performed
+ * atomically. For example, an iterator operating concurrently with a
+ * <tt>putAll</tt> operation might view only some of the added
+ * elements.
+ *
+ * <p>This class and its views and iterators implement all of the
+ * <em>optional</em> methods of the {@link Map} and {@link Iterator}
+ * interfaces. Like most other concurrent collections, this class does
+ * <em>not</em> permit the use of <tt>null</tt> keys or values because some
+ * null return values cannot be reliably distinguished from the absence of
+ * elements.
+ *
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
+ * Java Collections Framework</a>.
+ *
+ * @author Doug Lea
+ * @param <K> the type of keys maintained by this map
+ * @param <V> the type of mapped values
+ * @since 1.6
+ */
+public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
+ implements ConcurrentNavigableMap<K,V>,
+ Cloneable,
+ java.io.Serializable {
+ /*
+ * This class implements a tree-like two-dimensionally linked skip
+ * list in which the index levels are represented in separate
+ * nodes from the base nodes holding data. There are two reasons
+ * for taking this approach instead of the usual array-based
+ * structure: 1) Array based implementations seem to encounter
+ * more complexity and overhead 2) We can use cheaper algorithms
+ * for the heavily-traversed index lists than can be used for the
+ * base lists. Here's a picture of some of the basics for a
+ * possible list with 2 levels of index:
+ *
+ * Head nodes Index nodes
+ * +-+ right +-+ +-+
+ * |2|---------------->| |--------------------->| |->null
+ * +-+ +-+ +-+
+ * | down | |
+ * v v v
+ * +-+ +-+ +-+ +-+ +-+ +-+
+ * |1|----------->| |->| |------>| |----------->| |------>| |->null
+ * +-+ +-+ +-+ +-+ +-+ +-+
+ * v | | | | |
+ * Nodes next v v v v v
+ * +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+
+ * | |->|A|->|B|->|C|->|D|->|E|->|F|->|G|->|H|->|I|->|J|->|K|->null
+ * +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+
+ *
+ * The base lists use a variant of the HM linked ordered set
+ * algorithm. See Tim Harris, "A pragmatic implementation of
+ * non-blocking linked lists"
+ * http://www.cl.cam.ac.uk/~tlh20/publications.html and Maged
+ * Michael "High Performance Dynamic Lock-Free Hash Tables and
+ * List-Based Sets"
+ * http://www.research.ibm.com/people/m/michael/pubs.htm. The
+ * basic idea in these lists is to mark the "next" pointers of
+ * deleted nodes when deleting to avoid conflicts with concurrent
+ * insertions, and when traversing to keep track of triples
+ * (predecessor, node, successor) in order to detect when and how
+ * to unlink these deleted nodes.
+ *
+ * Rather than using mark-bits to mark list deletions (which can
+ * be slow and space-intensive using AtomicMarkedReference), nodes
+ * use direct CAS'able next pointers. On deletion, instead of
+ * marking a pointer, they splice in another node that can be
+ * thought of as standing for a marked pointer (indicating this by
+ * using otherwise impossible field values). Using plain nodes
+ * acts roughly like "boxed" implementations of marked pointers,
+ * but uses new nodes only when nodes are deleted, not for every
+ * link. This requires less space and supports faster
+ * traversal. Even if marked references were better supported by
+ * JVMs, traversal using this technique might still be faster
+ * because any search need only read ahead one more node than
+ * otherwise required (to check for trailing marker) rather than
+ * unmasking mark bits or whatever on each read.
+ *
+ * This approach maintains the essential property needed in the HM
+ * algorithm of changing the next-pointer of a deleted node so
+ * that any other CAS of it will fail, but implements the idea by
+ * changing the pointer to point to a different node, not by
+ * marking it. While it would be possible to further squeeze
+ * space by defining marker nodes not to have key/value fields, it
+ * isn't worth the extra type-testing overhead. The deletion
+ * markers are rarely encountered during traversal and are
+ * normally quickly garbage collected. (Note that this technique
+ * would not work well in systems without garbage collection.)
+ *
+ * In addition to using deletion markers, the lists also use
+ * nullness of value fields to indicate deletion, in a style
+ * similar to typical lazy-deletion schemes. If a node's value is
+ * null, then it is considered logically deleted and ignored even
+ * though it is still reachable. This maintains proper control of
+ * concurrent replace vs delete operations -- an attempted replace
+ * must fail if a delete beat it by nulling field, and a delete
+ * must return the last non-null value held in the field. (Note:
+ * Null, rather than some special marker, is used for value fields
+ * here because it just so happens to mesh with the Map API
+ * requirement that method get returns null if there is no
+ * mapping, which allows nodes to remain concurrently readable
+ * even when deleted. Using any other marker value here would be
+ * messy at best.)
+ *
+ * Here's the sequence of events for a deletion of node n with
+ * predecessor b and successor f, initially:
+ *
+ * +------+ +------+ +------+
+ * ... | b |------>| n |----->| f | ...
+ * +------+ +------+ +------+
+ *
+ * 1. CAS n's value field from non-null to null.
+ * From this point on, no public operations encountering
+ * the node consider this mapping to exist. However, other
+ * ongoing insertions and deletions might still modify
+ * n's next pointer.
+ *
+ * 2. CAS n's next pointer to point to a new marker node.
+ * From this point on, no other nodes can be appended to n.
+ * which avoids deletion errors in CAS-based linked lists.
+ *
+ * +------+ +------+ +------+ +------+
+ * ... | b |------>| n |----->|marker|------>| f | ...
+ * +------+ +------+ +------+ +------+
+ *
+ * 3. CAS b's next pointer over both n and its marker.
+ * From this point on, no new traversals will encounter n,
+ * and it can eventually be GCed.
+ * +------+ +------+
+ * ... | b |----------------------------------->| f | ...
+ * +------+ +------+
+ *
+ * A failure at step 1 leads to simple retry due to a lost race
+ * with another operation. Steps 2-3 can fail because some other
+ * thread noticed during a traversal a node with null value and
+ * helped out by marking and/or unlinking. This helping-out
+ * ensures that no thread can become stuck waiting for progress of
+ * the deleting thread. The use of marker nodes slightly
+ * complicates helping-out code because traversals must track
+ * consistent reads of up to four nodes (b, n, marker, f), not
+ * just (b, n, f), although the next field of a marker is
+ * immutable, and once a next field is CAS'ed to point to a
+ * marker, it never again changes, so this requires less care.
+ *
+ * Skip lists add indexing to this scheme, so that the base-level
+ * traversals start close to the locations being found, inserted
+ * or deleted -- usually base level traversals only traverse a few
+ * nodes. This doesn't change the basic algorithm except for the
+ * need to make sure base traversals start at predecessors (here,
+ * b) that are not (structurally) deleted, otherwise retrying
+ * after processing the deletion.
+ *
+ * Index levels are maintained as lists with volatile next fields,
+ * using CAS to link and unlink. Races are allowed in index-list
+ * operations that can (rarely) fail to link in a new index node
+ * or delete one. (We can't do this of course for data nodes.)
+ * However, even when this happens, the index lists remain sorted,
+ * so correctly serve as indices. This can impact performance,
+ * but since skip lists are probabilistic anyway, the net result
+ * is that under contention, the effective "p" value may be lower
+ * than its nominal value. And race windows are kept small enough
+ * that in practice these failures are rare, even under a lot of
+ * contention.
+ *
+ * The fact that retries (for both base and index lists) are
+ * relatively cheap due to indexing allows some minor
+ * simplifications of retry logic. Traversal restarts are
+ * performed after most "helping-out" CASes. This isn't always
+ * strictly necessary, but the implicit backoffs tend to help
+ * reduce other downstream failed CAS's enough to outweigh restart
+ * cost. This worsens the worst case, but seems to improve even
+ * highly contended cases.
+ *
+ * Unlike most skip-list implementations, index insertion and
+ * deletion here require a separate traversal pass occuring after
+ * the base-level action, to add or remove index nodes. This adds
+ * to single-threaded overhead, but improves contended
+ * multithreaded performance by narrowing interference windows,
+ * and allows deletion to ensure that all index nodes will be made
+ * unreachable upon return from a public remove operation, thus
+ * avoiding unwanted garbage retention. This is more important
+ * here than in some other data structures because we cannot null
+ * out node fields referencing user keys since they might still be
+ * read by other ongoing traversals.
+ *
+ * Indexing uses skip list parameters that maintain good search
+ * performance while using sparser-than-usual indices: The
+ * hardwired parameters k=1, p=0.5 (see method randomLevel) mean
+ * that about one-quarter of the nodes have indices. Of those that
+ * do, half have one level, a quarter have two, and so on (see
+ * Pugh's Skip List Cookbook, sec 3.4). The expected total space
+ * requirement for a map is slightly less than for the current
+ * implementation of java.util.TreeMap.
+ *
+ * Changing the level of the index (i.e, the height of the
+ * tree-like structure) also uses CAS. The head index has initial
+ * level/height of one. Creation of an index with height greater
+ * than the current level adds a level to the head index by
+ * CAS'ing on a new top-most head. To maintain good performance
+ * after a lot of removals, deletion methods heuristically try to
+ * reduce the height if the topmost levels appear to be empty.
+ * This may encounter races in which it possible (but rare) to
+ * reduce and "lose" a level just as it is about to contain an
+ * index (that will then never be encountered). This does no
+ * structural harm, and in practice appears to be a better option
+ * than allowing unrestrained growth of levels.
+ *
+ * The code for all this is more verbose than you'd like. Most
+ * operations entail locating an element (or position to insert an
+ * element). The code to do this can't be nicely factored out
+ * because subsequent uses require a snapshot of predecessor
+ * and/or successor and/or value fields which can't be returned
+ * all at once, at least not without creating yet another object
+ * to hold them -- creating such little objects is an especially
+ * bad idea for basic internal search operations because it adds
+ * to GC overhead. (This is one of the few times I've wished Java
+ * had macros.) Instead, some traversal code is interleaved within
+ * insertion and removal operations. The control logic to handle
+ * all the retry conditions is sometimes twisty. Most search is
+ * broken into 2 parts. findPredecessor() searches index nodes
+ * only, returning a base-level predecessor of the key. findNode()
+ * finishes out the base-level search. Even with this factoring,
+ * there is a fair amount of near-duplication of code to handle
+ * variants.
+ *
+ * For explanation of algorithms sharing at least a couple of
+ * features with this one, see Mikhail Fomitchev's thesis
+ * (http://www.cs.yorku.ca/~mikhail/), Keir Fraser's thesis
+ * (http://www.cl.cam.ac.uk/users/kaf24/), and Hakan Sundell's
+ * thesis (http://www.cs.chalmers.se/~phs/).
+ *
+ * Given the use of tree-like index nodes, you might wonder why
+ * this doesn't use some kind of search tree instead, which would
+ * support somewhat faster search operations. The reason is that
+ * there are no known efficient lock-free insertion and deletion
+ * algorithms for search trees. The immutability of the "down"
+ * links of index nodes (as opposed to mutable "left" fields in
+ * true trees) makes this tractable using only CAS operations.
+ *
+ * Notation guide for local variables
+ * Node: b, n, f for predecessor, node, successor
+ * Index: q, r, d for index node, right, down.
+ * t for another index node
+ * Head: h
+ * Levels: j
+ * Keys: k, key
+ * Values: v, value
+ * Comparisons: c
+ */
+
+ private static final long serialVersionUID = -8627078645895051609L;
+
+ /**
+ * Generates the initial random seed for the cheaper per-instance
+ * random number generators used in randomLevel.
+ */
+ private static final Random seedGenerator = new Random();
+
+ /**
+ * Special value used to identify base-level header
+ */
+ private static final Object BASE_HEADER = new Object();
+
+ /**
+ * The topmost head index of the skiplist.
+ */
+ private transient volatile HeadIndex<K,V> head;
+
+ /**
+ * The comparator used to maintain order in this map, or null
+ * if using natural ordering.
+ * @serial
+ */
+ private final Comparator<? super K> comparator;
+
+ /**
+ * Seed for simple random number generator. Not volatile since it
+ * doesn't matter too much if different threads don't see updates.
+ */
+ private transient int randomSeed;
+
+ /** Lazily initialized key set */
+ private transient KeySet keySet;
+ /** Lazily initialized entry set */
+ private transient EntrySet entrySet;
+ /** Lazily initialized values collection */
+ private transient Values values;
+ /** Lazily initialized descending key set */
+ private transient ConcurrentNavigableMap<K,V> descendingMap;
+
+ /**
+ * Initializes or resets state. Needed by constructors, clone,
+ * clear, readObject. and ConcurrentSkipListSet.clone.
+ * (Note that comparator must be separately initialized.)
+ */
+ final void initialize() {
+ keySet = null;
+ entrySet = null;
+ values = null;
+ descendingMap = null;
+ randomSeed = seedGenerator.nextInt() | 0x0100; // ensure nonzero
+ head = new HeadIndex<K,V>(new Node<K,V>(null, BASE_HEADER, null),
+ null, null, 1);
+ }
+
+ /** Updater for casHead */
+ private static final
+ AtomicReferenceFieldUpdater<ConcurrentSkipListMap, HeadIndex>
+ headUpdater = AtomicReferenceFieldUpdater.newUpdater
+ (ConcurrentSkipListMap.class, HeadIndex.class, "head");
+
+ /**
+ * compareAndSet head node
+ */
+ private boolean casHead(HeadIndex<K,V> cmp, HeadIndex<K,V> val) {
+ return headUpdater.compareAndSet(this, cmp, val);
+ }
+
+ /* ---------------- Nodes -------------- */
+
+ /**
+ * Nodes hold keys and values, and are singly linked in sorted
+ * order, possibly with some intervening marker nodes. The list is
+ * headed by a dummy node accessible as head.node. The value field
+ * is declared only as Object because it takes special non-V
+ * values for marker and header nodes.
+ */
+ static final class Node<K,V> {
+ final K key;
+ volatile Object value;
+ volatile Node<K,V> next;
+
+ /**
+ * Creates a new regular node.
+ */
+ Node(K key, Object value, Node<K,V> next) {
+ this.key = key;
+ this.value = value;
+ this.next = next;
+ }
+
+ /**
+ * Creates a new marker node. A marker is distinguished by
+ * having its value field point to itself. Marker nodes also
+ * have null keys, a fact that is exploited in a few places,
+ * but this doesn't distinguish markers from the base-level
+ * header node (head.node), which also has a null key.
+ */
+ Node(Node<K,V> next) {
+ this.key = null;
+ this.value = this;
+ this.next = next;
+ }
+
+ /** Updater for casNext */
+ static final AtomicReferenceFieldUpdater<Node, Node>
+ nextUpdater = AtomicReferenceFieldUpdater.newUpdater
+ (Node.class, Node.class, "next");
+
+ /** Updater for casValue */
+ static final AtomicReferenceFieldUpdater<Node, Object>
+ valueUpdater = AtomicReferenceFieldUpdater.newUpdater
+ (Node.class, Object.class, "value");
+
+ /**
+ * compareAndSet value field
+ */
+ boolean casValue(Object cmp, Object val) {
+ return valueUpdater.compareAndSet(this, cmp, val);
+ }
+
+ /**
+ * compareAndSet next field
+ */
+ boolean casNext(Node<K,V> cmp, Node<K,V> val) {
+ return nextUpdater.compareAndSet(this, cmp, val);
+ }
+
+ /**
+ * Returns true if this node is a marker. This method isn't
+ * actually called in any current code checking for markers
+ * because callers will have already read value field and need
+ * to use that read (not another done here) and so directly
+ * test if value points to node.
+ * @param n a possibly null reference to a node
+ * @return true if this node is a marker node
+ */
+ boolean isMarker() {
+ return value == this;
+ }
+
+ /**
+ * Returns true if this node is the header of base-level list.
+ * @return true if this node is header node
+ */
+ boolean isBaseHeader() {
+ return value == BASE_HEADER;
+ }
+
+ /**
+ * Tries to append a deletion marker to this node.
+ * @param f the assumed current successor of this node
+ * @return true if successful
+ */
+ boolean appendMarker(Node<K,V> f) {
+ return casNext(f, new Node<K,V>(f));
+ }
+
+ /**
+ * Helps out a deletion by appending marker or unlinking from
+ * predecessor. This is called during traversals when value
+ * field seen to be null.
+ * @param b predecessor
+ * @param f successor
+ */
+ void helpDelete(Node<K,V> b, Node<K,V> f) {
+ /*
+ * Rechecking links and then doing only one of the
+ * help-out stages per call tends to minimize CAS
+ * interference among helping threads.
+ */
+ if (f == next && this == b.next) {
+ if (f == null || f.value != f) // not already marked
+ appendMarker(f);
+ else
+ b.casNext(this, f.next);
+ }
+ }
+
+ /**
+ * Returns value if this node contains a valid key-value pair,
+ * else null.
+ * @return this node's value if it isn't a marker or header or
+ * is deleted, else null.
+ */
+ V getValidValue() {
+ Object v = value;
+ if (v == this || v == BASE_HEADER)
+ return null;
+ return (V)v;
+ }
+
+ /**
+ * Creates and returns a new SimpleImmutableEntry holding current
+ * mapping if this node holds a valid value, else null.
+ * @return new entry or null
+ */
+ AbstractMap.SimpleImmutableEntry<K,V> createSnapshot() {
+ V v = getValidValue();
+ if (v == null)
+ return null;
+ return new AbstractMap.SimpleImmutableEntry<K,V>(key, v);
+ }
+ }
+
+ /* ---------------- Indexing -------------- */
+
+ /**
+ * Index nodes represent the levels of the skip list. Note that
+ * even though both Nodes and Indexes have forward-pointing
+ * fields, they have different types and are handled in different
+ * ways, that can't nicely be captured by placing field in a
+ * shared abstract class.
+ */
+ static class Index<K,V> {
+ final Node<K,V> node;
+ final Index<K,V> down;
+ volatile Index<K,V> right;
+
+ /**
+ * Creates index node with given values.
+ */
+ Index(Node<K,V> node, Index<K,V> down, Index<K,V> right) {
+ this.node = node;
+ this.down = down;
+ this.right = right;
+ }
+
+ /** Updater for casRight */
+ static final AtomicReferenceFieldUpdater<Index, Index>
+ rightUpdater = AtomicReferenceFieldUpdater.newUpdater
+ (Index.class, Index.class, "right");
+
+ /**
+ * compareAndSet right field
+ */
+ final boolean casRight(Index<K,V> cmp, Index<K,V> val) {
+ return rightUpdater.compareAndSet(this, cmp, val);
+ }
+
+ /**
+ * Returns true if the node this indexes has been deleted.
+ * @return true if indexed node is known to be deleted
+ */
+ final boolean indexesDeletedNode() {
+ return node.value == null;
+ }
+
+ /**
+ * Tries to CAS newSucc as successor. To minimize races with
+ * unlink that may lose this index node, if the node being
+ * indexed is known to be deleted, it doesn't try to link in.
+ * @param succ the expected current successor
+ * @param newSucc the new successor
+ * @return true if successful
+ */
+ final boolean link(Index<K,V> succ, Index<K,V> newSucc) {
+ Node<K,V> n = node;
+ newSucc.right = succ;
+ return n.value != null && casRight(succ, newSucc);
+ }
+
+ /**
+ * Tries to CAS right field to skip over apparent successor
+ * succ. Fails (forcing a retraversal by caller) if this node
+ * is known to be deleted.
+ * @param succ the expected current successor
+ * @return true if successful
+ */
+ final boolean unlink(Index<K,V> succ) {
+ return !indexesDeletedNode() && casRight(succ, succ.right);
+ }
+ }
+
+ /* ---------------- Head nodes -------------- */
+
+ /**
+ * Nodes heading each level keep track of their level.
+ */
+ static final class HeadIndex<K,V> extends Index<K,V> {
+ final int level;
+ HeadIndex(Node<K,V> node, Index<K,V> down, Index<K,V> right, int level) {
+ super(node, down, right);
+ this.level = level;
+ }
+ }
+
+ /* ---------------- Comparison utilities -------------- */
+
+ /**
+ * Represents a key with a comparator as a Comparable.
+ *
+ * Because most sorted collections seem to use natural ordering on
+ * Comparables (Strings, Integers, etc), most internal methods are
+ * geared to use them. This is generally faster than checking
+ * per-comparison whether to use comparator or comparable because
+ * it doesn't require a (Comparable) cast for each comparison.
+ * (Optimizers can only sometimes remove such redundant checks
+ * themselves.) When Comparators are used,
+ * ComparableUsingComparators are created so that they act in the
+ * same way as natural orderings. This penalizes use of
+ * Comparators vs Comparables, which seems like the right
+ * tradeoff.
+ */
+ static final class ComparableUsingComparator<K> implements Comparable<K> {
+ final K actualKey;
+ final Comparator<? super K> cmp;
+ ComparableUsingComparator(K key, Comparator<? super K> cmp) {
+ this.actualKey = key;
+ this.cmp = cmp;
+ }
+ public int compareTo(K k2) {
+ return cmp.compare(actualKey, k2);
+ }
+ }
+
+ /**
+ * If using comparator, return a ComparableUsingComparator, else
+ * cast key as Comparable, which may cause ClassCastException,
+ * which is propagated back to caller.
+ */
+ private Comparable<? super K> comparable(Object key) throws ClassCastException {
+ if (key == null)
+ throw new NullPointerException();
+ if (comparator != null)
+ return new ComparableUsingComparator<K>((K)key, comparator);
+ else
+ return (Comparable<? super K>)key;
+ }
+
+ /**
+ * Compares using comparator or natural ordering. Used when the
+ * ComparableUsingComparator approach doesn't apply.
+ */
+ int compare(K k1, K k2) throws ClassCastException {
+ Comparator<? super K> cmp = comparator;
+ if (cmp != null)
+ return cmp.compare(k1, k2);
+ else
+ return ((Comparable<? super K>)k1).compareTo(k2);
+ }
+
+ /**
+ * Returns true if given key greater than or equal to least and
+ * strictly less than fence, bypassing either test if least or
+ * fence are null. Needed mainly in submap operations.
+ */
+ boolean inHalfOpenRange(K key, K least, K fence) {
+ if (key == null)
+ throw new NullPointerException();
+ return ((least == null || compare(key, least) >= 0) &&
+ (fence == null || compare(key, fence) < 0));
+ }
+
+ /**
+ * Returns true if given key greater than or equal to least and less
+ * or equal to fence. Needed mainly in submap operations.
+ */
+ boolean inOpenRange(K key, K least, K fence) {
+ if (key == null)
+ throw new NullPointerException();
+ return ((least == null || compare(key, least) >= 0) &&
+ (fence == null || compare(key, fence) <= 0));
+ }
+
+ /* ---------------- Traversal -------------- */
+
+ /**
+ * Returns a base-level node with key strictly less than given key,
+ * or the base-level header if there is no such node. Also
+ * unlinks indexes to deleted nodes found along the way. Callers
+ * rely on this side-effect of clearing indices to deleted nodes.
+ * @param key the key
+ * @return a predecessor of key
+ */
+ private Node<K,V> findPredecessor(Comparable<? super K> key) {
+ if (key == null)
+ throw new NullPointerException(); // don't postpone errors
+ for (;;) {
+ Index<K,V> q = head;
+ Index<K,V> r = q.right;
+ for (;;) {
+ if (r != null) {
+ Node<K,V> n = r.node;
+ K k = n.key;
+ if (n.value == null) {
+ if (!q.unlink(r))
+ break; // restart
+ r = q.right; // reread r
+ continue;
+ }
+ if (key.compareTo(k) > 0) {
+ q = r;
+ r = r.right;
+ continue;
+ }
+ }
+ Index<K,V> d = q.down;
+ if (d != null) {
+ q = d;
+ r = d.right;
+ } else
+ return q.node;
+ }
+ }
+ }
+
+ /**
+ * Returns node holding key or null if no such, clearing out any
+ * deleted nodes seen along the way. Repeatedly traverses at
+ * base-level looking for key starting at predecessor returned
+ * from findPredecessor, processing base-level deletions as
+ * encountered. Some callers rely on this side-effect of clearing
+ * deleted nodes.
+ *
+ * Restarts occur, at traversal step centered on node n, if:
+ *
+ * (1) After reading n's next field, n is no longer assumed
+ * predecessor b's current successor, which means that
+ * we don't have a consistent 3-node snapshot and so cannot
+ * unlink any subsequent deleted nodes encountered.
+ *
+ * (2) n's value field is null, indicating n is deleted, in
+ * which case we help out an ongoing structural deletion
+ * before retrying. Even though there are cases where such
+ * unlinking doesn't require restart, they aren't sorted out
+ * here because doing so would not usually outweigh cost of
+ * restarting.
+ *
+ * (3) n is a marker or n's predecessor's value field is null,
+ * indicating (among other possibilities) that
+ * findPredecessor returned a deleted node. We can't unlink
+ * the node because we don't know its predecessor, so rely
+ * on another call to findPredecessor to notice and return
+ * some earlier predecessor, which it will do. This check is
+ * only strictly needed at beginning of loop, (and the
+ * b.value check isn't strictly needed at all) but is done
+ * each iteration to help avoid contention with other
+ * threads by callers that will fail to be able to change
+ * links, and so will retry anyway.
+ *
+ * The traversal loops in doPut, doRemove, and findNear all
+ * include the same three kinds of checks. And specialized
+ * versions appear in findFirst, and findLast and their
+ * variants. They can't easily share code because each uses the
+ * reads of fields held in locals occurring in the orders they
+ * were performed.
+ *
+ * @param key the key
+ * @return node holding key, or null if no such
+ */
+ private Node<K,V> findNode(Comparable<? super K> key) {
+ for (;;) {
+ Node<K,V> b = findPredecessor(key);
+ Node<K,V> n = b.next;
+ for (;;) {
+ if (n == null)
+ return null;
+ Node<K,V> f = n.next;
+ if (n != b.next) // inconsistent read
+ break;
+ Object v = n.value;
+ if (v == null) { // n is deleted
+ n.helpDelete(b, f);
+ break;
+ }
+ if (v == n || b.value == null) // b is deleted
+ break;
+ int c = key.compareTo(n.key);
+ if (c == 0)
+ return n;
+ if (c < 0)
+ return null;
+ b = n;
+ n = f;
+ }
+ }
+ }
+
+ /**
+ * Specialized variant of findNode to perform Map.get. Does a weak
+ * traversal, not bothering to fix any deleted index nodes,
+ * returning early if it happens to see key in index, and passing
+ * over any deleted base nodes, falling back to getUsingFindNode
+ * only if it would otherwise return value from an ongoing
+ * deletion. Also uses "bound" to eliminate need for some
+ * comparisons (see Pugh Cookbook). Also folds uses of null checks
+ * and node-skipping because markers have null keys.
+ * @param okey the key
+ * @return the value, or null if absent
+ */
+ private V doGet(Object okey) {
+ Comparable<? super K> key = comparable(okey);
+ Node<K,V> bound = null;
+ Index<K,V> q = head;
+ Index<K,V> r = q.right;
+ Node<K,V> n;
+ K k;
+ int c;
+ for (;;) {
+ Index<K,V> d;
+ // Traverse rights
+ if (r != null && (n = r.node) != bound && (k = n.key) != null) {
+ if ((c = key.compareTo(k)) > 0) {
+ q = r;
+ r = r.right;
+ continue;
+ } else if (c == 0) {
+ Object v = n.value;
+ return (v != null)? (V)v : getUsingFindNode(key);
+ } else
+ bound = n;
+ }
+
+ // Traverse down
+ if ((d = q.down) != null) {
+ q = d;
+ r = d.right;
+ } else
+ break;
+ }
+
+ // Traverse nexts
+ for (n = q.node.next; n != null; n = n.next) {
+ if ((k = n.key) != null) {
+ if ((c = key.compareTo(k)) == 0) {
+ Object v = n.value;
+ return (v != null)? (V)v : getUsingFindNode(key);
+ } else if (c < 0)
+ break;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Performs map.get via findNode. Used as a backup if doGet
+ * encounters an in-progress deletion.
+ * @param key the key
+ * @return the value, or null if absent
+ */
+ private V getUsingFindNode(Comparable<? super K> key) {
+ /*
+ * Loop needed here and elsewhere in case value field goes
+ * null just as it is about to be returned, in which case we
+ * lost a race with a deletion, so must retry.
+ */
+ for (;;) {
+ Node<K,V> n = findNode(key);
+ if (n == null)
+ return null;
+ Object v = n.value;
+ if (v != null)
+ return (V)v;
+ }
+ }
+
+ /* ---------------- Insertion -------------- */
+
+ /**
+ * Main insertion method. Adds element if not present, or
+ * replaces value if present and onlyIfAbsent is false.
+ * @param kkey the key
+ * @param value the value that must be associated with key
+ * @param onlyIfAbsent if should not insert if already present
+ * @return the old value, or null if newly inserted
+ */
+ private V doPut(K kkey, V value, boolean onlyIfAbsent) {
+ Comparable<? super K> key = comparable(kkey);
+ for (;;) {
+ Node<K,V> b = findPredecessor(key);
+ Node<K,V> n = b.next;
+ for (;;) {
+ if (n != null) {
+ Node<K,V> f = n.next;
+ if (n != b.next) // inconsistent read
+ break;
+ Object v = n.value;
+ if (v == null) { // n is deleted
+ n.helpDelete(b, f);
+ break;
+ }
+ if (v == n || b.value == null) // b is deleted
+ break;
+ int c = key.compareTo(n.key);
+ if (c > 0) {
+ b = n;
+ n = f;
+ continue;
+ }
+ if (c == 0) {
+ if (onlyIfAbsent || n.casValue(v, value))
+ return (V)v;
+ else
+ break; // restart if lost race to replace value
+ }
+ // else c < 0; fall through
+ }
+
+ Node<K,V> z = new Node<K,V>(kkey, value, n);
+ if (!b.casNext(n, z))
+ break; // restart if lost race to append to b
+ int level = randomLevel();
+ if (level > 0)
+ insertIndex(z, level);
+ return null;
+ }
+ }
+ }
+
+ /**
+ * Returns a random level for inserting a new node.
+ * Hardwired to k=1, p=0.5, max 31 (see above and
+ * Pugh's "Skip List Cookbook", sec 3.4).
+ *
+ * This uses the simplest of the generators described in George
+ * Marsaglia's "Xorshift RNGs" paper. This is not a high-quality
+ * generator but is acceptable here.
+ */
+ private int randomLevel() {
+ int x = randomSeed;
+ x ^= x << 13;
+ x ^= x >>> 17;
+ randomSeed = x ^= x << 5;
+ if ((x & 0x8001) != 0) // test highest and lowest bits
+ return 0;
+ int level = 1;
+ while (((x >>>= 1) & 1) != 0) ++level;
+ return level;
+ }
+
+ /**
+ * Creates and adds index nodes for the given node.
+ * @param z the node
+ * @param level the level of the index
+ */
+ private void insertIndex(Node<K,V> z, int level) {
+ HeadIndex<K,V> h = head;
+ int max = h.level;
+
+ if (level <= max) {
+ Index<K,V> idx = null;
+ for (int i = 1; i <= level; ++i)
+ idx = new Index<K,V>(z, idx, null);
+ addIndex(idx, h, level);
+
+ } else { // Add a new level
+ /*
+ * To reduce interference by other threads checking for
+ * empty levels in tryReduceLevel, new levels are added
+ * with initialized right pointers. Which in turn requires
+ * keeping levels in an array to access them while
+ * creating new head index nodes from the opposite
+ * direction.
+ */
+ level = max + 1;
+ Index<K,V>[] idxs = (Index<K,V>[])new Index[level+1];
+ Index<K,V> idx = null;
+ for (int i = 1; i <= level; ++i)
+ idxs[i] = idx = new Index<K,V>(z, idx, null);
+
+ HeadIndex<K,V> oldh;
+ int k;
+ for (;;) {
+ oldh = head;
+ int oldLevel = oldh.level;
+ if (level <= oldLevel) { // lost race to add level
+ k = level;
+ break;
+ }
+ HeadIndex<K,V> newh = oldh;
+ Node<K,V> oldbase = oldh.node;
+ for (int j = oldLevel+1; j <= level; ++j)
+ newh = new HeadIndex<K,V>(oldbase, newh, idxs[j], j);
+ if (casHead(oldh, newh)) {
+ k = oldLevel;
+ break;
+ }
+ }
+ addIndex(idxs[k], oldh, k);
+ }
+ }
+
+ /**
+ * Adds given index nodes from given level down to 1.
+ * @param idx the topmost index node being inserted
+ * @param h the value of head to use to insert. This must be
+ * snapshotted by callers to provide correct insertion level
+ * @param indexLevel the level of the index
+ */
+ private void addIndex(Index<K,V> idx, HeadIndex<K,V> h, int indexLevel) {
+ // Track next level to insert in case of retries
+ int insertionLevel = indexLevel;
+ Comparable<? super K> key = comparable(idx.node.key);
+ if (key == null) throw new NullPointerException();
+
+ // Similar to findPredecessor, but adding index nodes along
+ // path to key.
+ for (;;) {
+ int j = h.level;
+ Index<K,V> q = h;
+ Index<K,V> r = q.right;
+ Index<K,V> t = idx;
+ for (;;) {
+ if (r != null) {
+ Node<K,V> n = r.node;
+ // compare before deletion check avoids needing recheck
+ int c = key.compareTo(n.key);
+ if (n.value == null) {
+ if (!q.unlink(r))
+ break;
+ r = q.right;
+ continue;
+ }
+ if (c > 0) {
+ q = r;
+ r = r.right;
+ continue;
+ }
+ }
+
+ if (j == insertionLevel) {
+ // Don't insert index if node already deleted
+ if (t.indexesDeletedNode()) {
+ findNode(key); // cleans up
+ return;
+ }
+ if (!q.link(r, t))
+ break; // restart
+ if (--insertionLevel == 0) {
+ // need final deletion check before return
+ if (t.indexesDeletedNode())
+ findNode(key);
+ return;
+ }
+ }
+
+ if (--j >= insertionLevel && j < indexLevel)
+ t = t.down;
+ q = q.down;
+ r = q.right;
+ }
+ }
+ }
+
+ /* ---------------- Deletion -------------- */
+
+ /**
+ * Main deletion method. Locates node, nulls value, appends a
+ * deletion marker, unlinks predecessor, removes associated index
+ * nodes, and possibly reduces head index level.
+ *
+ * Index nodes are cleared out simply by calling findPredecessor.
+ * which unlinks indexes to deleted nodes found along path to key,
+ * which will include the indexes to this node. This is done
+ * unconditionally. We can't check beforehand whether there are
+ * index nodes because it might be the case that some or all
+ * indexes hadn't been inserted yet for this node during initial
+ * search for it, and we'd like to ensure lack of garbage
+ * retention, so must call to be sure.
+ *
+ * @param okey the key
+ * @param value if non-null, the value that must be
+ * associated with key
+ * @return the node, or null if not found
+ */
+ final V doRemove(Object okey, Object value) {
+ Comparable<? super K> key = comparable(okey);
+ for (;;) {
+ Node<K,V> b = findPredecessor(key);
+ Node<K,V> n = b.next;
+ for (;;) {
+ if (n == null)
+ return null;
+ Node<K,V> f = n.next;
+ if (n != b.next) // inconsistent read
+ break;
+ Object v = n.value;
+ if (v == null) { // n is deleted
+ n.helpDelete(b, f);
+ break;
+ }
+ if (v == n || b.value == null) // b is deleted
+ break;
+ int c = key.compareTo(n.key);
+ if (c < 0)
+ return null;
+ if (c > 0) {
+ b = n;
+ n = f;
+ continue;
+ }
+ if (value != null && !value.equals(v))
+ return null;
+ if (!n.casValue(v, null))
+ break;
+ if (!n.appendMarker(f) || !b.casNext(n, f))
+ findNode(key); // Retry via findNode
+ else {
+ findPredecessor(key); // Clean index
+ if (head.right == null)
+ tryReduceLevel();
+ }
+ return (V)v;
+ }
+ }
+ }
+
+ /**
+ * Possibly reduce head level if it has no nodes. This method can
+ * (rarely) make mistakes, in which case levels can disappear even
+ * though they are about to contain index nodes. This impacts
+ * performance, not correctness. To minimize mistakes as well as
+ * to reduce hysteresis, the level is reduced by one only if the
+ * topmost three levels look empty. Also, if the removed level
+ * looks non-empty after CAS, we try to change it back quick
+ * before anyone notices our mistake! (This trick works pretty
+ * well because this method will practically never make mistakes
+ * unless current thread stalls immediately before first CAS, in
+ * which case it is very unlikely to stall again immediately
+ * afterwards, so will recover.)
+ *
+ * We put up with all this rather than just let levels grow
+ * because otherwise, even a small map that has undergone a large
+ * number of insertions and removals will have a lot of levels,
+ * slowing down access more than would an occasional unwanted
+ * reduction.
+ */
+ private void tryReduceLevel() {
+ HeadIndex<K,V> h = head;
+ HeadIndex<K,V> d;
+ HeadIndex<K,V> e;
+ if (h.level > 3 &&
+ (d = (HeadIndex<K,V>)h.down) != null &&
+ (e = (HeadIndex<K,V>)d.down) != null &&
+ e.right == null &&
+ d.right == null &&
+ h.right == null &&
+ casHead(h, d) && // try to set
+ h.right != null) // recheck
+ casHead(d, h); // try to backout
+ }
+
+ /* ---------------- Finding and removing first element -------------- */
+
+ /**
+ * Specialized variant of findNode to get first valid node.
+ * @return first node or null if empty
+ */
+ Node<K,V> findFirst() {
+ for (;;) {
+ Node<K,V> b = head.node;
+ Node<K,V> n = b.next;
+ if (n == null)
+ return null;
+ if (n.value != null)
+ return n;
+ n.helpDelete(b, n.next);
+ }
+ }
+
+ /**
+ * Removes first entry; returns its snapshot.
+ * @return null if empty, else snapshot of first entry
+ */
+ Map.Entry<K,V> doRemoveFirstEntry() {
+ for (;;) {
+ Node<K,V> b = head.node;
+ Node<K,V> n = b.next;
+ if (n == null)
+ return null;
+ Node<K,V> f = n.next;
+ if (n != b.next)
+ continue;
+ Object v = n.value;
+ if (v == null) {
+ n.helpDelete(b, f);
+ continue;
+ }
+ if (!n.casValue(v, null))
+ continue;
+ if (!n.appendMarker(f) || !b.casNext(n, f))
+ findFirst(); // retry
+ clearIndexToFirst();
+ return new AbstractMap.SimpleImmutableEntry<K,V>(n.key, (V)v);
+ }
+ }
+
+ /**
+ * Clears out index nodes associated with deleted first entry.
+ */
+ private void clearIndexToFirst() {
+ for (;;) {
+ Index<K,V> q = head;
+ for (;;) {
+ Index<K,V> r = q.right;
+ if (r != null && r.indexesDeletedNode() && !q.unlink(r))
+ break;
+ if ((q = q.down) == null) {
+ if (head.right == null)
+ tryReduceLevel();
+ return;
+ }
+ }
+ }
+ }
+
+
+ /* ---------------- Finding and removing last element -------------- */
+
+ /**
+ * Specialized version of find to get last valid node.
+ * @return last node or null if empty
+ */
+ Node<K,V> findLast() {
+ /*
+ * findPredecessor can't be used to traverse index level
+ * because this doesn't use comparisons. So traversals of
+ * both levels are folded together.
+ */
+ Index<K,V> q = head;
+ for (;;) {
+ Index<K,V> d, r;
+ if ((r = q.right) != null) {
+ if (r.indexesDeletedNode()) {
+ q.unlink(r);
+ q = head; // restart
+ }
+ else
+ q = r;
+ } else if ((d = q.down) != null) {
+ q = d;
+ } else {
+ Node<K,V> b = q.node;
+ Node<K,V> n = b.next;
+ for (;;) {
+ if (n == null)
+ return (b.isBaseHeader())? null : b;
+ Node<K,V> f = n.next; // inconsistent read
+ if (n != b.next)
+ break;
+ Object v = n.value;
+ if (v == null) { // n is deleted
+ n.helpDelete(b, f);
+ break;
+ }
+ if (v == n || b.value == null) // b is deleted
+ break;
+ b = n;
+ n = f;
+ }
+ q = head; // restart
+ }
+ }
+ }
+
+ /**
+ * Specialized variant of findPredecessor to get predecessor of last
+ * valid node. Needed when removing the last entry. It is possible
+ * that all successors of returned node will have been deleted upon
+ * return, in which case this method can be retried.
+ * @return likely predecessor of last node
+ */
+ private Node<K,V> findPredecessorOfLast() {
+ for (;;) {
+ Index<K,V> q = head;
+ for (;;) {
+ Index<K,V> d, r;
+ if ((r = q.right) != null) {
+ if (r.indexesDeletedNode()) {
+ q.unlink(r);
+ break; // must restart
+ }
+ // proceed as far across as possible without overshooting
+ if (r.node.next != null) {
+ q = r;
+ continue;
+ }
+ }
+ if ((d = q.down) != null)
+ q = d;
+ else
+ return q.node;
+ }
+ }
+ }
+
+ /**
+ * Removes last entry; returns its snapshot.
+ * Specialized variant of doRemove.
+ * @return null if empty, else snapshot of last entry
+ */
+ Map.Entry<K,V> doRemoveLastEntry() {
+ for (;;) {
+ Node<K,V> b = findPredecessorOfLast();
+ Node<K,V> n = b.next;
+ if (n == null) {
+ if (b.isBaseHeader()) // empty
+ return null;
+ else
+ continue; // all b's successors are deleted; retry
+ }
+ for (;;) {
+ Node<K,V> f = n.next;
+ if (n != b.next) // inconsistent read
+ break;
+ Object v = n.value;
+ if (v == null) { // n is deleted
+ n.helpDelete(b, f);
+ break;
+ }
+ if (v == n || b.value == null) // b is deleted
+ break;
+ if (f != null) {
+ b = n;
+ n = f;
+ continue;
+ }
+ if (!n.casValue(v, null))
+ break;
+ K key = n.key;
+ Comparable<? super K> ck = comparable(key);
+ if (!n.appendMarker(f) || !b.casNext(n, f))
+ findNode(ck); // Retry via findNode
+ else {
+ findPredecessor(ck); // Clean index
+ if (head.right == null)
+ tryReduceLevel();
+ }
+ return new AbstractMap.SimpleImmutableEntry<K,V>(key, (V)v);
+ }
+ }
+ }
+
+ /* ---------------- Relational operations -------------- */
+
+ // Control values OR'ed as arguments to findNear
+
+ private static final int EQ = 1;
+ private static final int LT = 2;
+ private static final int GT = 0; // Actually checked as !LT
+
+ /**
+ * Utility for ceiling, floor, lower, higher methods.
+ * @param kkey the key
+ * @param rel the relation -- OR'ed combination of EQ, LT, GT
+ * @return nearest node fitting relation, or null if no such
+ */
+ Node<K,V> findNear(K kkey, int rel) {
+ Comparable<? super K> key = comparable(kkey);
+ for (;;) {
+ Node<K,V> b = findPredecessor(key);
+ Node<K,V> n = b.next;
+ for (;;) {
+ if (n == null)
+ return ((rel & LT) == 0 || b.isBaseHeader())? null : b;
+ Node<K,V> f = n.next;
+ if (n != b.next) // inconsistent read
+ break;
+ Object v = n.value;
+ if (v == null) { // n is deleted
+ n.helpDelete(b, f);
+ break;
+ }
+ if (v == n || b.value == null) // b is deleted
+ break;
+ int c = key.compareTo(n.key);
+ if ((c == 0 && (rel & EQ) != 0) ||
+ (c < 0 && (rel & LT) == 0))
+ return n;
+ if ( c <= 0 && (rel & LT) != 0)
+ return (b.isBaseHeader())? null : b;
+ b = n;
+ n = f;
+ }
+ }
+ }
+
+ /**
+ * Returns SimpleImmutableEntry for results of findNear.
+ * @param key the key
+ * @param rel the relation -- OR'ed combination of EQ, LT, GT
+ * @return Entry fitting relation, or null if no such
+ */
+ AbstractMap.SimpleImmutableEntry<K,V> getNear(K key, int rel) {
+ for (;;) {
+ Node<K,V> n = findNear(key, rel);
+ if (n == null)
+ return null;
+ AbstractMap.SimpleImmutableEntry<K,V> e = n.createSnapshot();
+ if (e != null)
+ return e;
+ }
+ }
+
+
+ /* ---------------- Constructors -------------- */
+
+ /**
+ * Constructs a new, empty map, sorted according to the
+ * {@linkplain Comparable natural ordering} of the keys.
+ */
+ public ConcurrentSkipListMap() {
+ this.comparator = null;
+ initialize();
+ }
+
+ /**
+ * Constructs a new, empty map, sorted according to the specified
+ * comparator.
+ *
+ * @param comparator the comparator that will be used to order this map.
+ * If <tt>null</tt>, the {@linkplain Comparable natural
+ * ordering} of the keys will be used.
+ */
+ public ConcurrentSkipListMap(Comparator<? super K> comparator) {
+ this.comparator = comparator;
+ initialize();
+ }
+
+ /**
+ * Constructs a new map containing the same mappings as the given map,
+ * sorted according to the {@linkplain Comparable natural ordering} of
+ * the keys.
+ *
+ * @param m the map whose mappings are to be placed in this map
+ * @throws ClassCastException if the keys in <tt>m</tt> are not
+ * {@link Comparable}, or are not mutually comparable
+ * @throws NullPointerException if the specified map or any of its keys
+ * or values are null
+ */
+ public ConcurrentSkipListMap(Map<? extends K, ? extends V> m) {
+ this.comparator = null;
+ initialize();
+ putAll(m);
+ }
+
+ /**
+ * Constructs a new map containing the same mappings and using the
+ * same ordering as the specified sorted map.
+ *
+ * @param m the sorted map whose mappings are to be placed in this
+ * map, and whose comparator is to be used to sort this map
+ * @throws NullPointerException if the specified sorted map or any of
+ * its keys or values are null
+ */
+ public ConcurrentSkipListMap(SortedMap<K, ? extends V> m) {
+ this.comparator = m.comparator();
+ initialize();
+ buildFromSorted(m);
+ }
+
+ /**
+ * Returns a shallow copy of this <tt>ConcurrentSkipListMap</tt>
+ * instance. (The keys and values themselves are not cloned.)
+ *
+ * @return a shallow copy of this map
+ */
+ public ConcurrentSkipListMap<K,V> clone() {
+ ConcurrentSkipListMap<K,V> clone = null;
+ try {
+ clone = (ConcurrentSkipListMap<K,V>) super.clone();
+ } catch (CloneNotSupportedException e) {
+ throw new InternalError();
+ }
+
+ clone.initialize();
+ clone.buildFromSorted(this);
+ return clone;
+ }
+
+ /**
+ * Streamlined bulk insertion to initialize from elements of
+ * given sorted map. Call only from constructor or clone
+ * method.
+ */
+ private void buildFromSorted(SortedMap<K, ? extends V> map) {
+ if (map == null)
+ throw new NullPointerException();
+
+ HeadIndex<K,V> h = head;
+ Node<K,V> basepred = h.node;
+
+ // Track the current rightmost node at each level. Uses an
+ // ArrayList to avoid committing to initial or maximum level.
+ ArrayList<Index<K,V>> preds = new ArrayList<Index<K,V>>();
+
+ // initialize
+ for (int i = 0; i <= h.level; ++i)
+ preds.add(null);
+ Index<K,V> q = h;
+ for (int i = h.level; i > 0; --i) {
+ preds.set(i, q);
+ q = q.down;
+ }
+
+ Iterator<? extends Map.Entry<? extends K, ? extends V>> it =
+ map.entrySet().iterator();
+ while (it.hasNext()) {
+ Map.Entry<? extends K, ? extends V> e = it.next();
+ int j = randomLevel();
+ if (j > h.level) j = h.level + 1;
+ K k = e.getKey();
+ V v = e.getValue();
+ if (k == null || v == null)
+ throw new NullPointerException();
+ Node<K,V> z = new Node<K,V>(k, v, null);
+ basepred.next = z;
+ basepred = z;
+ if (j > 0) {
+ Index<K,V> idx = null;
+ for (int i = 1; i <= j; ++i) {
+ idx = new Index<K,V>(z, idx, null);
+ if (i > h.level)
+ h = new HeadIndex<K,V>(h.node, h, idx, i);
+
+ if (i < preds.size()) {
+ preds.get(i).right = idx;
+ preds.set(i, idx);
+ } else
+ preds.add(idx);
+ }
+ }
+ }
+ head = h;
+ }
+
+ /* ---------------- Serialization -------------- */
+
+ /**
+ * Save the state of this map to a stream.
+ *
+ * @serialData The key (Object) and value (Object) for each
+ * key-value mapping represented by the map, followed by
+ * <tt>null</tt>. The key-value mappings are emitted in key-order
+ * (as determined by the Comparator, or by the keys' natural
+ * ordering if no Comparator).
+ */
+ private void writeObject(java.io.ObjectOutputStream s)
+ throws java.io.IOException {
+ // Write out the Comparator and any hidden stuff
+ s.defaultWriteObject();
+
+ // Write out keys and values (alternating)
+ for (Node<K,V> n = findFirst(); n != null; n = n.next) {
+ V v = n.getValidValue();
+ if (v != null) {
+ s.writeObject(n.key);
+ s.writeObject(v);
+ }
+ }
+ s.writeObject(null);
+ }
+
+ /**
+ * Reconstitute the map from a stream.
+ */
+ private void readObject(final java.io.ObjectInputStream s)
+ throws java.io.IOException, ClassNotFoundException {
+ // Read in the Comparator and any hidden stuff
+ s.defaultReadObject();
+ // Reset transients
+ initialize();
+
+ /*
+ * This is nearly identical to buildFromSorted, but is
+ * distinct because readObject calls can't be nicely adapted
+ * as the kind of iterator needed by buildFromSorted. (They
+ * can be, but doing so requires type cheats and/or creation
+ * of adaptor classes.) It is simpler to just adapt the code.
+ */
+
+ HeadIndex<K,V> h = head;
+ Node<K,V> basepred = h.node;
+ ArrayList<Index<K,V>> preds = new ArrayList<Index<K,V>>();
+ for (int i = 0; i <= h.level; ++i)
+ preds.add(null);
+ Index<K,V> q = h;
+ for (int i = h.level; i > 0; --i) {
+ preds.set(i, q);
+ q = q.down;
+ }
+
+ for (;;) {
+ Object k = s.readObject();
+ if (k == null)
+ break;
+ Object v = s.readObject();
+ if (v == null)
+ throw new NullPointerException();
+ K key = (K) k;
+ V val = (V) v;
+ int j = randomLevel();
+ if (j > h.level) j = h.level + 1;
+ Node<K,V> z = new Node<K,V>(key, val, null);
+ basepred.next = z;
+ basepred = z;
+ if (j > 0) {
+ Index<K,V> idx = null;
+ for (int i = 1; i <= j; ++i) {
+ idx = new Index<K,V>(z, idx, null);
+ if (i > h.level)
+ h = new HeadIndex<K,V>(h.node, h, idx, i);
+
+ if (i < preds.size()) {
+ preds.get(i).right = idx;
+ preds.set(i, idx);
+ } else
+ preds.add(idx);
+ }
+ }
+ }
+ head = h;
+ }
+
+ /* ------ Map API methods ------ */
+
+ /**
+ * Returns <tt>true</tt> if this map contains a mapping for the specified
+ * key.
+ *
+ * @param key key whose presence in this map is to be tested
+ * @return <tt>true</tt> if this map contains a mapping for the specified key
+ * @throws ClassCastException if the specified key cannot be compared
+ * with the keys currently in the map
+ * @throws NullPointerException if the specified key is null
+ */
+ public boolean containsKey(Object key) {
+ return doGet(key) != null;
+ }
+
+ /**
+ * Returns the value to which the specified key is mapped,
+ * or {@code null} if this map contains no mapping for the key.
+ *
+ * <p>More formally, if this map contains a mapping from a key
+ * {@code k} to a value {@code v} such that {@code key} compares
+ * equal to {@code k} according to the map's ordering, then this
+ * method returns {@code v}; otherwise it returns {@code null}.
+ * (There can be at most one such mapping.)
+ *
+ * @throws ClassCastException if the specified key cannot be compared
+ * with the keys currently in the map
+ * @throws NullPointerException if the specified key is null
+ */
+ public V get(Object key) {
+ return doGet(key);
+ }
+
+ /**
+ * Associates the specified value with the specified key in this map.
+ * If the map previously contained a mapping for the key, the old
+ * value is replaced.
+ *
+ * @param key key with which the specified value is to be associated
+ * @param value value to be associated with the specified key
+ * @return the previous value associated with the specified key, or
+ * <tt>null</tt> if there was no mapping for the key
+ * @throws ClassCastException if the specified key cannot be compared
+ * with the keys currently in the map
+ * @throws NullPointerException if the specified key or value is null
+ */
+ public V put(K key, V value) {
+ if (value == null)
+ throw new NullPointerException();
+ return doPut(key, value, false);
+ }
+
+ /**
+ * Removes the mapping for the specified key from this map if present.
+ *
+ * @param key key for which mapping should be removed
+ * @return the previous value associated with the specified key, or
+ * <tt>null</tt> if there was no mapping for the key
+ * @throws ClassCastException if the specified key cannot be compared
+ * with the keys currently in the map
+ * @throws NullPointerException if the specified key is null
+ */
+ public V remove(Object key) {
+ return doRemove(key, null);
+ }
+
+ /**
+ * Returns <tt>true</tt> if this map maps one or more keys to the
+ * specified value. This operation requires time linear in the
+ * map size.
+ *
+ * @param value value whose presence in this map is to be tested
+ * @return <tt>true</tt> if a mapping to <tt>value</tt> exists;
+ * <tt>false</tt> otherwise
+ * @throws NullPointerException if the specified value is null
+ */
+ public boolean containsValue(Object value) {
+ if (value == null)
+ throw new NullPointerException();
+ for (Node<K,V> n = findFirst(); n != null; n = n.next) {
+ V v = n.getValidValue();
+ if (v != null && value.equals(v))
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Returns the number of key-value mappings in this map. If this map
+ * contains more than <tt>Integer.MAX_VALUE</tt> elements, it
+ * 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 maps, determining the current
+ * number of elements requires traversing them all to count them.
+ * Additionally, it is possible for the size to change during
+ * execution of this method, in which case the returned result
+ * will be inaccurate. Thus, this method is typically not very
+ * useful in concurrent applications.
+ *
+ * @return the number of elements in this map
+ */
+ public int size() {
+ long count = 0;
+ for (Node<K,V> n = findFirst(); n != null; n = n.next) {
+ if (n.getValidValue() != null)
+ ++count;
+ }
+ return (count >= Integer.MAX_VALUE)? Integer.MAX_VALUE : (int)count;
+ }
+
+ /**
+ * Returns <tt>true</tt> if this map contains no key-value mappings.
+ * @return <tt>true</tt> if this map contains no key-value mappings
+ */
+ public boolean isEmpty() {
+ return findFirst() == null;
+ }
+
+ /**
+ * Removes all of the mappings from this map.
+ */
+ public void clear() {
+ initialize();
+ }
+
+ /* ---------------- View methods -------------- */
+
+ /*
+ * Note: Lazy initialization works for views because view classes
+ * are stateless/immutable so it doesn't matter wrt correctness if
+ * more than one is created (which will only rarely happen). Even
+ * so, the following idiom conservatively ensures that the method
+ * returns the one it created if it does so, not one created by
+ * another racing thread.
+ */
+
+ /**
+ * Returns a {@link NavigableSet} view of the keys contained in this map.
+ * The set's iterator returns the keys in ascending order.
+ * The set is backed by the map, so changes to the map are
+ * reflected in the set, and vice-versa. The set supports element
+ * removal, which removes the corresponding mapping from the map,
+ * via the {@code Iterator.remove}, {@code Set.remove},
+ * {@code removeAll}, {@code retainAll}, and {@code clear}
+ * operations. It does not support the {@code add} or {@code addAll}
+ * operations.
+ *
+ * <p>The view's {@code iterator} is a "weakly consistent" iterator
+ * that will never throw {@link ConcurrentModificationException},
+ * and guarantees to traverse elements as they existed upon
+ * construction of the iterator, and may (but is not guaranteed to)
+ * reflect any modifications subsequent to construction.
+ *
+ * <p>This method is equivalent to method {@code navigableKeySet}.
+ *
+ * @return a navigable set view of the keys in this map
+ */
+ public NavigableSet<K> keySet() {
+ KeySet ks = keySet;
+ return (ks != null) ? ks : (keySet = new KeySet(this));
+ }
+
+ public NavigableSet<K> navigableKeySet() {
+ KeySet ks = keySet;
+ return (ks != null) ? ks : (keySet = new KeySet(this));
+ }
+
+ /**
+ * Returns a {@link Collection} view of the values contained in this map.
+ * The collection's iterator returns the values in ascending order
+ * of the corresponding keys.
+ * The collection is backed by the map, so changes to the map are
+ * reflected in the collection, and vice-versa. The collection
+ * supports element removal, which removes the corresponding
+ * mapping from the map, via the <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.
+ *
+ * <p>The view's <tt>iterator</tt> is a "weakly consistent" iterator
+ * that will never throw {@link ConcurrentModificationException},
+ * and guarantees to traverse elements as they existed upon
+ * construction of the iterator, and may (but is not guaranteed to)
+ * reflect any modifications subsequent to construction.
+ */
+ public Collection<V> values() {
+ Values vs = values;
+ return (vs != null) ? vs : (values = new Values(this));
+ }
+
+ /**
+ * Returns a {@link Set} view of the mappings contained in this map.
+ * The set's iterator returns the entries in ascending key order.
+ * The set is backed by the map, so changes to the map are
+ * reflected in the set, and vice-versa. The set supports element
+ * removal, which removes the corresponding mapping from the map,
+ * via the <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.
+ *
+ * <p>The view's <tt>iterator</tt> is a "weakly consistent" iterator
+ * that will never throw {@link ConcurrentModificationException},
+ * and guarantees to traverse elements as they existed upon
+ * construction of the iterator, and may (but is not guaranteed to)
+ * reflect any modifications subsequent to construction.
+ *
+ * <p>The <tt>Map.Entry</tt> elements returned by
+ * <tt>iterator.next()</tt> do <em>not</em> support the
+ * <tt>setValue</tt> operation.
+ *
+ * @return a set view of the mappings contained in this map,
+ * sorted in ascending key order
+ */
+ public Set<Map.Entry<K,V>> entrySet() {
+ EntrySet es = entrySet;
+ return (es != null) ? es : (entrySet = new EntrySet(this));
+ }
+
+ public ConcurrentNavigableMap<K,V> descendingMap() {
+ ConcurrentNavigableMap<K,V> dm = descendingMap;
+ return (dm != null) ? dm : (descendingMap = new SubMap<K,V>
+ (this, null, false, null, false, true));
+ }
+
+ public NavigableSet<K> descendingKeySet() {
+ return descendingMap().navigableKeySet();
+ }
+
+ /* ---------------- AbstractMap Overrides -------------- */
+
+ /**
+ * Compares the specified object with this map for equality.
+ * Returns <tt>true</tt> if the given object is also a map and the
+ * two maps represent the same mappings. More formally, two maps
+ * <tt>m1</tt> and <tt>m2</tt> represent the same mappings if
+ * <tt>m1.entrySet().equals(m2.entrySet())</tt>. This
+ * operation may return misleading results if either map is
+ * concurrently modified during execution of this method.
+ *
+ * @param o object to be compared for equality with this map
+ * @return <tt>true</tt> if the specified object is equal to this map
+ */
+ public boolean equals(Object o) {
+ if (o == this)
+ return true;
+ if (!(o instanceof Map))
+ return false;
+ Map<?,?> m = (Map<?,?>) o;
+ try {
+ for (Map.Entry<K,V> e : this.entrySet())
+ if (! e.getValue().equals(m.get(e.getKey())))
+ return false;
+ for (Map.Entry<?,?> e : m.entrySet()) {
+ Object k = e.getKey();
+ Object v = e.getValue();
+ if (k == null || v == null || !v.equals(get(k)))
+ return false;
+ }
+ return true;
+ } catch (ClassCastException unused) {
+ return false;
+ } catch (NullPointerException unused) {
+ return false;
+ }
+ }
+
+ /* ------ ConcurrentMap API methods ------ */
+
+ /**
+ * {@inheritDoc}
+ *
+ * @return the previous value associated with the specified key,
+ * or <tt>null</tt> if there was no mapping for the key
+ * @throws ClassCastException if the specified key cannot be compared
+ * with the keys currently in the map
+ * @throws NullPointerException if the specified key or value is null
+ */
+ public V putIfAbsent(K key, V value) {
+ if (value == null)
+ throw new NullPointerException();
+ return doPut(key, value, true);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @throws ClassCastException if the specified key cannot be compared
+ * with the keys currently in the map
+ * @throws NullPointerException if the specified key is null
+ */
+ public boolean remove(Object key, Object value) {
+ if (key == null)
+ throw new NullPointerException();
+ if (value == null)
+ return false;
+ return doRemove(key, value) != null;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @throws ClassCastException if the specified key cannot be compared
+ * with the keys currently in the map
+ * @throws NullPointerException if any of the arguments are null
+ */
+ public boolean replace(K key, V oldValue, V newValue) {
+ if (oldValue == null || newValue == null)
+ throw new NullPointerException();
+ Comparable<? super K> k = comparable(key);
+ for (;;) {
+ Node<K,V> n = findNode(k);
+ if (n == null)
+ return false;
+ Object v = n.value;
+ if (v != null) {
+ if (!oldValue.equals(v))
+ return false;
+ if (n.casValue(v, newValue))
+ return true;
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @return the previous value associated with the specified key,
+ * or <tt>null</tt> if there was no mapping for the key
+ * @throws ClassCastException if the specified key cannot be compared
+ * with the keys currently in the map
+ * @throws NullPointerException if the specified key or value is null
+ */
+ public V replace(K key, V value) {
+ if (value == null)
+ throw new NullPointerException();
+ Comparable<? super K> k = comparable(key);
+ for (;;) {
+ Node<K,V> n = findNode(k);
+ if (n == null)
+ return null;
+ Object v = n.value;
+ if (v != null && n.casValue(v, value))
+ return (V)v;
+ }
+ }
+
+ /* ------ SortedMap API methods ------ */
+
+ public Comparator<? super K> comparator() {
+ return comparator;
+ }
+
+ /**
+ * @throws NoSuchElementException {@inheritDoc}
+ */
+ public K firstKey() {
+ Node<K,V> n = findFirst();
+ if (n == null)
+ throw new NoSuchElementException();
+ return n.key;
+ }
+
+ /**
+ * @throws NoSuchElementException {@inheritDoc}
+ */
+ public K lastKey() {
+ Node<K,V> n = findLast();
+ if (n == null)
+ throw new NoSuchElementException();
+ return n.key;
+ }
+
+ /**
+ * @throws ClassCastException {@inheritDoc}
+ * @throws NullPointerException if {@code fromKey} or {@code toKey} is null
+ * @throws IllegalArgumentException {@inheritDoc}
+ */
+ public ConcurrentNavigableMap<K,V> subMap(K fromKey,
+ boolean fromInclusive,
+ K toKey,
+ boolean toInclusive) {
+ if (fromKey == null || toKey == null)
+ throw new NullPointerException();
+ return new SubMap<K,V>
+ (this, fromKey, fromInclusive, toKey, toInclusive, false);
+ }
+
+ /**
+ * @throws ClassCastException {@inheritDoc}
+ * @throws NullPointerException if {@code toKey} is null
+ * @throws IllegalArgumentException {@inheritDoc}
+ */
+ public ConcurrentNavigableMap<K,V> headMap(K toKey,
+ boolean inclusive) {
+ if (toKey == null)
+ throw new NullPointerException();
+ return new SubMap<K,V>
+ (this, null, false, toKey, inclusive, false);
+ }
+
+ /**
+ * @throws ClassCastException {@inheritDoc}
+ * @throws NullPointerException if {@code fromKey} is null
+ * @throws IllegalArgumentException {@inheritDoc}
+ */
+ public ConcurrentNavigableMap<K,V> tailMap(K fromKey,
+ boolean inclusive) {
+ if (fromKey == null)
+ throw new NullPointerException();
+ return new SubMap<K,V>
+ (this, fromKey, inclusive, null, false, false);
+ }
+
+ /**
+ * @throws ClassCastException {@inheritDoc}
+ * @throws NullPointerException if {@code fromKey} or {@code toKey} is null
+ * @throws IllegalArgumentException {@inheritDoc}
+ */
+ public ConcurrentNavigableMap<K,V> subMap(K fromKey, K toKey) {
+ return subMap(fromKey, true, toKey, false);
+ }
+
+ /**
+ * @throws ClassCastException {@inheritDoc}
+ * @throws NullPointerException if {@code toKey} is null
+ * @throws IllegalArgumentException {@inheritDoc}
+ */
+ public ConcurrentNavigableMap<K,V> headMap(K toKey) {
+ return headMap(toKey, false);
+ }
+
+ /**
+ * @throws ClassCastException {@inheritDoc}
+ * @throws NullPointerException if {@code fromKey} is null
+ * @throws IllegalArgumentException {@inheritDoc}
+ */
+ public ConcurrentNavigableMap<K,V> tailMap(K fromKey) {
+ return tailMap(fromKey, true);
+ }
+
+ /* ---------------- Relational operations -------------- */
+
+ /**
+ * Returns a key-value mapping associated with the greatest key
+ * strictly less than the given key, or <tt>null</tt> if there is
+ * no such key. The returned entry does <em>not</em> support the
+ * <tt>Entry.setValue</tt> method.
+ *
+ * @throws ClassCastException {@inheritDoc}
+ * @throws NullPointerException if the specified key is null
+ */
+ public Map.Entry<K,V> lowerEntry(K key) {
+ return getNear(key, LT);
+ }
+
+ /**
+ * @throws ClassCastException {@inheritDoc}
+ * @throws NullPointerException if the specified key is null
+ */
+ public K lowerKey(K key) {
+ Node<K,V> n = findNear(key, LT);
+ return (n == null)? null : n.key;
+ }
+
+ /**
+ * Returns a key-value mapping associated with the greatest key
+ * less than or equal to the given key, or <tt>null</tt> if there
+ * is no such key. The returned entry does <em>not</em> support
+ * the <tt>Entry.setValue</tt> method.
+ *
+ * @param key the key
+ * @throws ClassCastException {@inheritDoc}
+ * @throws NullPointerException if the specified key is null
+ */
+ public Map.Entry<K,V> floorEntry(K key) {
+ return getNear(key, LT|EQ);
+ }
+
+ /**
+ * @param key the key
+ * @throws ClassCastException {@inheritDoc}
+ * @throws NullPointerException if the specified key is null
+ */
+ public K floorKey(K key) {
+ Node<K,V> n = findNear(key, LT|EQ);
+ return (n == null)? null : n.key;
+ }
+
+ /**
+ * Returns a key-value mapping associated with the least key
+ * greater than or equal to the given key, or <tt>null</tt> if
+ * there is no such entry. The returned entry does <em>not</em>
+ * support the <tt>Entry.setValue</tt> method.
+ *
+ * @throws ClassCastException {@inheritDoc}
+ * @throws NullPointerException if the specified key is null
+ */
+ public Map.Entry<K,V> ceilingEntry(K key) {
+ return getNear(key, GT|EQ);
+ }
+
+ /**
+ * @throws ClassCastException {@inheritDoc}
+ * @throws NullPointerException if the specified key is null
+ */
+ public K ceilingKey(K key) {
+ Node<K,V> n = findNear(key, GT|EQ);
+ return (n == null)? null : n.key;
+ }
+
+ /**
+ * Returns a key-value mapping associated with the least key
+ * strictly greater than the given key, or <tt>null</tt> if there
+ * is no such key. The returned entry does <em>not</em> support
+ * the <tt>Entry.setValue</tt> method.
+ *
+ * @param key the key
+ * @throws ClassCastException {@inheritDoc}
+ * @throws NullPointerException if the specified key is null
+ */
+ public Map.Entry<K,V> higherEntry(K key) {
+ return getNear(key, GT);
+ }
+
+ /**
+ * @param key the key
+ * @throws ClassCastException {@inheritDoc}
+ * @throws NullPointerException if the specified key is null
+ */
+ public K higherKey(K key) {
+ Node<K,V> n = findNear(key, GT);
+ return (n == null)? null : n.key;
+ }
+
+ /**
+ * Returns a key-value mapping associated with the least
+ * key in this map, or <tt>null</tt> if the map is empty.
+ * The returned entry does <em>not</em> support
+ * the <tt>Entry.setValue</tt> method.
+ */
+ public Map.Entry<K,V> firstEntry() {
+ for (;;) {
+ Node<K,V> n = findFirst();
+ if (n == null)
+ return null;
+ AbstractMap.SimpleImmutableEntry<K,V> e = n.createSnapshot();
+ if (e != null)
+ return e;
+ }
+ }
+
+ /**
+ * Returns a key-value mapping associated with the greatest
+ * key in this map, or <tt>null</tt> if the map is empty.
+ * The returned entry does <em>not</em> support
+ * the <tt>Entry.setValue</tt> method.
+ */
+ public Map.Entry<K,V> lastEntry() {
+ for (;;) {
+ Node<K,V> n = findLast();
+ if (n == null)
+ return null;
+ AbstractMap.SimpleImmutableEntry<K,V> e = n.createSnapshot();
+ if (e != null)
+ return e;
+ }
+ }
+
+ /**
+ * Removes and returns a key-value mapping associated with
+ * the least key in this map, or <tt>null</tt> if the map is empty.
+ * The returned entry does <em>not</em> support
+ * the <tt>Entry.setValue</tt> method.
+ */
+ public Map.Entry<K,V> pollFirstEntry() {
+ return doRemoveFirstEntry();
+ }
+
+ /**
+ * Removes and returns a key-value mapping associated with
+ * the greatest key in this map, or <tt>null</tt> if the map is empty.
+ * The returned entry does <em>not</em> support
+ * the <tt>Entry.setValue</tt> method.
+ */
+ public Map.Entry<K,V> pollLastEntry() {
+ return doRemoveLastEntry();
+ }
+
+
+ /* ---------------- Iterators -------------- */
+
+ /**
+ * Base of iterator classes:
+ */
+ abstract class Iter<T> implements Iterator<T> {
+ /** the last node returned by next() */
+ Node<K,V> lastReturned;
+ /** the next node to return from next(); */
+ Node<K,V> next;
+ /** Cache of next value field to maintain weak consistency */
+ V nextValue;
+
+ /** Initializes ascending iterator for entire range. */
+ Iter() {
+ for (;;) {
+ next = findFirst();
+ if (next == null)
+ break;
+ Object x = next.value;
+ if (x != null && x != next) {
+ nextValue = (V) x;
+ break;
+ }
+ }
+ }
+
+ public final boolean hasNext() {
+ return next != null;
+ }
+
+ /** Advances next to higher entry. */
+ final void advance() {
+ if (next == null)
+ throw new NoSuchElementException();
+ lastReturned = next;
+ for (;;) {
+ next = next.next;
+ if (next == null)
+ break;
+ Object x = next.value;
+ if (x != null && x != next) {
+ nextValue = (V) x;
+ break;
+ }
+ }
+ }
+
+ public void remove() {
+ Node<K,V> l = lastReturned;
+ if (l == null)
+ throw new IllegalStateException();
+ // It would not be worth all of the overhead to directly
+ // unlink from here. Using remove is fast enough.
+ ConcurrentSkipListMap.this.remove(l.key);
+ lastReturned = null;
+ }
+
+ }
+
+ final class ValueIterator extends Iter<V> {
+ public V next() {
+ V v = nextValue;
+ advance();
+ return v;
+ }
+ }
+
+ final class KeyIterator extends Iter<K> {
+ public K next() {
+ Node<K,V> n = next;
+ advance();
+ return n.key;
+ }
+ }
+
+ final class EntryIterator extends Iter<Map.Entry<K,V>> {
+ public Map.Entry<K,V> next() {
+ Node<K,V> n = next;
+ V v = nextValue;
+ advance();
+ return new AbstractMap.SimpleImmutableEntry<K,V>(n.key, v);
+ }
+ }
+
+ // Factory methods for iterators needed by ConcurrentSkipListSet etc
+
+ Iterator<K> keyIterator() {
+ return new KeyIterator();
+ }
+
+ Iterator<V> valueIterator() {
+ return new ValueIterator();
+ }
+
+ Iterator<Map.Entry<K,V>> entryIterator() {
+ return new EntryIterator();
+ }
+
+ /* ---------------- View Classes -------------- */
+
+ /*
+ * View classes are static, delegating to a ConcurrentNavigableMap
+ * to allow use by SubMaps, which outweighs the ugliness of
+ * needing type-tests for Iterator methods.
+ */
+
+ static final <E> List<E> toList(Collection<E> c) {
+ // Using size() here would be a pessimization.
+ List<E> list = new ArrayList<E>();
+ for (E e : c)
+ list.add(e);
+ return list;
+ }
+
+ static final class KeySet<E> extends AbstractSet<E> implements NavigableSet<E> {
+ private final ConcurrentNavigableMap<E,Object> m;
+ KeySet(ConcurrentNavigableMap<E,Object> map) { m = map; }
+ public int size() { return m.size(); }
+ public boolean isEmpty() { return m.isEmpty(); }
+ public boolean contains(Object o) { return m.containsKey(o); }
+ public boolean remove(Object o) { return m.remove(o) != null; }
+ public void clear() { m.clear(); }
+ public E lower(E e) { return m.lowerKey(e); }
+ public E floor(E e) { return m.floorKey(e); }
+ public E ceiling(E e) { return m.ceilingKey(e); }
+ public E higher(E e) { return m.higherKey(e); }
+ public Comparator<? super E> comparator() { return m.comparator(); }
+ public E first() { return m.firstKey(); }
+ public E last() { return m.lastKey(); }
+ public E pollFirst() {
+ Map.Entry<E,Object> e = m.pollFirstEntry();
+ return e == null? null : e.getKey();
+ }
+ public E pollLast() {
+ Map.Entry<E,Object> e = m.pollLastEntry();
+ return e == null? null : e.getKey();
+ }
+ public Iterator<E> iterator() {
+ if (m instanceof ConcurrentSkipListMap)
+ return ((ConcurrentSkipListMap<E,Object>)m).keyIterator();
+ else
+ return ((ConcurrentSkipListMap.SubMap<E,Object>)m).keyIterator();
+ }
+ public boolean equals(Object o) {
+ if (o == this)
+ return true;
+ if (!(o instanceof Set))
+ return false;
+ Collection<?> c = (Collection<?>) o;
+ try {
+ return containsAll(c) && c.containsAll(this);
+ } catch (ClassCastException unused) {
+ return false;
+ } catch (NullPointerException unused) {
+ return false;
+ }
+ }
+ public Object[] toArray() { return toList(this).toArray(); }
+ public <T> T[] toArray(T[] a) { return toList(this).toArray(a); }
+ public Iterator<E> descendingIterator() {
+ return descendingSet().iterator();
+ }
+ public NavigableSet<E> subSet(E fromElement,
+ boolean fromInclusive,
+ E toElement,
+ boolean toInclusive) {
+ return new KeySet<E>(m.subMap(fromElement, fromInclusive,
+ toElement, toInclusive));
+ }
+ public NavigableSet<E> headSet(E toElement, boolean inclusive) {
+ return new KeySet<E>(m.headMap(toElement, inclusive));
+ }
+ public NavigableSet<E> tailSet(E fromElement, boolean inclusive) {
+ return new KeySet<E>(m.tailMap(fromElement, inclusive));
+ }
+ public NavigableSet<E> subSet(E fromElement, E toElement) {
+ return subSet(fromElement, true, toElement, false);
+ }
+ public NavigableSet<E> headSet(E toElement) {
+ return headSet(toElement, false);
+ }
+ public NavigableSet<E> tailSet(E fromElement) {
+ return tailSet(fromElement, true);
+ }
+ public NavigableSet<E> descendingSet() {
+ return new KeySet(m.descendingMap());
+ }
+ }
+
+ static final class Values<E> extends AbstractCollection<E> {
+ private final ConcurrentNavigableMap<Object, E> m;
+ Values(ConcurrentNavigableMap<Object, E> map) {
+ m = map;
+ }
+ public Iterator<E> iterator() {
+ if (m instanceof ConcurrentSkipListMap)
+ return ((ConcurrentSkipListMap<Object,E>)m).valueIterator();
+ else
+ return ((SubMap<Object,E>)m).valueIterator();
+ }
+ public boolean isEmpty() {
+ return m.isEmpty();
+ }
+ public int size() {
+ return m.size();
+ }
+ public boolean contains(Object o) {
+ return m.containsValue(o);
+ }
+ public void clear() {
+ m.clear();
+ }
+ public Object[] toArray() { return toList(this).toArray(); }
+ public <T> T[] toArray(T[] a) { return toList(this).toArray(a); }
+ }
+
+ static final class EntrySet<K1,V1> extends AbstractSet<Map.Entry<K1,V1>> {
+ private final ConcurrentNavigableMap<K1, V1> m;
+ EntrySet(ConcurrentNavigableMap<K1, V1> map) {
+ m = map;
+ }
+
+ public Iterator<Map.Entry<K1,V1>> iterator() {
+ if (m instanceof ConcurrentSkipListMap)
+ return ((ConcurrentSkipListMap<K1,V1>)m).entryIterator();
+ else
+ return ((SubMap<K1,V1>)m).entryIterator();
+ }
+
+ public boolean contains(Object o) {
+ if (!(o instanceof Map.Entry))
+ return false;
+ Map.Entry<K1,V1> e = (Map.Entry<K1,V1>)o;
+ V1 v = m.get(e.getKey());
+ return v != null && v.equals(e.getValue());
+ }
+ public boolean remove(Object o) {
+ if (!(o instanceof Map.Entry))
+ return false;
+ Map.Entry<K1,V1> e = (Map.Entry<K1,V1>)o;
+ return m.remove(e.getKey(),
+ e.getValue());
+ }
+ public boolean isEmpty() {
+ return m.isEmpty();
+ }
+ public int size() {
+ return m.size();
+ }
+ public void clear() {
+ m.clear();
+ }
+ public boolean equals(Object o) {
+ if (o == this)
+ return true;
+ if (!(o instanceof Set))
+ return false;
+ Collection<?> c = (Collection<?>) o;
+ try {
+ return containsAll(c) && c.containsAll(this);
+ } catch (ClassCastException unused) {
+ return false;
+ } catch (NullPointerException unused) {
+ return false;
+ }
+ }
+ public Object[] toArray() { return toList(this).toArray(); }
+ public <T> T[] toArray(T[] a) { return toList(this).toArray(a); }
+ }
+
+ /**
+ * Submaps returned by {@link ConcurrentSkipListMap} submap operations
+ * represent a subrange of mappings of their underlying
+ * maps. Instances of this class support all methods of their
+ * underlying maps, differing in that mappings outside their range are
+ * ignored, and attempts to add mappings outside their ranges result
+ * in {@link IllegalArgumentException}. Instances of this class are
+ * constructed only using the <tt>subMap</tt>, <tt>headMap</tt>, and
+ * <tt>tailMap</tt> methods of their underlying maps.
+ *
+ * @serial include
+ */
+ static final class SubMap<K,V> extends AbstractMap<K,V>
+ implements ConcurrentNavigableMap<K,V>, Cloneable,
+ java.io.Serializable {
+ private static final long serialVersionUID = -7647078645895051609L;
+
+ /** Underlying map */
+ private final ConcurrentSkipListMap<K,V> m;
+ /** lower bound key, or null if from start */
+ private final K lo;
+ /** upper bound key, or null if to end */
+ private final K hi;
+ /** inclusion flag for lo */
+ private final boolean loInclusive;
+ /** inclusion flag for hi */
+ private final boolean hiInclusive;
+ /** direction */
+ private final boolean isDescending;
+
+ // Lazily initialized view holders
+ private transient KeySet<K> keySetView;
+ private transient Set<Map.Entry<K,V>> entrySetView;
+ private transient Collection<V> valuesView;
+
+ /**
+ * Creates a new submap, initializing all fields
+ */
+ SubMap(ConcurrentSkipListMap<K,V> map,
+ K fromKey, boolean fromInclusive,
+ K toKey, boolean toInclusive,
+ boolean isDescending) {
+ if (fromKey != null && toKey != null &&
+ map.compare(fromKey, toKey) > 0)
+ throw new IllegalArgumentException("inconsistent range");
+ this.m = map;
+ this.lo = fromKey;
+ this.hi = toKey;
+ this.loInclusive = fromInclusive;
+ this.hiInclusive = toInclusive;
+ this.isDescending = isDescending;
+ }
+
+ /* ---------------- Utilities -------------- */
+
+ private boolean tooLow(K key) {
+ if (lo != null) {
+ int c = m.compare(key, lo);
+ if (c < 0 || (c == 0 && !loInclusive))
+ return true;
+ }
+ return false;
+ }
+
+ private boolean tooHigh(K key) {
+ if (hi != null) {
+ int c = m.compare(key, hi);
+ if (c > 0 || (c == 0 && !hiInclusive))
+ return true;
+ }
+ return false;
+ }
+
+ private boolean inBounds(K key) {
+ return !tooLow(key) && !tooHigh(key);
+ }
+
+ private void checkKeyBounds(K key) throws IllegalArgumentException {
+ if (key == null)
+ throw new NullPointerException();
+ if (!inBounds(key))
+ throw new IllegalArgumentException("key out of range");
+ }
+
+ /**
+ * Returns true if node key is less than upper bound of range
+ */
+ private boolean isBeforeEnd(ConcurrentSkipListMap.Node<K,V> n) {
+ if (n == null)
+ return false;
+ if (hi == null)
+ return true;
+ K k = n.key;
+ if (k == null) // pass by markers and headers
+ return true;
+ int c = m.compare(k, hi);
+ if (c > 0 || (c == 0 && !hiInclusive))
+ return false;
+ return true;
+ }
+
+ /**
+ * Returns lowest node. This node might not be in range, so
+ * most usages need to check bounds
+ */
+ private ConcurrentSkipListMap.Node<K,V> loNode() {
+ if (lo == null)
+ return m.findFirst();
+ else if (loInclusive)
+ return m.findNear(lo, m.GT|m.EQ);
+ else
+ return m.findNear(lo, m.GT);
+ }
+
+ /**
+ * Returns highest node. This node might not be in range, so
+ * most usages need to check bounds
+ */
+ private ConcurrentSkipListMap.Node<K,V> hiNode() {
+ if (hi == null)
+ return m.findLast();
+ else if (hiInclusive)
+ return m.findNear(hi, m.LT|m.EQ);
+ else
+ return m.findNear(hi, m.LT);
+ }
+
+ /**
+ * Returns lowest absolute key (ignoring directonality)
+ */
+ private K lowestKey() {
+ ConcurrentSkipListMap.Node<K,V> n = loNode();
+ if (isBeforeEnd(n))
+ return n.key;
+ else
+ throw new NoSuchElementException();
+ }
+
+ /**
+ * Returns highest absolute key (ignoring directonality)
+ */
+ private K highestKey() {
+ ConcurrentSkipListMap.Node<K,V> n = hiNode();
+ if (n != null) {
+ K last = n.key;
+ if (inBounds(last))
+ return last;
+ }
+ throw new NoSuchElementException();
+ }
+
+ private Map.Entry<K,V> lowestEntry() {
+ for (;;) {
+ ConcurrentSkipListMap.Node<K,V> n = loNode();
+ if (!isBeforeEnd(n))
+ return null;
+ Map.Entry<K,V> e = n.createSnapshot();
+ if (e != null)
+ return e;
+ }
+ }
+
+ private Map.Entry<K,V> highestEntry() {
+ for (;;) {
+ ConcurrentSkipListMap.Node<K,V> n = hiNode();
+ if (n == null || !inBounds(n.key))
+ return null;
+ Map.Entry<K,V> e = n.createSnapshot();
+ if (e != null)
+ return e;
+ }
+ }
+
+ private Map.Entry<K,V> removeLowest() {
+ for (;;) {
+ Node<K,V> n = loNode();
+ if (n == null)
+ return null;
+ K k = n.key;
+ if (!inBounds(k))
+ return null;
+ V v = m.doRemove(k, null);
+ if (v != null)
+ return new AbstractMap.SimpleImmutableEntry<K,V>(k, v);
+ }
+ }
+
+ private Map.Entry<K,V> removeHighest() {
+ for (;;) {
+ Node<K,V> n = hiNode();
+ if (n == null)
+ return null;
+ K k = n.key;
+ if (!inBounds(k))
+ return null;
+ V v = m.doRemove(k, null);
+ if (v != null)
+ return new AbstractMap.SimpleImmutableEntry<K,V>(k, v);
+ }
+ }
+
+ /**
+ * Submap version of ConcurrentSkipListMap.getNearEntry
+ */
+ private Map.Entry<K,V> getNearEntry(K key, int rel) {
+ if (isDescending) { // adjust relation for direction
+ if ((rel & m.LT) == 0)
+ rel |= m.LT;
+ else
+ rel &= ~m.LT;
+ }
+ if (tooLow(key))
+ return ((rel & m.LT) != 0)? null : lowestEntry();
+ if (tooHigh(key))
+ return ((rel & m.LT) != 0)? highestEntry() : null;
+ for (;;) {
+ Node<K,V> n = m.findNear(key, rel);
+ if (n == null || !inBounds(n.key))
+ return null;
+ K k = n.key;
+ V v = n.getValidValue();
+ if (v != null)
+ return new AbstractMap.SimpleImmutableEntry<K,V>(k, v);
+ }
+ }
+
+ // Almost the same as getNearEntry, except for keys
+ private K getNearKey(K key, int rel) {
+ if (isDescending) { // adjust relation for direction
+ if ((rel & m.LT) == 0)
+ rel |= m.LT;
+ else
+ rel &= ~m.LT;
+ }
+ if (tooLow(key)) {
+ if ((rel & m.LT) == 0) {
+ ConcurrentSkipListMap.Node<K,V> n = loNode();
+ if (isBeforeEnd(n))
+ return n.key;
+ }
+ return null;
+ }
+ if (tooHigh(key)) {
+ if ((rel & m.LT) != 0) {
+ ConcurrentSkipListMap.Node<K,V> n = hiNode();
+ if (n != null) {
+ K last = n.key;
+ if (inBounds(last))
+ return last;
+ }
+ }
+ return null;
+ }
+ for (;;) {
+ Node<K,V> n = m.findNear(key, rel);
+ if (n == null || !inBounds(n.key))
+ return null;
+ K k = n.key;
+ V v = n.getValidValue();
+ if (v != null)
+ return k;
+ }
+ }
+
+ /* ---------------- Map API methods -------------- */
+
+ public boolean containsKey(Object key) {
+ if (key == null) throw new NullPointerException();
+ K k = (K)key;
+ return inBounds(k) && m.containsKey(k);
+ }
+
+ public V get(Object key) {
+ if (key == null) throw new NullPointerException();
+ K k = (K)key;
+ return ((!inBounds(k)) ? null : m.get(k));
+ }
+
+ public V put(K key, V value) {
+ checkKeyBounds(key);
+ return m.put(key, value);
+ }
+
+ public V remove(Object key) {
+ K k = (K)key;
+ return (!inBounds(k))? null : m.remove(k);
+ }
+
+ public int size() {
+ long count = 0;
+ for (ConcurrentSkipListMap.Node<K,V> n = loNode();
+ isBeforeEnd(n);
+ n = n.next) {
+ if (n.getValidValue() != null)
+ ++count;
+ }
+ return count >= Integer.MAX_VALUE? Integer.MAX_VALUE : (int)count;
+ }
+
+ public boolean isEmpty() {
+ return !isBeforeEnd(loNode());
+ }
+
+ public boolean containsValue(Object value) {
+ if (value == null)
+ throw new NullPointerException();
+ for (ConcurrentSkipListMap.Node<K,V> n = loNode();
+ isBeforeEnd(n);
+ n = n.next) {
+ V v = n.getValidValue();
+ if (v != null && value.equals(v))
+ return true;
+ }
+ return false;
+ }
+
+ public void clear() {
+ for (ConcurrentSkipListMap.Node<K,V> n = loNode();
+ isBeforeEnd(n);
+ n = n.next) {
+ if (n.getValidValue() != null)
+ m.remove(n.key);
+ }
+ }
+
+ /* ---------------- ConcurrentMap API methods -------------- */
+
+ public V putIfAbsent(K key, V value) {
+ checkKeyBounds(key);
+ return m.putIfAbsent(key, value);
+ }
+
+ public boolean remove(Object key, Object value) {
+ K k = (K)key;
+ return inBounds(k) && m.remove(k, value);
+ }
+
+ public boolean replace(K key, V oldValue, V newValue) {
+ checkKeyBounds(key);
+ return m.replace(key, oldValue, newValue);
+ }
+
+ public V replace(K key, V value) {
+ checkKeyBounds(key);
+ return m.replace(key, value);
+ }
+
+ /* ---------------- SortedMap API methods -------------- */
+
+ public Comparator<? super K> comparator() {
+ Comparator<? super K> cmp = m.comparator();
+ if (isDescending)
+ return Collections.reverseOrder(cmp);
+ else
+ return cmp;
+ }
+
+ /**
+ * Utility to create submaps, where given bounds override
+ * unbounded(null) ones and/or are checked against bounded ones.
+ */
+ private SubMap<K,V> newSubMap(K fromKey,
+ boolean fromInclusive,
+ K toKey,
+ boolean toInclusive) {
+ if (isDescending) { // flip senses
+ K tk = fromKey;
+ fromKey = toKey;
+ toKey = tk;
+ boolean ti = fromInclusive;
+ fromInclusive = toInclusive;
+ toInclusive = ti;
+ }
+ if (lo != null) {
+ if (fromKey == null) {
+ fromKey = lo;
+ fromInclusive = loInclusive;
+ }
+ else {
+ int c = m.compare(fromKey, lo);
+ if (c < 0 || (c == 0 && !loInclusive && fromInclusive))
+ throw new IllegalArgumentException("key out of range");
+ }
+ }
+ if (hi != null) {
+ if (toKey == null) {
+ toKey = hi;
+ toInclusive = hiInclusive;
+ }
+ else {
+ int c = m.compare(toKey, hi);
+ if (c > 0 || (c == 0 && !hiInclusive && toInclusive))
+ throw new IllegalArgumentException("key out of range");
+ }
+ }
+ return new SubMap<K,V>(m, fromKey, fromInclusive,
+ toKey, toInclusive, isDescending);
+ }
+
+ public SubMap<K,V> subMap(K fromKey,
+ boolean fromInclusive,
+ K toKey,
+ boolean toInclusive) {
+ if (fromKey == null || toKey == null)
+ throw new NullPointerException();
+ return newSubMap(fromKey, fromInclusive, toKey, toInclusive);
+ }
+
+ public SubMap<K,V> headMap(K toKey,
+ boolean inclusive) {
+ if (toKey == null)
+ throw new NullPointerException();
+ return newSubMap(null, false, toKey, inclusive);
+ }
+
+ public SubMap<K,V> tailMap(K fromKey,
+ boolean inclusive) {
+ if (fromKey == null)
+ throw new NullPointerException();
+ return newSubMap(fromKey, inclusive, null, false);
+ }
+
+ public SubMap<K,V> subMap(K fromKey, K toKey) {
+ return subMap(fromKey, true, toKey, false);
+ }
+
+ public SubMap<K,V> headMap(K toKey) {
+ return headMap(toKey, false);
+ }
+
+ public SubMap<K,V> tailMap(K fromKey) {
+ return tailMap(fromKey, true);
+ }
+
+ public SubMap<K,V> descendingMap() {
+ return new SubMap<K,V>(m, lo, loInclusive,
+ hi, hiInclusive, !isDescending);
+ }
+
+ /* ---------------- Relational methods -------------- */
+
+ public Map.Entry<K,V> ceilingEntry(K key) {
+ return getNearEntry(key, (m.GT|m.EQ));
+ }
+
+ public K ceilingKey(K key) {
+ return getNearKey(key, (m.GT|m.EQ));
+ }
+
+ public Map.Entry<K,V> lowerEntry(K key) {
+ return getNearEntry(key, (m.LT));
+ }
+
+ public K lowerKey(K key) {
+ return getNearKey(key, (m.LT));
+ }
+
+ public Map.Entry<K,V> floorEntry(K key) {
+ return getNearEntry(key, (m.LT|m.EQ));
+ }
+
+ public K floorKey(K key) {
+ return getNearKey(key, (m.LT|m.EQ));
+ }
+
+ public Map.Entry<K,V> higherEntry(K key) {
+ return getNearEntry(key, (m.GT));
+ }
+
+ public K higherKey(K key) {
+ return getNearKey(key, (m.GT));
+ }
+
+ public K firstKey() {
+ return isDescending? highestKey() : lowestKey();
+ }
+
+ public K lastKey() {
+ return isDescending? lowestKey() : highestKey();
+ }
+
+ public Map.Entry<K,V> firstEntry() {
+ return isDescending? highestEntry() : lowestEntry();
+ }
+
+ public Map.Entry<K,V> lastEntry() {
+ return isDescending? lowestEntry() : highestEntry();
+ }
+
+ public Map.Entry<K,V> pollFirstEntry() {
+ return isDescending? removeHighest() : removeLowest();
+ }
+
+ public Map.Entry<K,V> pollLastEntry() {
+ return isDescending? removeLowest() : removeHighest();
+ }
+
+ /* ---------------- Submap Views -------------- */
+
+ public NavigableSet<K> keySet() {
+ KeySet<K> ks = keySetView;
+ return (ks != null) ? ks : (keySetView = new KeySet(this));
+ }
+
+ public NavigableSet<K> navigableKeySet() {
+ KeySet<K> ks = keySetView;
+ return (ks != null) ? ks : (keySetView = new KeySet(this));
+ }
+
+ public Collection<V> values() {
+ Collection<V> vs = valuesView;
+ return (vs != null) ? vs : (valuesView = new Values(this));
+ }
+
+ public Set<Map.Entry<K,V>> entrySet() {
+ Set<Map.Entry<K,V>> es = entrySetView;
+ return (es != null) ? es : (entrySetView = new EntrySet(this));
+ }
+
+ public NavigableSet<K> descendingKeySet() {
+ return descendingMap().navigableKeySet();
+ }
+
+ Iterator<K> keyIterator() {
+ return new SubMapKeyIterator();
+ }
+
+ Iterator<V> valueIterator() {
+ return new SubMapValueIterator();
+ }
+
+ Iterator<Map.Entry<K,V>> entryIterator() {
+ return new SubMapEntryIterator();
+ }
+
+ /**
+ * Variant of main Iter class to traverse through submaps.
+ */
+ abstract class SubMapIter<T> implements Iterator<T> {
+ /** the last node returned by next() */
+ Node<K,V> lastReturned;
+ /** the next node to return from next(); */
+ Node<K,V> next;
+ /** Cache of next value field to maintain weak consistency */
+ V nextValue;
+
+ SubMapIter() {
+ for (;;) {
+ next = isDescending ? hiNode() : loNode();
+ if (next == null)
+ break;
+ Object x = next.value;
+ if (x != null && x != next) {
+ if (! inBounds(next.key))
+ next = null;
+ else
+ nextValue = (V) x;
+ break;
+ }
+ }
+ }
+
+ public final boolean hasNext() {
+ return next != null;
+ }
+
+ final void advance() {
+ if (next == null)
+ throw new NoSuchElementException();
+ lastReturned = next;
+ if (isDescending)
+ descend();
+ else
+ ascend();
+ }
+
+ private void ascend() {
+ for (;;) {
+ next = next.next;
+ if (next == null)
+ break;
+ Object x = next.value;
+ if (x != null && x != next) {
+ if (tooHigh(next.key))
+ next = null;
+ else
+ nextValue = (V) x;
+ break;
+ }
+ }
+ }
+
+ private void descend() {
+ for (;;) {
+ next = m.findNear(lastReturned.key, LT);
+ if (next == null)
+ break;
+ Object x = next.value;
+ if (x != null && x != next) {
+ if (tooLow(next.key))
+ next = null;
+ else
+ nextValue = (V) x;
+ break;
+ }
+ }
+ }
+
+ public void remove() {
+ Node<K,V> l = lastReturned;
+ if (l == null)
+ throw new IllegalStateException();
+ m.remove(l.key);
+ lastReturned = null;
+ }
+
+ }
+
+ final class SubMapValueIterator extends SubMapIter<V> {
+ public V next() {
+ V v = nextValue;
+ advance();
+ return v;
+ }
+ }
+
+ final class SubMapKeyIterator extends SubMapIter<K> {
+ public K next() {
+ Node<K,V> n = next;
+ advance();
+ return n.key;
+ }
+ }
+
+ final class SubMapEntryIterator extends SubMapIter<Map.Entry<K,V>> {
+ public Map.Entry<K,V> next() {
+ Node<K,V> n = next;
+ V v = nextValue;
+ advance();
+ return new AbstractMap.SimpleImmutableEntry<K,V>(n.key, v);
+ }
+ }
+ }
+}
diff --git a/concurrent/src/main/java/java/util/concurrent/ConcurrentSkipListSet.java b/concurrent/src/main/java/java/util/concurrent/ConcurrentSkipListSet.java
new file mode 100644
index 0000000..7fd1c76
--- /dev/null
+++ b/concurrent/src/main/java/java/util/concurrent/ConcurrentSkipListSet.java
@@ -0,0 +1,456 @@
+/*
+ * 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 sun.misc.Unsafe;
+
+/**
+ * A scalable concurrent {@link NavigableSet} implementation based on
+ * a {@link ConcurrentSkipListMap}. The elements of the set are kept
+ * sorted according to their {@linkplain Comparable natural ordering},
+ * or by a {@link Comparator} provided at set creation time, depending
+ * on which constructor is used.
+ *
+ * <p>This implementation provides expected average <i>log(n)</i> time
+ * cost for the <tt>contains</tt>, <tt>add</tt>, and <tt>remove</tt>
+ * operations and their variants. Insertion, removal, and access
+ * operations safely execute concurrently by multiple threads.
+ * Iterators are <i>weakly consistent</i>, returning elements
+ * reflecting the state of the set at some point at or since the
+ * creation of the iterator. They do <em>not</em> throw {@link
+ * ConcurrentModificationException}, and may proceed concurrently with
+ * other operations. Ascending ordered views and their iterators are
+ * faster than descending ones.
+ *
+ * <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 sets, determining the current number
+ * of elements requires a traversal of the elements. Additionally, the
+ * bulk operations <tt>addAll</tt>, <tt>removeAll</tt>,
+ * <tt>retainAll</tt>, and <tt>containsAll</tt> are <em>not</em>
+ * guaranteed to be performed atomically. For example, an iterator
+ * operating concurrently with an <tt>addAll</tt> operation might view
+ * only some of the added elements.
+ *
+ * <p>This class and its iterators implement all of the
+ * <em>optional</em> methods of the {@link Set} and {@link Iterator}
+ * interfaces. Like most other concurrent collection implementations,
+ * this class does not permit the use of <tt>null</tt> elements,
+ * because <tt>null</tt> arguments and return values cannot be reliably
+ * distinguished from the absence of elements.
+ *
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
+ * Java Collections Framework</a>.
+ *
+ * @author Doug Lea
+ * @param <E> the type of elements maintained by this set
+ * @since 1.6
+ */
+public class ConcurrentSkipListSet<E>
+ extends AbstractSet<E>
+ implements NavigableSet<E>, Cloneable, java.io.Serializable {
+
+ private static final long serialVersionUID = -2479143111061671589L;
+
+ /**
+ * The underlying map. Uses Boolean.TRUE as value for each
+ * element. This field is declared final for the sake of thread
+ * safety, which entails some ugliness in clone()
+ */
+ private final ConcurrentNavigableMap<E,Object> m;
+
+ /**
+ * Constructs a new, empty set that orders its elements according to
+ * their {@linkplain Comparable natural ordering}.
+ */
+ public ConcurrentSkipListSet() {
+ m = new ConcurrentSkipListMap<E,Object>();
+ }
+
+ /**
+ * Constructs a new, empty set that orders its elements according to
+ * the specified comparator.
+ *
+ * @param comparator the comparator that will be used to order this set.
+ * If <tt>null</tt>, the {@linkplain Comparable natural
+ * ordering} of the elements will be used.
+ */
+ public ConcurrentSkipListSet(Comparator<? super E> comparator) {
+ m = new ConcurrentSkipListMap<E,Object>(comparator);
+ }
+
+ /**
+ * Constructs a new set containing the elements in the specified
+ * collection, that orders its elements according to their
+ * {@linkplain Comparable natural ordering}.
+ *
+ * @param c The elements that will comprise the new set
+ * @throws ClassCastException if the elements in <tt>c</tt> are
+ * not {@link Comparable}, or are not mutually comparable
+ * @throws NullPointerException if the specified collection or any
+ * of its elements are null
+ */
+ public ConcurrentSkipListSet(Collection<? extends E> c) {
+ m = new ConcurrentSkipListMap<E,Object>();
+ addAll(c);
+ }
+
+ /**
+ * Constructs a new set containing the same elements and using the
+ * same ordering as the specified sorted set.
+ *
+ * @param s sorted set whose elements will comprise the new set
+ * @throws NullPointerException if the specified sorted set or any
+ * of its elements are null
+ */
+ public ConcurrentSkipListSet(SortedSet<E> s) {
+ m = new ConcurrentSkipListMap<E,Object>(s.comparator());
+ addAll(s);
+ }
+
+ /**
+ * For use by submaps
+ */
+ ConcurrentSkipListSet(ConcurrentNavigableMap<E,Object> m) {
+ this.m = m;
+ }
+
+ /**
+ * Returns a shallow copy of this <tt>ConcurrentSkipListSet</tt>
+ * instance. (The elements themselves are not cloned.)
+ *
+ * @return a shallow copy of this set
+ */
+ public ConcurrentSkipListSet<E> clone() {
+ ConcurrentSkipListSet<E> clone = null;
+ try {
+ clone = (ConcurrentSkipListSet<E>) super.clone();
+ clone.setMap(new ConcurrentSkipListMap(m));
+ } catch (CloneNotSupportedException e) {
+ throw new InternalError();
+ }
+
+ return clone;
+ }
+
+ /* ---------------- Set operations -------------- */
+
+ /**
+ * Returns the number of elements in this set. If this set
+ * contains more than <tt>Integer.MAX_VALUE</tt> elements, it
+ * 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 sets, determining the current
+ * number of elements requires traversing them all to count them.
+ * Additionally, it is possible for the size to change during
+ * execution of this method, in which case the returned result
+ * will be inaccurate. Thus, this method is typically not very
+ * useful in concurrent applications.
+ *
+ * @return the number of elements in this set
+ */
+ public int size() {
+ return m.size();
+ }
+
+ /**
+ * Returns <tt>true</tt> if this set contains no elements.
+ * @return <tt>true</tt> if this set contains no elements
+ */
+ public boolean isEmpty() {
+ return m.isEmpty();
+ }
+
+ /**
+ * Returns <tt>true</tt> if this set contains the specified element.
+ * More formally, returns <tt>true</tt> if and only if this set
+ * contains an element <tt>e</tt> such that <tt>o.equals(e)</tt>.
+ *
+ * @param o object to be checked for containment in this set
+ * @return <tt>true</tt> if this set contains the specified element
+ * @throws ClassCastException if the specified element cannot be
+ * compared with the elements currently in this set
+ * @throws NullPointerException if the specified element is null
+ */
+ public boolean contains(Object o) {
+ return m.containsKey(o);
+ }
+
+ /**
+ * Adds the specified element to this set if it is not already present.
+ * More formally, adds the specified element <tt>e</tt> to this set if
+ * the set contains no element <tt>e2</tt> such that <tt>e.equals(e2)</tt>.
+ * If this set already contains the element, the call leaves the set
+ * unchanged and returns <tt>false</tt>.
+ *
+ * @param e element to be added to this set
+ * @return <tt>true</tt> if this set did not already contain the
+ * specified element
+ * @throws ClassCastException if <tt>e</tt> cannot be compared
+ * with the elements currently in this set
+ * @throws NullPointerException if the specified element is null
+ */
+ public boolean add(E e) {
+ return m.putIfAbsent(e, Boolean.TRUE) == null;
+ }
+
+ /**
+ * Removes the specified element from this set if it is present.
+ * More formally, removes an element <tt>e</tt> such that
+ * <tt>o.equals(e)</tt>, if this set contains such an element.
+ * Returns <tt>true</tt> if this set contained the element (or
+ * equivalently, if this set changed as a result of the call).
+ * (This set will not contain the element once the call returns.)
+ *
+ * @param o object to be removed from this set, if present
+ * @return <tt>true</tt> if this set contained the specified element
+ * @throws ClassCastException if <tt>o</tt> cannot be compared
+ * with the elements currently in this set
+ * @throws NullPointerException if the specified element is null
+ */
+ public boolean remove(Object o) {
+ return m.remove(o, Boolean.TRUE);
+ }
+
+ /**
+ * Removes all of the elements from this set.
+ */
+ public void clear() {
+ m.clear();
+ }
+
+ /**
+ * Returns an iterator over the elements in this set in ascending order.
+ *
+ * @return an iterator over the elements in this set in ascending order
+ */
+ public Iterator<E> iterator() {
+ return m.navigableKeySet().iterator();
+ }
+
+ /**
+ * Returns an iterator over the elements in this set in descending order.
+ *
+ * @return an iterator over the elements in this set in descending order
+ */
+ public Iterator<E> descendingIterator() {
+ return m.descendingKeySet().iterator();
+ }
+
+
+ /* ---------------- AbstractSet Overrides -------------- */
+
+ /**
+ * Compares the specified object with this set for equality. Returns
+ * <tt>true</tt> if the specified object is also a set, the two sets
+ * have the same size, and every member of the specified set is
+ * contained in this set (or equivalently, every member of this set is
+ * contained in the specified set). This definition ensures that the
+ * equals method works properly across different implementations of the
+ * set interface.
+ *
+ * @param o the object to be compared for equality with this set
+ * @return <tt>true</tt> if the specified object is equal to this set
+ */
+ public boolean equals(Object o) {
+ // Override AbstractSet version to avoid calling size()
+ if (o == this)
+ return true;
+ if (!(o instanceof Set))
+ return false;
+ Collection<?> c = (Collection<?>) o;
+ try {
+ return containsAll(c) && c.containsAll(this);
+ } catch (ClassCastException unused) {
+ return false;
+ } catch (NullPointerException unused) {
+ return false;
+ }
+ }
+
+ /**
+ * Removes from this set all of its elements that are contained in
+ * the specified collection. If the specified collection is also
+ * a set, this operation effectively modifies this set so that its
+ * value is the <i>asymmetric set difference</i> of the two sets.
+ *
+ * @param c collection containing elements to be removed from this set
+ * @return <tt>true</tt> if this set changed as a result of the call
+ * @throws ClassCastException if the types of one or more elements in this
+ * set are incompatible with the specified collection
+ * @throws NullPointerException if the specified collection or any
+ * of its elements are null
+ */
+ public boolean removeAll(Collection<?> c) {
+ // Override AbstractSet version to avoid unnecessary call to size()
+ boolean modified = false;
+ for (Iterator<?> i = c.iterator(); i.hasNext(); )
+ if (remove(i.next()))
+ modified = true;
+ return modified;
+ }
+
+ /* ---------------- Relational operations -------------- */
+
+ /**
+ * @throws ClassCastException {@inheritDoc}
+ * @throws NullPointerException if the specified element is null
+ */
+ public E lower(E e) {
+ return m.lowerKey(e);
+ }
+
+ /**
+ * @throws ClassCastException {@inheritDoc}
+ * @throws NullPointerException if the specified element is null
+ */
+ public E floor(E e) {
+ return m.floorKey(e);
+ }
+
+ /**
+ * @throws ClassCastException {@inheritDoc}
+ * @throws NullPointerException if the specified element is null
+ */
+ public E ceiling(E e) {
+ return m.ceilingKey(e);
+ }
+
+ /**
+ * @throws ClassCastException {@inheritDoc}
+ * @throws NullPointerException if the specified element is null
+ */
+ public E higher(E e) {
+ return m.higherKey(e);
+ }
+
+ public E pollFirst() {
+ Map.Entry<E,Object> e = m.pollFirstEntry();
+ return e == null? null : e.getKey();
+ }
+
+ public E pollLast() {
+ Map.Entry<E,Object> e = m.pollLastEntry();
+ return e == null? null : e.getKey();
+ }
+
+
+ /* ---------------- SortedSet operations -------------- */
+
+
+ public Comparator<? super E> comparator() {
+ return m.comparator();
+ }
+
+ /**
+ * @throws NoSuchElementException {@inheritDoc}
+ */
+ public E first() {
+ return m.firstKey();
+ }
+
+ /**
+ * @throws NoSuchElementException {@inheritDoc}
+ */
+ public E last() {
+ return m.lastKey();
+ }
+
+ /**
+ * @throws ClassCastException {@inheritDoc}
+ * @throws NullPointerException if {@code fromElement} or
+ * {@code toElement} is null
+ * @throws IllegalArgumentException {@inheritDoc}
+ */
+ public NavigableSet<E> subSet(E fromElement,
+ boolean fromInclusive,
+ E toElement,
+ boolean toInclusive) {
+ return new ConcurrentSkipListSet<E>
+ (m.subMap(fromElement, fromInclusive,
+ toElement, toInclusive));
+ }
+
+ /**
+ * @throws ClassCastException {@inheritDoc}
+ * @throws NullPointerException if {@code toElement} is null
+ * @throws IllegalArgumentException {@inheritDoc}
+ */
+ public NavigableSet<E> headSet(E toElement, boolean inclusive) {
+ return new ConcurrentSkipListSet<E>(m.headMap(toElement, inclusive));
+ }
+
+ /**
+ * @throws ClassCastException {@inheritDoc}
+ * @throws NullPointerException if {@code fromElement} is null
+ * @throws IllegalArgumentException {@inheritDoc}
+ */
+ public NavigableSet<E> tailSet(E fromElement, boolean inclusive) {
+ return new ConcurrentSkipListSet<E>(m.tailMap(fromElement, inclusive));
+ }
+
+ /**
+ * @throws ClassCastException {@inheritDoc}
+ * @throws NullPointerException if {@code fromElement} or
+ * {@code toElement} is null
+ * @throws IllegalArgumentException {@inheritDoc}
+ */
+ public NavigableSet<E> subSet(E fromElement, E toElement) {
+ return subSet(fromElement, true, toElement, false);
+ }
+
+ /**
+ * @throws ClassCastException {@inheritDoc}
+ * @throws NullPointerException if {@code toElement} is null
+ * @throws IllegalArgumentException {@inheritDoc}
+ */
+ public NavigableSet<E> headSet(E toElement) {
+ return headSet(toElement, false);
+ }
+
+ /**
+ * @throws ClassCastException {@inheritDoc}
+ * @throws NullPointerException if {@code fromElement} is null
+ * @throws IllegalArgumentException {@inheritDoc}
+ */
+ public NavigableSet<E> tailSet(E fromElement) {
+ return tailSet(fromElement, true);
+ }
+
+ /**
+ * Returns a reverse order view of the elements contained in this set.
+ * The descending set is backed by this set, so changes to the set are
+ * reflected in the descending set, and vice-versa.
+ *
+ * <p>The returned set has an ordering equivalent to
+ * <tt>{@link Collections#reverseOrder(Comparator) Collections.reverseOrder}(comparator())</tt>.
+ * The expression {@code s.descendingSet().descendingSet()} returns a
+ * view of {@code s} essentially equivalent to {@code s}.
+ *
+ * @return a reverse order view of this set
+ */
+ public NavigableSet<E> descendingSet() {
+ return new ConcurrentSkipListSet(m.descendingMap());
+ }
+
+ // Support for resetting map in clone
+ private static final Unsafe unsafe = Unsafe.getUnsafe();
+ private static final long mapOffset;
+ static {
+ try {
+ mapOffset = unsafe.objectFieldOffset
+ (ConcurrentSkipListSet.class.getDeclaredField("m"));
+ } catch (Exception ex) { throw new Error(ex); }
+ }
+ private void setMap(ConcurrentNavigableMap<E,Object> map) {
+ unsafe.putObjectVolatile(this, mapOffset, map);
+ }
+
+}
diff --git a/concurrent/src/main/java/java/util/concurrent/CopyOnWriteArrayList.java b/concurrent/src/main/java/java/util/concurrent/CopyOnWriteArrayList.java
index f0c8ac6..237c5df 100644
--- a/concurrent/src/main/java/java/util/concurrent/CopyOnWriteArrayList.java
+++ b/concurrent/src/main/java/java/util/concurrent/CopyOnWriteArrayList.java
@@ -17,8 +17,6 @@
package java.util.concurrent;
import java.util.*;
import java.util.concurrent.locks.*;
-import java.lang.reflect.Array;
-
import sun.misc.Unsafe;
// BEGIN android-note
@@ -102,7 +100,7 @@ public class CopyOnWriteArrayList<E>
Object[] elements = c.toArray();
// c.toArray might (incorrectly) not return Object[] (see 6260652)
if (elements.getClass() != Object[].class)
- elements = Java6Arrays.copyOf(elements, elements.length, Object[].class);
+ elements = Arrays.copyOf(elements, elements.length, Object[].class);
setArray(elements);
}
@@ -114,7 +112,7 @@ public class CopyOnWriteArrayList<E>
* @throws NullPointerException if the specified array is null
*/
public CopyOnWriteArrayList(E[] toCopyIn) {
- setArray(Java6Arrays.copyOf(toCopyIn, toCopyIn.length, Object[].class));
+ setArray(Arrays.copyOf(toCopyIn, toCopyIn.length, Object[].class));
}
/**
@@ -288,7 +286,7 @@ public class CopyOnWriteArrayList<E>
*/
public Object[] toArray() {
Object[] elements = getArray();
- return Java6Arrays.copyOf(elements, elements.length);
+ return Arrays.copyOf(elements, elements.length);
}
/**
@@ -335,7 +333,7 @@ public class CopyOnWriteArrayList<E>
Object[] elements = getArray();
int len = elements.length;
if (a.length < len)
- return (T[]) Java6Arrays.copyOf(elements, len, a.getClass());
+ return (T[]) Arrays.copyOf(elements, len, a.getClass());
else {
System.arraycopy(elements, 0, a, 0, len);
if (a.length > len)
@@ -375,7 +373,7 @@ public class CopyOnWriteArrayList<E>
if (oldValue != element) {
int len = elements.length;
- Object[] newElements = Java6Arrays.copyOf(elements, len);
+ Object[] newElements = Arrays.copyOf(elements, len);
newElements[index] = element;
setArray(newElements);
} else {
@@ -400,7 +398,7 @@ public class CopyOnWriteArrayList<E>
try {
Object[] elements = getArray();
int len = elements.length;
- Object[] newElements = Java6Arrays.copyOf(elements, len + 1);
+ Object[] newElements = Arrays.copyOf(elements, len + 1);
newElements[len] = e;
setArray(newElements);
return true;
@@ -428,7 +426,7 @@ public class CopyOnWriteArrayList<E>
Object[] newElements;
int numMoved = len - index;
if (numMoved == 0)
- newElements = Java6Arrays.copyOf(elements, len + 1);
+ newElements = Arrays.copyOf(elements, len + 1);
else {
newElements = new Object[len + 1];
System.arraycopy(elements, 0, newElements, 0, index);
@@ -458,7 +456,7 @@ public class CopyOnWriteArrayList<E>
E oldValue = get(elements, index);
int numMoved = len - index - 1;
if (numMoved == 0)
- setArray(Java6Arrays.copyOf(elements, len - 1));
+ setArray(Arrays.copyOf(elements, len - 1));
else {
Object[] newElements = new Object[len - 1];
System.arraycopy(elements, 0, newElements, 0, index);
@@ -544,7 +542,7 @@ public class CopyOnWriteArrayList<E>
int newlen = len - (toIndex - fromIndex);
int numMoved = len - toIndex;
if (numMoved == 0)
- setArray(Java6Arrays.copyOf(elements, newlen));
+ setArray(Arrays.copyOf(elements, newlen));
else {
Object[] newElements = new Object[newlen];
System.arraycopy(elements, 0, newElements, 0, fromIndex);
@@ -636,7 +634,7 @@ public class CopyOnWriteArrayList<E>
temp[newlen++] = element;
}
if (newlen != len) {
- setArray(Java6Arrays.copyOf(temp, newlen));
+ setArray(Arrays.copyOf(temp, newlen));
return true;
}
}
@@ -676,7 +674,7 @@ public class CopyOnWriteArrayList<E>
temp[newlen++] = element;
}
if (newlen != len) {
- setArray(Java6Arrays.copyOf(temp, newlen));
+ setArray(Arrays.copyOf(temp, newlen));
return true;
}
}
@@ -715,7 +713,7 @@ public class CopyOnWriteArrayList<E>
uniq[added++] = e;
}
if (added > 0) {
- Object[] newElements = Java6Arrays.copyOf(elements, len + added);
+ Object[] newElements = Arrays.copyOf(elements, len + added);
System.arraycopy(uniq, 0, newElements, len, added);
setArray(newElements);
}
@@ -758,7 +756,7 @@ public class CopyOnWriteArrayList<E>
try {
Object[] elements = getArray();
int len = elements.length;
- Object[] newElements = Java6Arrays.copyOf(elements, len + cs.length);
+ Object[] newElements = Arrays.copyOf(elements, len + cs.length);
System.arraycopy(cs, 0, newElements, len, cs.length);
setArray(newElements);
return true;
@@ -798,7 +796,7 @@ public class CopyOnWriteArrayList<E>
int numMoved = len - index;
Object[] newElements;
if (numMoved == 0)
- newElements = Java6Arrays.copyOf(elements, len + cs.length);
+ newElements = Arrays.copyOf(elements, len + cs.length);
else {
newElements = new Object[len + cs.length];
System.arraycopy(elements, 0, newElements, 0, index);
@@ -1314,4 +1312,5 @@ public class CopyOnWriteArrayList<E>
private void resetLock() {
unsafe.putObjectVolatile(this, lockOffset, new ReentrantLock());
}
+
}
diff --git a/concurrent/src/main/java/java/util/concurrent/Delayed.java b/concurrent/src/main/java/java/util/concurrent/Delayed.java
index af41300..b1ff4ee 100644
--- a/concurrent/src/main/java/java/util/concurrent/Delayed.java
+++ b/concurrent/src/main/java/java/util/concurrent/Delayed.java
@@ -4,19 +4,10 @@
* http://creativecommons.org/licenses/publicdomain
*/
-/*
- * Modified in Apache Harmony to comply with Java 5 signature
- * specification.
- */
-
package java.util.concurrent;
import java.util.*;
-// BEGIN android-note
-// Added generic type Delayed to Comparable to be closer to the RI.
-// END android-note
-
/**
* A mix-in style interface for marking objects that should be
* acted upon after a given delay.
diff --git a/concurrent/src/main/java/java/util/concurrent/Exchanger.java b/concurrent/src/main/java/java/util/concurrent/Exchanger.java
index f67659c..bb2193c 100644
--- a/concurrent/src/main/java/java/util/concurrent/Exchanger.java
+++ b/concurrent/src/main/java/java/util/concurrent/Exchanger.java
@@ -471,7 +471,7 @@ public class Exchanger<V> {
else if (w.isInterrupted()) // Abort on interrupt
tryCancel(node, slot);
else // Block
- LockSupport.park();
+ LockSupport.park(node);
}
}
@@ -506,7 +506,7 @@ public class Exchanger<V> {
else if (w.isInterrupted())
tryCancel(node, slot);
else
- LockSupport.parkNanos(nanos);
+ LockSupport.parkNanos(node, nanos);
}
else if (tryCancel(node, slot) && !w.isInterrupted())
return scanOnTimeout(node);
diff --git a/concurrent/src/main/java/java/util/concurrent/ExecutorCompletionService.java b/concurrent/src/main/java/java/util/concurrent/ExecutorCompletionService.java
index 02606f9..bf4a584 100644
--- a/concurrent/src/main/java/java/util/concurrent/ExecutorCompletionService.java
+++ b/concurrent/src/main/java/java/util/concurrent/ExecutorCompletionService.java
@@ -84,7 +84,7 @@ public class ExecutorCompletionService<V> implements CompletionService<V> {
* FutureTask extension to enqueue upon completion
*/
private class QueueingFuture extends FutureTask<Void> {
- QueueingFuture(FutureTask<V> task) {
+ QueueingFuture(RunnableFuture<V> task) {
super(task, null);
this.task = task;
}
@@ -92,12 +92,18 @@ public class ExecutorCompletionService<V> implements CompletionService<V> {
private final Future<V> task;
}
- private FutureTask<V> newTaskFor(Callable<V> task) {
- return new FutureTask<V>(task);
+ private RunnableFuture<V> newTaskFor(Callable<V> task) {
+ if (aes == null)
+ return new FutureTask<V>(task);
+ else
+ return aes.newTaskFor(task);
}
- private FutureTask<V> newTaskFor(Runnable task, V result) {
- return new FutureTask<V>(task, result);
+ private RunnableFuture<V> newTaskFor(Runnable task, V result) {
+ if (aes == null)
+ return new FutureTask<V>(task, result);
+ else
+ return aes.newTaskFor(task, result);
}
/**
@@ -142,14 +148,14 @@ public class ExecutorCompletionService<V> implements CompletionService<V> {
public Future<V> submit(Callable<V> task) {
if (task == null) throw new NullPointerException();
- FutureTask<V> f = newTaskFor(task);
+ RunnableFuture<V> f = newTaskFor(task);
executor.execute(new QueueingFuture(f));
return f;
}
public Future<V> submit(Runnable task, V result) {
if (task == null) throw new NullPointerException();
- FutureTask<V> f = newTaskFor(task, result);
+ RunnableFuture<V> f = newTaskFor(task, result);
executor.execute(new QueueingFuture(f));
return f;
}
diff --git a/concurrent/src/main/java/java/util/concurrent/ExecutorService.java b/concurrent/src/main/java/java/util/concurrent/ExecutorService.java
index 757f7cb..ddd77bf 100644
--- a/concurrent/src/main/java/java/util/concurrent/ExecutorService.java
+++ b/concurrent/src/main/java/java/util/concurrent/ExecutorService.java
@@ -258,7 +258,7 @@ public interface ExecutorService extends Executor {
* scheduled for execution
*/
- <T> List<Future<T>> invokeAll(Collection<Callable<T>> tasks)
+ <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
throws InterruptedException;
/**
@@ -288,7 +288,7 @@ public interface ExecutorService extends Executor {
* @throws RejectedExecutionException if any task cannot be scheduled
* for execution
*/
- <T> List<Future<T>> invokeAll(Collection<Callable<T>> tasks,
+ <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
long timeout, TimeUnit unit)
throws InterruptedException;
@@ -303,14 +303,14 @@ public interface ExecutorService extends Executor {
* @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 NullPointerException if tasks or any element task
+ * subject to execution is <tt>null</tt>
* @throws IllegalArgumentException if tasks is empty
* @throws ExecutionException if no task successfully completes
* @throws RejectedExecutionException if tasks cannot be scheduled
* for execution
*/
- <T> T invokeAny(Collection<Callable<T>> tasks)
+ <T> T invokeAny(Collection<? extends Callable<T>> tasks)
throws InterruptedException, ExecutionException;
/**
@@ -327,15 +327,15 @@ public interface ExecutorService extends Executor {
* @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 NullPointerException if tasks, or unit, or any element
+ * task subject to execution is <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,
+ <T> T invokeAny(Collection<? extends 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
index a57abe5..96f6c15 100644
--- a/concurrent/src/main/java/java/util/concurrent/Executors.java
+++ b/concurrent/src/main/java/java/util/concurrent/Executors.java
@@ -13,6 +13,7 @@ import java.security.PrivilegedAction;
import java.security.PrivilegedExceptionAction;
import java.security.PrivilegedActionException;
import java.security.AccessControlException;
+// import sun.security.util.SecurityConstants; // android-removed
/**
* Factory and utility methods for {@link Executor}, {@link
@@ -359,7 +360,7 @@ public class Executors {
* @return a callable object
* @throws NullPointerException if action null
*/
- public static Callable<Object> callable(final PrivilegedAction action) {
+ public static Callable<Object> callable(final PrivilegedAction<?> action) {
if (action == null)
throw new NullPointerException();
return new Callable<Object>() {
@@ -374,7 +375,7 @@ public class Executors {
* @return a callable object
* @throws NullPointerException if action null
*/
- public static Callable<Object> callable(final PrivilegedExceptionAction action) {
+ public static Callable<Object> callable(final PrivilegedExceptionAction<?> action) {
if (action == null)
throw new NullPointerException();
return new Callable<Object>() {
@@ -484,7 +485,7 @@ public class Executors {
// Calls to getContextClassLoader from this class
// never trigger a security check, but we check
// whether our callers have this permission anyways.
- sm.checkPermission(new RuntimePermission("getContextClassLoader"));
+ sm.checkPermission(new RuntimePermission("getContextClassLoader")); // android-changed
// Whether setContextClassLoader turns out to be necessary
// or not, we fail fast if permission is not available.
@@ -565,7 +566,7 @@ public class Executors {
// Calls to getContextClassLoader from this class
// never trigger a security check, but we check
// whether our callers have this permission anyways.
- sm.checkPermission(new RuntimePermission("getContextClassLoader"));
+ sm.checkPermission(new RuntimePermission("getContextClassLoader")); // android-changed
// Fail fast
sm.checkPermission(new RuntimePermission("setContextClassLoader"));
@@ -614,20 +615,20 @@ public class Executors {
public <T> Future<T> submit(Runnable task, T result) {
return e.submit(task, result);
}
- public <T> List<Future<T>> invokeAll(Collection<Callable<T>> tasks)
+ public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
throws InterruptedException {
return e.invokeAll(tasks);
}
- public <T> List<Future<T>> invokeAll(Collection<Callable<T>> tasks,
+ public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
long timeout, TimeUnit unit)
throws InterruptedException {
return e.invokeAll(tasks, timeout, unit);
}
- public <T> T invokeAny(Collection<Callable<T>> tasks)
+ public <T> T invokeAny(Collection<? extends Callable<T>> tasks)
throws InterruptedException, ExecutionException {
return e.invokeAny(tasks);
}
- public <T> T invokeAny(Collection<Callable<T>> tasks,
+ public <T> T invokeAny(Collection<? extends Callable<T>> tasks,
long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException {
return e.invokeAny(tasks, timeout, unit);
diff --git a/concurrent/src/main/java/java/util/concurrent/FutureTask.java b/concurrent/src/main/java/java/util/concurrent/FutureTask.java
index 8aa9dd1..6bd13f9 100644
--- a/concurrent/src/main/java/java/util/concurrent/FutureTask.java
+++ b/concurrent/src/main/java/java/util/concurrent/FutureTask.java
@@ -30,7 +30,7 @@ import java.util.concurrent.locks.*;
* @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 {
+public class FutureTask<V> implements RunnableFuture<V> {
/** Synchronization control for FutureTask */
private final Sync sync;
diff --git a/concurrent/src/main/java/java/util/concurrent/Java6Arrays.java b/concurrent/src/main/java/java/util/concurrent/Java6Arrays.java
deleted file mode 100644
index 6b728be..0000000
--- a/concurrent/src/main/java/java/util/concurrent/Java6Arrays.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * 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.lang.reflect.Array;
-
-/**
- * Arrays.copyOf and Arrays.copyOfRange backported from Java 6.
- */
-class Java6Arrays {
-
- static <T> T[] copyOf(T[] original, int newLength) {
- if (null == original) {
- throw new NullPointerException();
- }
- if (0 <= newLength) {
- return copyOfRange(original, 0, newLength);
- }
- throw new NegativeArraySizeException();
- }
-
- static <T, U> T[] copyOf(U[] original, int newLength,
- Class<? extends T[]> newType) {
- if (0 <= newLength) {
- return copyOfRange(original, 0, newLength, newType);
- }
- throw new NegativeArraySizeException();
- }
-
- @SuppressWarnings("unchecked")
- static <T> T[] copyOfRange(T[] original, int start, int end) {
- if (original.length >= start && 0 <= start) {
- if (start <= end) {
- int length = end - start;
- int copyLength = Math.min(length, original.length - start);
- T[] copy = (T[]) Array.newInstance(original.getClass().getComponentType(), length);
- System.arraycopy(original, start, copy, 0, copyLength);
- return copy;
- }
- throw new IllegalArgumentException();
- }
- throw new ArrayIndexOutOfBoundsException();
- }
-
- @SuppressWarnings("unchecked")
- static <T, U> T[] copyOfRange(U[] original, int start, int end,
- Class<? extends T[]> newType) {
- if (start <= end) {
- if (original.length >= start && 0 <= start) {
- int length = end - start;
- int copyLength = Math.min(length, original.length - start);
- T[] copy = (T[]) Array.newInstance(newType.getComponentType(),
- length);
- System.arraycopy(original, start, copy, 0, copyLength);
- return copy;
- }
- throw new ArrayIndexOutOfBoundsException();
- }
- throw new IllegalArgumentException();
- }
-
-}
diff --git a/concurrent/src/main/java/java/util/concurrent/LinkedBlockingDeque.java b/concurrent/src/main/java/java/util/concurrent/LinkedBlockingDeque.java
new file mode 100644
index 0000000..196ea76
--- /dev/null
+++ b/concurrent/src/main/java/java/util/concurrent/LinkedBlockingDeque.java
@@ -0,0 +1,1137 @@
+/*
+ * 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.AbstractQueue;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.ReentrantLock;
+
+/**
+ * An optionally-bounded {@linkplain BlockingDeque blocking deque} based on
+ * linked nodes.
+ *
+ * <p> The optional capacity bound constructor argument serves as a
+ * way to prevent excessive expansion. The capacity, if unspecified,
+ * is equal to {@link Integer#MAX_VALUE}. Linked nodes are
+ * dynamically created upon each insertion unless this would bring the
+ * deque above capacity.
+ *
+ * <p>Most operations run in constant time (ignoring time spent
+ * blocking). Exceptions include {@link #remove(Object) remove},
+ * {@link #removeFirstOccurrence removeFirstOccurrence}, {@link
+ * #removeLastOccurrence removeLastOccurrence}, {@link #contains
+ * contains}, {@link #iterator iterator.remove()}, and the bulk
+ * operations, all of which run in linear time.
+ *
+ * <p>This class and its iterator implement all of the
+ * <em>optional</em> methods of the {@link Collection} and {@link
+ * Iterator} interfaces.
+ *
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
+ * Java Collections Framework</a>.
+ *
+ * @since 1.6
+ * @author Doug Lea
+ * @param <E> the type of elements held in this collection
+ */
+public class LinkedBlockingDeque<E>
+ extends AbstractQueue<E>
+ implements BlockingDeque<E>, java.io.Serializable {
+
+ /*
+ * Implemented as a simple doubly-linked list protected by a
+ * single lock and using conditions to manage blocking.
+ *
+ * To implement weakly consistent iterators, it appears we need to
+ * keep all Nodes GC-reachable from a predecessor dequeued Node.
+ * That would cause two problems:
+ * - allow a rogue Iterator to cause unbounded memory retention
+ * - cause cross-generational linking of old Nodes to new Nodes if
+ * a Node was tenured while live, which generational GCs have a
+ * hard time dealing with, causing repeated major collections.
+ * However, only non-deleted Nodes need to be reachable from
+ * dequeued Nodes, and reachability does not necessarily have to
+ * be of the kind understood by the GC. We use the trick of
+ * linking a Node that has just been dequeued to itself. Such a
+ * self-link implicitly means to jump to "first" (for next links)
+ * or "last" (for prev links).
+ */
+
+ /*
+ * We have "diamond" multiple interface/abstract class inheritance
+ * here, and that introduces ambiguities. Often we want the
+ * BlockingDeque javadoc combined with the AbstractQueue
+ * implementation, so a lot of method specs are duplicated here.
+ */
+
+ private static final long serialVersionUID = -387911632671998426L;
+
+ /** Doubly-linked list node class */
+ static final class Node<E> {
+ /**
+ * The item, or null if this node has been removed.
+ */
+ E item;
+
+ /**
+ * One of:
+ * - the real predecessor Node
+ * - this Node, meaning the predecessor is tail
+ * - null, meaning there is no predecessor
+ */
+ Node<E> prev;
+
+ /**
+ * One of:
+ * - the real successor Node
+ * - this Node, meaning the successor is head
+ * - null, meaning there is no successor
+ */
+ Node<E> next;
+
+ Node(E x, Node<E> p, Node<E> n) {
+ item = x;
+ prev = p;
+ next = n;
+ }
+ }
+
+ /**
+ * Pointer to first node.
+ * Invariant: (first == null && last == null) ||
+ * (first.prev == null && first.item != null)
+ */
+ transient Node<E> first;
+
+ /**
+ * Pointer to last node.
+ * Invariant: (first == null && last == null) ||
+ * (last.next == null && last.item != null)
+ */
+ transient Node<E> last;
+
+ /** Number of items in the deque */
+ private transient int count;
+
+ /** Maximum number of items in the deque */
+ private final int capacity;
+
+ /** Main lock guarding all access */
+ final ReentrantLock lock = new ReentrantLock();
+
+ /** Condition for waiting takes */
+ private final Condition notEmpty = lock.newCondition();
+
+ /** Condition for waiting puts */
+ private final Condition notFull = lock.newCondition();
+
+ /**
+ * Creates a {@code LinkedBlockingDeque} with a capacity of
+ * {@link Integer#MAX_VALUE}.
+ */
+ public LinkedBlockingDeque() {
+ this(Integer.MAX_VALUE);
+ }
+
+ /**
+ * Creates a {@code LinkedBlockingDeque} with the given (fixed) capacity.
+ *
+ * @param capacity the capacity of this deque
+ * @throws IllegalArgumentException if {@code capacity} is less than 1
+ */
+ public LinkedBlockingDeque(int capacity) {
+ if (capacity <= 0) throw new IllegalArgumentException();
+ this.capacity = capacity;
+ }
+
+ /**
+ * Creates a {@code LinkedBlockingDeque} with a capacity of
+ * {@link Integer#MAX_VALUE}, initially containing the elements of
+ * the given collection, added in traversal order of the
+ * collection's iterator.
+ *
+ * @param c the collection of elements to initially contain
+ * @throws NullPointerException if the specified collection or any
+ * of its elements are null
+ */
+ public LinkedBlockingDeque(Collection<? extends E> c) {
+ this(Integer.MAX_VALUE);
+ final ReentrantLock lock = this.lock;
+ lock.lock(); // Never contended, but necessary for visibility
+ try {
+ for (E e : c) {
+ if (e == null)
+ throw new NullPointerException();
+ if (!linkLast(e))
+ throw new IllegalStateException("Deque full");
+ }
+ } finally {
+ lock.unlock();
+ }
+ }
+
+
+ // Basic linking and unlinking operations, called only while holding lock
+
+ /**
+ * Links e as first element, or returns false if full.
+ */
+ private boolean linkFirst(E e) {
+ // assert lock.isHeldByCurrentThread();
+ if (count >= capacity)
+ return false;
+ Node<E> f = first;
+ Node<E> x = new Node<E>(e, null, f);
+ first = x;
+ if (last == null)
+ last = x;
+ else
+ f.prev = x;
+ ++count;
+ notEmpty.signal();
+ return true;
+ }
+
+ /**
+ * Links e as last element, or returns false if full.
+ */
+ private boolean linkLast(E e) {
+ // assert lock.isHeldByCurrentThread();
+ if (count >= capacity)
+ return false;
+ Node<E> l = last;
+ Node<E> x = new Node<E>(e, l, null);
+ last = x;
+ if (first == null)
+ first = x;
+ else
+ l.next = x;
+ ++count;
+ notEmpty.signal();
+ return true;
+ }
+
+ /**
+ * Removes and returns first element, or null if empty.
+ */
+ private E unlinkFirst() {
+ // assert lock.isHeldByCurrentThread();
+ Node<E> f = first;
+ if (f == null)
+ return null;
+ Node<E> n = f.next;
+ E item = f.item;
+ f.item = null;
+ f.next = f; // help GC
+ first = n;
+ if (n == null)
+ last = null;
+ else
+ n.prev = null;
+ --count;
+ notFull.signal();
+ return item;
+ }
+
+ /**
+ * Removes and returns last element, or null if empty.
+ */
+ private E unlinkLast() {
+ // assert lock.isHeldByCurrentThread();
+ Node<E> l = last;
+ if (l == null)
+ return null;
+ Node<E> p = l.prev;
+ E item = l.item;
+ l.item = null;
+ l.prev = l; // help GC
+ last = p;
+ if (p == null)
+ first = null;
+ else
+ p.next = null;
+ --count;
+ notFull.signal();
+ return item;
+ }
+
+ /**
+ * Unlinks x.
+ */
+ void unlink(Node<E> x) {
+ // assert lock.isHeldByCurrentThread();
+ Node<E> p = x.prev;
+ Node<E> n = x.next;
+ if (p == null) {
+ unlinkFirst();
+ } else if (n == null) {
+ unlinkLast();
+ } else {
+ p.next = n;
+ n.prev = p;
+ x.item = null;
+ // Don't mess with x's links. They may still be in use by
+ // an iterator.
+ --count;
+ notFull.signal();
+ }
+ }
+
+ // BlockingDeque methods
+
+ /**
+ * @throws IllegalStateException {@inheritDoc}
+ * @throws NullPointerException {@inheritDoc}
+ */
+ public void addFirst(E e) {
+ if (!offerFirst(e))
+ throw new IllegalStateException("Deque full");
+ }
+
+ /**
+ * @throws IllegalStateException {@inheritDoc}
+ * @throws NullPointerException {@inheritDoc}
+ */
+ public void addLast(E e) {
+ if (!offerLast(e))
+ throw new IllegalStateException("Deque full");
+ }
+
+ /**
+ * @throws NullPointerException {@inheritDoc}
+ */
+ public boolean offerFirst(E e) {
+ if (e == null) throw new NullPointerException();
+ final ReentrantLock lock = this.lock;
+ lock.lock();
+ try {
+ return linkFirst(e);
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * @throws NullPointerException {@inheritDoc}
+ */
+ public boolean offerLast(E e) {
+ if (e == null) throw new NullPointerException();
+ final ReentrantLock lock = this.lock;
+ lock.lock();
+ try {
+ return linkLast(e);
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * @throws NullPointerException {@inheritDoc}
+ * @throws InterruptedException {@inheritDoc}
+ */
+ public void putFirst(E e) throws InterruptedException {
+ if (e == null) throw new NullPointerException();
+ final ReentrantLock lock = this.lock;
+ lock.lock();
+ try {
+ while (!linkFirst(e))
+ notFull.await();
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * @throws NullPointerException {@inheritDoc}
+ * @throws InterruptedException {@inheritDoc}
+ */
+ public void putLast(E e) throws InterruptedException {
+ if (e == null) throw new NullPointerException();
+ final ReentrantLock lock = this.lock;
+ lock.lock();
+ try {
+ while (!linkLast(e))
+ notFull.await();
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * @throws NullPointerException {@inheritDoc}
+ * @throws InterruptedException {@inheritDoc}
+ */
+ public boolean offerFirst(E e, long timeout, TimeUnit unit)
+ throws InterruptedException {
+ if (e == null) throw new NullPointerException();
+ long nanos = unit.toNanos(timeout);
+ final ReentrantLock lock = this.lock;
+ lock.lockInterruptibly();
+ try {
+ while (!linkFirst(e)) {
+ if (nanos <= 0)
+ return false;
+ nanos = notFull.awaitNanos(nanos);
+ }
+ return true;
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * @throws NullPointerException {@inheritDoc}
+ * @throws InterruptedException {@inheritDoc}
+ */
+ public boolean offerLast(E e, long timeout, TimeUnit unit)
+ throws InterruptedException {
+ if (e == null) throw new NullPointerException();
+ long nanos = unit.toNanos(timeout);
+ final ReentrantLock lock = this.lock;
+ lock.lockInterruptibly();
+ try {
+ while (!linkLast(e)) {
+ if (nanos <= 0)
+ return false;
+ nanos = notFull.awaitNanos(nanos);
+ }
+ return true;
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * @throws NoSuchElementException {@inheritDoc}
+ */
+ public E removeFirst() {
+ E x = pollFirst();
+ if (x == null) throw new NoSuchElementException();
+ return x;
+ }
+
+ /**
+ * @throws NoSuchElementException {@inheritDoc}
+ */
+ public E removeLast() {
+ E x = pollLast();
+ if (x == null) throw new NoSuchElementException();
+ return x;
+ }
+
+ public E pollFirst() {
+ final ReentrantLock lock = this.lock;
+ lock.lock();
+ try {
+ return unlinkFirst();
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ public E pollLast() {
+ final ReentrantLock lock = this.lock;
+ lock.lock();
+ try {
+ return unlinkLast();
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ public E takeFirst() throws InterruptedException {
+ final ReentrantLock lock = this.lock;
+ lock.lock();
+ try {
+ E x;
+ while ( (x = unlinkFirst()) == null)
+ notEmpty.await();
+ return x;
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ public E takeLast() throws InterruptedException {
+ final ReentrantLock lock = this.lock;
+ lock.lock();
+ try {
+ E x;
+ while ( (x = unlinkLast()) == null)
+ notEmpty.await();
+ return x;
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ public E pollFirst(long timeout, TimeUnit unit)
+ throws InterruptedException {
+ long nanos = unit.toNanos(timeout);
+ final ReentrantLock lock = this.lock;
+ lock.lockInterruptibly();
+ try {
+ E x;
+ while ( (x = unlinkFirst()) == null) {
+ if (nanos <= 0)
+ return null;
+ nanos = notEmpty.awaitNanos(nanos);
+ }
+ return x;
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ public E pollLast(long timeout, TimeUnit unit)
+ throws InterruptedException {
+ long nanos = unit.toNanos(timeout);
+ final ReentrantLock lock = this.lock;
+ lock.lockInterruptibly();
+ try {
+ E x;
+ while ( (x = unlinkLast()) == null) {
+ if (nanos <= 0)
+ return null;
+ nanos = notEmpty.awaitNanos(nanos);
+ }
+ return x;
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * @throws NoSuchElementException {@inheritDoc}
+ */
+ public E getFirst() {
+ E x = peekFirst();
+ if (x == null) throw new NoSuchElementException();
+ return x;
+ }
+
+ /**
+ * @throws NoSuchElementException {@inheritDoc}
+ */
+ public E getLast() {
+ E x = peekLast();
+ if (x == null) throw new NoSuchElementException();
+ return x;
+ }
+
+ public E peekFirst() {
+ final ReentrantLock lock = this.lock;
+ lock.lock();
+ try {
+ return (first == null) ? null : first.item;
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ public E peekLast() {
+ final ReentrantLock lock = this.lock;
+ lock.lock();
+ try {
+ return (last == null) ? null : last.item;
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ public boolean removeFirstOccurrence(Object o) {
+ if (o == null) return false;
+ final ReentrantLock lock = this.lock;
+ lock.lock();
+ try {
+ for (Node<E> p = first; p != null; p = p.next) {
+ if (o.equals(p.item)) {
+ unlink(p);
+ return true;
+ }
+ }
+ return false;
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ public boolean removeLastOccurrence(Object o) {
+ if (o == null) return false;
+ final ReentrantLock lock = this.lock;
+ lock.lock();
+ try {
+ for (Node<E> p = last; p != null; p = p.prev) {
+ if (o.equals(p.item)) {
+ unlink(p);
+ return true;
+ }
+ }
+ return false;
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ // BlockingQueue methods
+
+ /**
+ * Inserts the specified element at the end of this deque unless it would
+ * violate capacity restrictions. When using a capacity-restricted deque,
+ * it is generally preferable to use method {@link #offer(Object) offer}.
+ *
+ * <p>This method is equivalent to {@link #addLast}.
+ *
+ * @throws IllegalStateException if the element cannot be added at this
+ * time due to capacity restrictions
+ * @throws NullPointerException if the specified element is null
+ */
+ public boolean add(E e) {
+ addLast(e);
+ return true;
+ }
+
+ /**
+ * @throws NullPointerException if the specified element is null
+ */
+ public boolean offer(E e) {
+ return offerLast(e);
+ }
+
+ /**
+ * @throws NullPointerException {@inheritDoc}
+ * @throws InterruptedException {@inheritDoc}
+ */
+ public void put(E e) throws InterruptedException {
+ putLast(e);
+ }
+
+ /**
+ * @throws NullPointerException {@inheritDoc}
+ * @throws InterruptedException {@inheritDoc}
+ */
+ public boolean offer(E e, long timeout, TimeUnit unit)
+ throws InterruptedException {
+ return offerLast(e, timeout, unit);
+ }
+
+ /**
+ * Retrieves and removes the head of the queue represented by this deque.
+ * This method differs from {@link #poll poll} only in that it throws an
+ * exception if this deque is empty.
+ *
+ * <p>This method is equivalent to {@link #removeFirst() removeFirst}.
+ *
+ * @return the head of the queue represented by this deque
+ * @throws NoSuchElementException if this deque is empty
+ */
+ public E remove() {
+ return removeFirst();
+ }
+
+ public E poll() {
+ return pollFirst();
+ }
+
+ public E take() throws InterruptedException {
+ return takeFirst();
+ }
+
+ public E poll(long timeout, TimeUnit unit) throws InterruptedException {
+ return pollFirst(timeout, unit);
+ }
+
+ /**
+ * Retrieves, but does not remove, the head of the queue represented by
+ * this deque. This method differs from {@link #peek peek} only in that
+ * it throws an exception if this deque is empty.
+ *
+ * <p>This method is equivalent to {@link #getFirst() getFirst}.
+ *
+ * @return the head of the queue represented by this deque
+ * @throws NoSuchElementException if this deque is empty
+ */
+ public E element() {
+ return getFirst();
+ }
+
+ public E peek() {
+ return peekFirst();
+ }
+
+ /**
+ * Returns the number of additional elements that this deque can ideally
+ * (in the absence of memory or resource constraints) accept without
+ * blocking. This is always equal to the initial capacity of this deque
+ * less the current {@code size} of this deque.
+ *
+ * <p>Note that you <em>cannot</em> always tell if an attempt to insert
+ * an element will succeed by inspecting {@code remainingCapacity}
+ * because it may be the case that another thread is about to
+ * insert or remove an element.
+ */
+ public int remainingCapacity() {
+ final ReentrantLock lock = this.lock;
+ lock.lock();
+ try {
+ return capacity - count;
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * @throws UnsupportedOperationException {@inheritDoc}
+ * @throws ClassCastException {@inheritDoc}
+ * @throws NullPointerException {@inheritDoc}
+ * @throws IllegalArgumentException {@inheritDoc}
+ */
+ public int drainTo(Collection<? super E> c) {
+ return drainTo(c, Integer.MAX_VALUE);
+ }
+
+ /**
+ * @throws UnsupportedOperationException {@inheritDoc}
+ * @throws ClassCastException {@inheritDoc}
+ * @throws NullPointerException {@inheritDoc}
+ * @throws IllegalArgumentException {@inheritDoc}
+ */
+ public int drainTo(Collection<? super E> c, int maxElements) {
+ if (c == null)
+ throw new NullPointerException();
+ if (c == this)
+ throw new IllegalArgumentException();
+ final ReentrantLock lock = this.lock;
+ lock.lock();
+ try {
+ int n = Math.min(maxElements, count);
+ for (int i = 0; i < n; i++) {
+ c.add(first.item); // In this order, in case add() throws.
+ unlinkFirst();
+ }
+ return n;
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ // Stack methods
+
+ /**
+ * @throws IllegalStateException {@inheritDoc}
+ * @throws NullPointerException {@inheritDoc}
+ */
+ public void push(E e) {
+ addFirst(e);
+ }
+
+ /**
+ * @throws NoSuchElementException {@inheritDoc}
+ */
+ public E pop() {
+ return removeFirst();
+ }
+
+ // Collection methods
+
+ /**
+ * Removes the first occurrence of the specified element from this deque.
+ * If the deque does not contain the element, it is unchanged.
+ * More formally, removes the first element {@code e} such that
+ * {@code o.equals(e)} (if such an element exists).
+ * Returns {@code true} if this deque contained the specified element
+ * (or equivalently, if this deque changed as a result of the call).
+ *
+ * <p>This method is equivalent to
+ * {@link #removeFirstOccurrence(Object) removeFirstOccurrence}.
+ *
+ * @param o element to be removed from this deque, if present
+ * @return {@code true} if this deque changed as a result of the call
+ */
+ public boolean remove(Object o) {
+ return removeFirstOccurrence(o);
+ }
+
+ /**
+ * Returns the number of elements in this deque.
+ *
+ * @return the number of elements in this deque
+ */
+ public int size() {
+ final ReentrantLock lock = this.lock;
+ lock.lock();
+ try {
+ return count;
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * Returns {@code true} if this deque contains the specified element.
+ * More formally, returns {@code true} if and only if this deque contains
+ * at least one element {@code e} such that {@code o.equals(e)}.
+ *
+ * @param o object to be checked for containment in this deque
+ * @return {@code true} if this deque contains the specified element
+ */
+ public boolean contains(Object o) {
+ if (o == null) return false;
+ final ReentrantLock lock = this.lock;
+ lock.lock();
+ try {
+ for (Node<E> p = first; p != null; p = p.next)
+ if (o.equals(p.item))
+ return true;
+ return false;
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /*
+ * TODO: Add support for more efficient bulk operations.
+ *
+ * We don't want to acquire the lock for every iteration, but we
+ * also want other threads a chance to interact with the
+ * collection, especially when count is close to capacity.
+ */
+
+// /**
+// * Adds all of the elements in the specified collection to this
+// * queue. Attempts to addAll of a queue to itself result in
+// * {@code IllegalArgumentException}. Further, the behavior of
+// * this operation is undefined if the specified collection is
+// * modified while the operation is in progress.
+// *
+// * @param c collection containing elements to be added to this queue
+// * @return {@code true} if this queue changed as a result of the call
+// * @throws ClassCastException {@inheritDoc}
+// * @throws NullPointerException {@inheritDoc}
+// * @throws IllegalArgumentException {@inheritDoc}
+// * @throws IllegalStateException {@inheritDoc}
+// * @see #add(Object)
+// */
+// public boolean addAll(Collection<? extends E> c) {
+// if (c == null)
+// throw new NullPointerException();
+// if (c == this)
+// throw new IllegalArgumentException();
+// final ReentrantLock lock = this.lock;
+// lock.lock();
+// try {
+// boolean modified = false;
+// for (E e : c)
+// if (linkLast(e))
+// modified = true;
+// return modified;
+// } finally {
+// lock.unlock();
+// }
+// }
+
+ /**
+ * Returns an array containing all of the elements in this deque, in
+ * proper sequence (from first to last element).
+ *
+ * <p>The returned array will be "safe" in that no references to it are
+ * maintained by this deque. (In other words, this method must allocate
+ * a new array). The caller is thus free to modify the returned array.
+ *
+ * <p>This method acts as bridge between array-based and collection-based
+ * APIs.
+ *
+ * @return an array containing all of the elements in this deque
+ */
+ @SuppressWarnings("unchecked")
+ public Object[] toArray() {
+ final ReentrantLock lock = this.lock;
+ lock.lock();
+ try {
+ Object[] a = new Object[count];
+ int k = 0;
+ for (Node<E> p = first; p != null; p = p.next)
+ a[k++] = p.item;
+ return a;
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * Returns an array containing all of the elements in this deque, in
+ * proper sequence; the runtime type of the returned array is that of
+ * the specified array. If the deque fits in the specified array, it
+ * is returned therein. Otherwise, a new array is allocated with the
+ * runtime type of the specified array and the size of this deque.
+ *
+ * <p>If this deque fits in the specified array with room to spare
+ * (i.e., the array has more elements than this deque), the element in
+ * the array immediately following the end of the deque is set to
+ * {@code null}.
+ *
+ * <p>Like the {@link #toArray()} method, this method acts as bridge between
+ * array-based and collection-based APIs. Further, this method allows
+ * precise control over the runtime type of the output array, and may,
+ * under certain circumstances, be used to save allocation costs.
+ *
+ * <p>Suppose {@code x} is a deque known to contain only strings.
+ * The following code can be used to dump the deque into a newly
+ * allocated array of {@code String}:
+ *
+ * <pre>
+ * String[] y = x.toArray(new String[0]);</pre>
+ *
+ * Note that {@code toArray(new Object[0])} is identical in function to
+ * {@code toArray()}.
+ *
+ * @param a the array into which the elements of the deque are to
+ * be stored, if it is big enough; otherwise, a new array of the
+ * same runtime type is allocated for this purpose
+ * @return an array containing all of the elements in this deque
+ * @throws ArrayStoreException if the runtime type of the specified array
+ * is not a supertype of the runtime type of every element in
+ * this deque
+ * @throws NullPointerException if the specified array is null
+ */
+ @SuppressWarnings("unchecked")
+ public <T> T[] toArray(T[] a) {
+ final ReentrantLock lock = this.lock;
+ lock.lock();
+ try {
+ if (a.length < count)
+ a = (T[])java.lang.reflect.Array.newInstance
+ (a.getClass().getComponentType(), count);
+
+ int k = 0;
+ for (Node<E> p = first; p != null; p = p.next)
+ a[k++] = (T)p.item;
+ if (a.length > k)
+ a[k] = null;
+ return a;
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ public String toString() {
+ final ReentrantLock lock = this.lock;
+ lock.lock();
+ try {
+ return super.toString();
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * Atomically removes all of the elements from this deque.
+ * The deque will be empty after this call returns.
+ */
+ public void clear() {
+ final ReentrantLock lock = this.lock;
+ lock.lock();
+ try {
+ for (Node<E> f = first; f != null; ) {
+ f.item = null;
+ Node<E> n = f.next;
+ f.prev = null;
+ f.next = null;
+ f = n;
+ }
+ first = last = null;
+ count = 0;
+ notFull.signalAll();
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * Returns an iterator over the elements in this deque in proper sequence.
+ * The elements will be returned in order from first (head) to last (tail).
+ * The returned {@code Iterator} is a "weakly consistent" iterator that
+ * will never throw {@link java.util.ConcurrentModificationException
+ * ConcurrentModificationException},
+ * and guarantees to traverse elements as they existed upon
+ * construction of the iterator, and may (but is not guaranteed to)
+ * reflect any modifications subsequent to construction.
+ *
+ * @return an iterator over the elements in this deque in proper sequence
+ */
+ public Iterator<E> iterator() {
+ return new Itr();
+ }
+
+ /**
+ * Returns an iterator over the elements in this deque in reverse
+ * sequential order. The elements will be returned in order from
+ * last (tail) to first (head).
+ * The returned {@code Iterator} is a "weakly consistent" iterator that
+ * will never throw {@link java.util.ConcurrentModificationException
+ * ConcurrentModificationException},
+ * and guarantees to traverse elements as they existed upon
+ * construction of the iterator, and may (but is not guaranteed to)
+ * reflect any modifications subsequent to construction.
+ */
+ public Iterator<E> descendingIterator() {
+ return new DescendingItr();
+ }
+
+ /**
+ * Base class for Iterators for LinkedBlockingDeque
+ */
+ private abstract class AbstractItr implements Iterator<E> {
+ /**
+ * The next node to return in next()
+ */
+ Node<E> next;
+
+ /**
+ * nextItem holds on to item fields because once we claim that
+ * an element exists in hasNext(), we must return item read
+ * under lock (in advance()) even if it was in the process of
+ * being removed when hasNext() was called.
+ */
+ E nextItem;
+
+ /**
+ * Node returned by most recent call to next. Needed by remove.
+ * Reset to null if this element is deleted by a call to remove.
+ */
+ private Node<E> lastRet;
+
+ abstract Node<E> firstNode();
+ abstract Node<E> nextNode(Node<E> n);
+
+ AbstractItr() {
+ // set to initial position
+ final ReentrantLock lock = LinkedBlockingDeque.this.lock;
+ lock.lock();
+ try {
+ next = firstNode();
+ nextItem = (next == null) ? null : next.item;
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * Advances next.
+ */
+ void advance() {
+ final ReentrantLock lock = LinkedBlockingDeque.this.lock;
+ lock.lock();
+ try {
+ // assert next != null;
+ Node<E> s = nextNode(next);
+ if (s == next) {
+ next = firstNode();
+ } else {
+ // Skip over removed nodes.
+ // May be necessary if multiple interior Nodes are removed.
+ while (s != null && s.item == null)
+ s = nextNode(s);
+ next = s;
+ }
+ nextItem = (next == null) ? null : next.item;
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ public boolean hasNext() {
+ return next != null;
+ }
+
+ public E next() {
+ if (next == null)
+ throw new NoSuchElementException();
+ lastRet = next;
+ E x = nextItem;
+ advance();
+ return x;
+ }
+
+ public void remove() {
+ Node<E> n = lastRet;
+ if (n == null)
+ throw new IllegalStateException();
+ lastRet = null;
+ final ReentrantLock lock = LinkedBlockingDeque.this.lock;
+ lock.lock();
+ try {
+ if (n.item != null)
+ unlink(n);
+ } finally {
+ lock.unlock();
+ }
+ }
+ }
+
+ /** Forward iterator */
+ private class Itr extends AbstractItr {
+ Node<E> firstNode() { return first; }
+ Node<E> nextNode(Node<E> n) { return n.next; }
+ }
+
+ /** Descending iterator */
+ private class DescendingItr extends AbstractItr {
+ Node<E> firstNode() { return last; }
+ Node<E> nextNode(Node<E> n) { return n.prev; }
+ }
+
+ /**
+ * Save the state of this deque to a stream (that is, serialize it).
+ *
+ * @serialData The capacity (int), followed by elements (each an
+ * {@code Object}) in the proper order, followed by a null
+ * @param s the stream
+ */
+ private void writeObject(java.io.ObjectOutputStream s)
+ throws java.io.IOException {
+ final ReentrantLock lock = this.lock;
+ lock.lock();
+ try {
+ // Write out capacity and any hidden stuff
+ s.defaultWriteObject();
+ // Write out all elements in the proper order.
+ for (Node<E> p = first; p != null; p = p.next)
+ s.writeObject(p.item);
+ // Use trailing null as sentinel
+ s.writeObject(null);
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * Reconstitute this deque from a stream (that is,
+ * deserialize it).
+ * @param s the stream
+ */
+ private void readObject(java.io.ObjectInputStream s)
+ throws java.io.IOException, ClassNotFoundException {
+ s.defaultReadObject();
+ count = 0;
+ first = null;
+ last = null;
+ // Read in all elements and place in queue
+ for (;;) {
+ @SuppressWarnings("unchecked")
+ E item = (E)s.readObject();
+ if (item == null)
+ break;
+ add(item);
+ }
+ }
+
+}
diff --git a/concurrent/src/main/java/java/util/concurrent/LinkedBlockingQueue.java b/concurrent/src/main/java/java/util/concurrent/LinkedBlockingQueue.java
index e06f7bd..1a8e412 100644
--- a/concurrent/src/main/java/java/util/concurrent/LinkedBlockingQueue.java
+++ b/concurrent/src/main/java/java/util/concurrent/LinkedBlockingQueue.java
@@ -5,14 +5,19 @@
*/
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
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.AbstractQueue;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
/**
* An optionally-bounded {@linkplain BlockingQueue blocking queue} based on
* linked nodes.
@@ -57,15 +62,43 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E>
* items have been entered since the signal. And symmetrically for
* takes signalling puts. Operations such as remove(Object) and
* iterators acquire both locks.
+ *
+ * Visibility between writers and readers is provided as follows:
+ *
+ * Whenever an element is enqueued, the putLock is acquired and
+ * count updated. A subsequent reader guarantees visibility to the
+ * enqueued Node by either acquiring the putLock (via fullyLock)
+ * or by acquiring the takeLock, and then reading n = count.get();
+ * this gives visibility to the first n items.
+ *
+ * To implement weakly consistent iterators, it appears we need to
+ * keep all Nodes GC-reachable from a predecessor dequeued Node.
+ * That would cause two problems:
+ * - allow a rogue Iterator to cause unbounded memory retention
+ * - cause cross-generational linking of old Nodes to new Nodes if
+ * a Node was tenured while live, which generational GCs have a
+ * hard time dealing with, causing repeated major collections.
+ * However, only non-deleted Nodes need to be reachable from
+ * dequeued Nodes, and reachability does not necessarily have to
+ * be of the kind understood by the GC. We use the trick of
+ * linking a Node that has just been dequeued to itself. Such a
+ * self-link implicitly means to advance to head.next.
*/
/**
* Linked list node class
*/
static class Node<E> {
- /** The item, volatile to ensure barrier separating write and read */
- volatile E item;
+ E item;
+
+ /**
+ * One of:
+ * - the real successor Node
+ * - this Node, meaning the successor is head.next
+ * - null, meaning there is no successor (this is the last node)
+ */
Node<E> next;
+
Node(E x) { item = x; }
}
@@ -75,10 +108,16 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E>
/** Current number of elements */
private final AtomicInteger count = new AtomicInteger(0);
- /** Head of linked list */
+ /**
+ * Head of linked list.
+ * Invariant: head.item == null
+ */
private transient Node<E> head;
- /** Tail of linked list */
+ /**
+ * Tail of linked list.
+ * Invariant: last.next == null
+ */
private transient Node<E> last;
/** Lock held by take, poll, etc */
@@ -122,20 +161,26 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E>
/**
* Creates a node and links it at end of queue.
+ *
* @param x the item
*/
- private void insert(E x) {
+ private void enqueue(E x) {
+ // assert putLock.isHeldByCurrentThread();
+ // assert last.next == null;
last = last.next = new Node<E>(x);
}
/**
- * Removes a node from head of queue,
+ * Removes a node from head of queue.
+ *
* @return the node
*/
- private E extract() {
+ private E dequeue() {
+ // assert takeLock.isHeldByCurrentThread();
+ // assert head.item == null;
Node<E> h = head;
Node<E> first = h.next;
- h.next = null; // help GC
+ h.next = h; // help GC
head = first;
E x = first.item;
first.item = null;
@@ -145,7 +190,7 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E>
/**
* Lock to prevent both puts and takes.
*/
- private void fullyLock() {
+ void fullyLock() {
putLock.lock();
takeLock.lock();
}
@@ -153,14 +198,21 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E>
/**
* Unlock to allow both puts and takes.
*/
- private void fullyUnlock() {
+ void fullyUnlock() {
takeLock.unlock();
putLock.unlock();
}
+// /**
+// * Tells whether both locks are held by current thread.
+// */
+// boolean isFullyLocked() {
+// return (putLock.isHeldByCurrentThread() &&
+// takeLock.isHeldByCurrentThread());
+// }
/**
- * Creates a <tt>LinkedBlockingQueue</tt> with a capacity of
+ * Creates a {@code LinkedBlockingQueue} with a capacity of
* {@link Integer#MAX_VALUE}.
*/
public LinkedBlockingQueue() {
@@ -168,10 +220,10 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E>
}
/**
- * Creates a <tt>LinkedBlockingQueue</tt> with the given (fixed) capacity.
+ * Creates a {@code LinkedBlockingQueue} with the given (fixed) capacity.
*
* @param capacity the capacity of this queue
- * @throws IllegalArgumentException if <tt>capacity</tt> is not greater
+ * @throws IllegalArgumentException if {@code capacity} is not greater
* than zero
*/
public LinkedBlockingQueue(int capacity) {
@@ -181,7 +233,7 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E>
}
/**
- * Creates a <tt>LinkedBlockingQueue</tt> with a capacity of
+ * Creates a {@code LinkedBlockingQueue} with a capacity of
* {@link Integer#MAX_VALUE}, initially containing the elements of the
* given collection,
* added in traversal order of the collection's iterator.
@@ -192,8 +244,22 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E>
*/
public LinkedBlockingQueue(Collection<? extends E> c) {
this(Integer.MAX_VALUE);
- for (E e : c)
- add(e);
+ final ReentrantLock putLock = this.putLock;
+ putLock.lock(); // Never contended, but necessary for visibility
+ try {
+ int n = 0;
+ for (E e : c) {
+ if (e == null)
+ throw new NullPointerException();
+ if (n == capacity)
+ throw new IllegalStateException("Queue full");
+ enqueue(e);
+ ++n;
+ }
+ count.set(n);
+ } finally {
+ putLock.unlock();
+ }
}
@@ -214,10 +280,10 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E>
* Returns the number of additional elements that this queue can ideally
* (in the absence of memory or resource constraints) accept without
* blocking. This is always equal to the initial capacity of this queue
- * less the current <tt>size</tt> of this queue.
+ * less the current {@code size} of this queue.
*
* <p>Note that you <em>cannot</em> always tell if an attempt to insert
- * an element will succeed by inspecting <tt>remainingCapacity</tt>
+ * an element will succeed by inspecting {@code remainingCapacity}
* because it may be the case that another thread is about to
* insert or remove an element.
*/
@@ -234,8 +300,8 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E>
*/
public void put(E e) throws InterruptedException {
if (e == null) throw new NullPointerException();
- // Note: convention in all put/take/etc is to preset
- // local var holding count negative to indicate failure unless set.
+ // 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;
@@ -246,18 +312,13 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E>
* 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.
+ * 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;
+ while (count.get() == capacity) {
+ notFull.await();
}
- insert(e);
+ enqueue(e);
c = count.getAndIncrement();
if (c + 1 < capacity)
notFull.signal();
@@ -272,7 +333,7 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E>
* Inserts the specified element at the tail of this queue, waiting if
* necessary up to the specified wait time for space to become available.
*
- * @return <tt>true</tt> if successful, or <tt>false</tt> if
+ * @return {@code true} if successful, or {@code false} if
* the specified waiting time elapses before space is available.
* @throws InterruptedException {@inheritDoc}
* @throws NullPointerException {@inheritDoc}
@@ -287,23 +348,15 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E>
final AtomicInteger count = this.count;
putLock.lockInterruptibly();
try {
- for (;;) {
- if (count.get() < capacity) {
- insert(e);
- c = count.getAndIncrement();
- if (c + 1 < capacity)
- notFull.signal();
- break;
- }
+ while (count.get() == capacity) {
if (nanos <= 0)
return false;
- try {
- nanos = notFull.awaitNanos(nanos);
- } catch (InterruptedException ie) {
- notFull.signal(); // propagate to a non-interrupted thread
- throw ie;
- }
+ nanos = notFull.awaitNanos(nanos);
}
+ enqueue(e);
+ c = count.getAndIncrement();
+ if (c + 1 < capacity)
+ notFull.signal();
} finally {
putLock.unlock();
}
@@ -315,7 +368,7 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E>
/**
* Inserts the specified element at the tail of this queue if it is
* possible to do so immediately without exceeding the queue's capacity,
- * returning <tt>true</tt> upon success and <tt>false</tt> if this queue
+ * returning {@code true} upon success and {@code false} if this queue
* is full.
* When using a capacity-restricted queue, this method is generally
* preferable to method {@link BlockingQueue#add add}, which can fail to
@@ -333,7 +386,7 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E>
putLock.lock();
try {
if (count.get() < capacity) {
- insert(e);
+ enqueue(e);
c = count.getAndIncrement();
if (c + 1 < capacity)
notFull.signal();
@@ -354,15 +407,10 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E>
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;
+ while (count.get() == 0) {
+ notEmpty.await();
}
-
- x = extract();
+ x = dequeue();
c = count.getAndDecrement();
if (c > 1)
notEmpty.signal();
@@ -382,23 +430,15 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E>
final ReentrantLock takeLock = this.takeLock;
takeLock.lockInterruptibly();
try {
- for (;;) {
- if (count.get() > 0) {
- x = extract();
- c = count.getAndDecrement();
- if (c > 1)
- notEmpty.signal();
- break;
- }
+ while (count.get() == 0) {
if (nanos <= 0)
return null;
- try {
- nanos = notEmpty.awaitNanos(nanos);
- } catch (InterruptedException ie) {
- notEmpty.signal(); // propagate to a non-interrupted thread
- throw ie;
- }
+ nanos = notEmpty.awaitNanos(nanos);
}
+ x = dequeue();
+ c = count.getAndDecrement();
+ if (c > 1)
+ notEmpty.signal();
} finally {
takeLock.unlock();
}
@@ -417,7 +457,7 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E>
takeLock.lock();
try {
if (count.get() > 0) {
- x = extract();
+ x = dequeue();
c = count.getAndDecrement();
if (c > 1)
notEmpty.signal();
@@ -430,7 +470,6 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E>
return x;
}
-
public E peek() {
if (count.get() == 0)
return null;
@@ -448,43 +487,47 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E>
}
/**
+ * Unlinks interior Node p with predecessor trail.
+ */
+ void unlink(Node<E> p, Node<E> trail) {
+ // assert isFullyLocked();
+ // p.next is not changed, to allow iterators that are
+ // traversing p to maintain their weak-consistency guarantee.
+ p.item = null;
+ trail.next = p.next;
+ if (last == p)
+ last = trail;
+ if (count.getAndDecrement() == capacity)
+ notFull.signal();
+ }
+
+ /**
* Removes a single instance of the specified element from this queue,
- * if it is present. More formally, removes an element <tt>e</tt> such
- * that <tt>o.equals(e)</tt>, if this queue contains one or more such
+ * if it is present. More formally, removes an element {@code e} such
+ * that {@code o.equals(e)}, if this queue contains one or more such
* elements.
- * Returns <tt>true</tt> if this queue contained the specified element
+ * Returns {@code true} if this queue contained the specified element
* (or equivalently, if this queue changed as a result of the call).
*
* @param o element to be removed from this queue, if present
- * @return <tt>true</tt> if this queue changed as a result of the call
+ * @return {@code true} if this queue changed as a result of the call
*/
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) {
+ for (Node<E> trail = head, p = trail.next;
+ p != null;
+ trail = p, p = p.next) {
if (o.equals(p.item)) {
- removed = true;
- break;
+ unlink(p, trail);
+ return true;
}
- trail = p;
- p = p.next;
- }
- if (removed) {
- p.item = null;
- trail.next = p.next;
- if (last == p)
- last = trail;
- if (count.getAndDecrement() == capacity)
- notFull.signalAll();
}
+ return false;
} finally {
fullyUnlock();
}
- return removed;
}
/**
@@ -524,22 +567,22 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E>
* <p>If this queue fits in the specified array with room to spare
* (i.e., the array has more elements than this queue), the element in
* the array immediately following the end of the queue is set to
- * <tt>null</tt>.
+ * {@code null}.
*
* <p>Like the {@link #toArray()} method, this method acts as bridge between
* array-based and collection-based APIs. Further, this method allows
* precise control over the runtime type of the output array, and may,
* under certain circumstances, be used to save allocation costs.
*
- * <p>Suppose <tt>x</tt> is a queue known to contain only strings.
+ * <p>Suppose {@code x} is a queue known to contain only strings.
* The following code can be used to dump the queue into a newly
- * allocated array of <tt>String</tt>:
+ * allocated array of {@code String}:
*
* <pre>
* String[] y = x.toArray(new String[0]);</pre>
*
- * Note that <tt>toArray(new Object[0])</tt> is identical in function to
- * <tt>toArray()</tt>.
+ * Note that {@code toArray(new Object[0])} is identical in function to
+ * {@code toArray()}.
*
* @param a the array into which the elements of the queue are to
* be stored, if it is big enough; otherwise, a new array of the
@@ -550,6 +593,7 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E>
* this queue
* @throws NullPointerException if the specified array is null
*/
+ @SuppressWarnings("unchecked")
public <T> T[] toArray(T[] a) {
fullyLock();
try {
@@ -559,7 +603,7 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E>
(a.getClass().getComponentType(), size);
int k = 0;
- for (Node p = head.next; p != null; p = p.next)
+ for (Node<E> p = head.next; p != null; p = p.next)
a[k++] = (T)p.item;
if (a.length > k)
a[k] = null;
@@ -585,11 +629,14 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E>
public void clear() {
fullyLock();
try {
- head.next = null;
- assert head.item == null;
- last = head;
+ for (Node<E> p, h = head; (p = h.next) != null; h = p) {
+ h.next = h;
+ p.item = null;
+ }
+ head = last;
+ // assert head.item == null && head.next == null;
if (count.getAndSet(0) == capacity)
- notFull.signalAll();
+ notFull.signal();
} finally {
fullyUnlock();
}
@@ -602,30 +649,7 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E>
* @throws IllegalArgumentException {@inheritDoc}
*/
public int drainTo(Collection<? super E> c) {
- if (c == null)
- throw new NullPointerException();
- if (c == this)
- throw new IllegalArgumentException();
- Node<E> first;
- fullyLock();
- try {
- first = head.next;
- head.next = null;
- assert head.item == null;
- last = head;
- 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;
+ return drainTo(c, Integer.MAX_VALUE);
}
/**
@@ -639,34 +663,44 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E>
throw new NullPointerException();
if (c == this)
throw new IllegalArgumentException();
- fullyLock();
+ boolean signalNotFull = false;
+ final ReentrantLock takeLock = this.takeLock;
+ takeLock.lock();
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;
- assert head.item == null;
- if (p == null)
- last = head;
- if (count.getAndAdd(-n) == capacity)
- notFull.signalAll();
+ int n = Math.min(maxElements, count.get());
+ // count.get provides visibility to first n Nodes
+ Node<E> h = head;
+ int i = 0;
+ try {
+ while (i < n) {
+ Node<E> p = h.next;
+ c.add(p.item);
+ p.item = null;
+ h.next = h;
+ h = p;
+ ++i;
+ }
+ return n;
+ } finally {
+ // Restore invariants even if c.add() threw
+ if (i > 0) {
+ // assert h.item == null;
+ head = h;
+ signalNotFull = (count.getAndAdd(-i) == capacity);
+ }
}
- return n;
} finally {
- fullyUnlock();
+ takeLock.unlock();
+ if (signalNotFull)
+ signalNotFull();
}
}
/**
* 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 ConcurrentModificationException},
+ * The returned {@code Iterator} is a "weakly consistent" iterator that
+ * will never throw {@link java.util.ConcurrentModificationException
+ * ConcurrentModificationException},
* and guarantees to traverse elements as they existed upon
* construction of the iterator, and may (but is not guaranteed to)
* reflect any modifications subsequent to construction.
@@ -679,7 +713,7 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E>
private class Itr implements Iterator<E> {
/*
- * Basic weak-consistent iterator. At all times hold the next
+ * Basic weakly-consistent iterator. At all times hold the next
* item to hand out so that if hasNext() reports true, we will
* still have it to return even if lost race with a take etc.
*/
@@ -688,17 +722,13 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E>
private E currentElement;
Itr() {
- final ReentrantLock putLock = LinkedBlockingQueue.this.putLock;
- final ReentrantLock takeLock = LinkedBlockingQueue.this.takeLock;
- putLock.lock();
- takeLock.lock();
+ fullyLock();
try {
current = head.next;
if (current != null)
currentElement = current.item;
} finally {
- takeLock.unlock();
- putLock.unlock();
+ fullyUnlock();
}
}
@@ -706,54 +736,56 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E>
return current != null;
}
+ /**
+ * Returns the next live successor of p, or null if no such.
+ *
+ * Unlike other traversal methods, iterators need to handle both:
+ * - dequeued nodes (p.next == p)
+ * - (possibly multiple) interior removed nodes (p.item == null)
+ */
+ private Node<E> nextNode(Node<E> p) {
+ for (;;) {
+ Node<E> s = p.next;
+ if (s == p)
+ return head.next;
+ if (s == null || s.item != null)
+ return s;
+ p = s;
+ }
+ }
+
public E next() {
- final ReentrantLock putLock = LinkedBlockingQueue.this.putLock;
- final ReentrantLock takeLock = LinkedBlockingQueue.this.takeLock;
- putLock.lock();
- takeLock.lock();
+ fullyLock();
try {
if (current == null)
throw new NoSuchElementException();
E x = currentElement;
lastRet = current;
- current = current.next;
- if (current != null)
- currentElement = current.item;
+ current = nextNode(current);
+ currentElement = (current == null) ? null : current.item;
return x;
} finally {
- takeLock.unlock();
- putLock.unlock();
+ fullyUnlock();
}
}
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();
+ fullyLock();
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;
- if (last == p)
- last = trail;
- int c = count.getAndDecrement();
- if (c == capacity)
- notFull.signalAll();
+ for (Node<E> trail = head, p = trail.next;
+ p != null;
+ trail = p, p = p.next) {
+ if (p == node) {
+ unlink(p, trail);
+ break;
+ }
}
} finally {
- takeLock.unlock();
- putLock.unlock();
+ fullyUnlock();
}
}
}
@@ -762,7 +794,7 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E>
* 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,
+ * its elements (each an {@code Object}) in the proper order,
* followed by a null
* @param s the stream
*/
@@ -788,6 +820,7 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E>
/**
* Reconstitute this queue instance from a stream (that is,
* deserialize it).
+ *
* @param s the stream
*/
private void readObject(java.io.ObjectInputStream s)
@@ -800,6 +833,7 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E>
// Read in all elements and place in queue
for (;;) {
+ @SuppressWarnings("unchecked")
E item = (E)s.readObject();
if (item == null)
break;
diff --git a/concurrent/src/main/java/java/util/concurrent/PriorityBlockingQueue.java b/concurrent/src/main/java/java/util/concurrent/PriorityBlockingQueue.java
index 7a33dc7..35d7b89 100644
--- a/concurrent/src/main/java/java/util/concurrent/PriorityBlockingQueue.java
+++ b/concurrent/src/main/java/java/util/concurrent/PriorityBlockingQueue.java
@@ -146,7 +146,6 @@ public class PriorityBlockingQueue<E> extends AbstractQueue<E>
return offer(e);
}
- // BEGIN android-changed
/**
* Inserts the specified element into this priority queue.
*
diff --git a/concurrent/src/main/java/java/util/concurrent/RunnableFuture.java b/concurrent/src/main/java/java/util/concurrent/RunnableFuture.java
new file mode 100644
index 0000000..d74211d
--- /dev/null
+++ b/concurrent/src/main/java/java/util/concurrent/RunnableFuture.java
@@ -0,0 +1,25 @@
+/*
+ * 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 Future} that is {@link Runnable}. Successful execution of
+ * the <tt>run</tt> method causes completion of the <tt>Future</tt>
+ * and allows access to its results.
+ * @see FutureTask
+ * @see Executor
+ * @since 1.6
+ * @author Doug Lea
+ * @param <V> The result type returned by this Future's <tt>get</tt> method
+ */
+public interface RunnableFuture<V> extends Runnable, Future<V> {
+ /**
+ * Sets this Future to the result of its computation
+ * unless it has been cancelled.
+ */
+ void run();
+}
diff --git a/concurrent/src/main/java/java/util/concurrent/RunnableScheduledFuture.java b/concurrent/src/main/java/java/util/concurrent/RunnableScheduledFuture.java
new file mode 100644
index 0000000..0e8cc32
--- /dev/null
+++ b/concurrent/src/main/java/java/util/concurrent/RunnableScheduledFuture.java
@@ -0,0 +1,29 @@
+/*
+ * 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 ScheduledFuture} that is {@link Runnable}. Successful
+ * execution of the <tt>run</tt> method causes completion of the
+ * <tt>Future</tt> and allows access to its results.
+ * @see FutureTask
+ * @see Executor
+ * @since 1.6
+ * @author Doug Lea
+ * @param <V> The result type returned by this Future's <tt>get</tt> method
+ */
+public interface RunnableScheduledFuture<V> extends RunnableFuture<V>, ScheduledFuture<V> {
+
+ /**
+ * Returns true if this is a periodic task. A periodic task may
+ * re-run according to some schedule. A non-periodic task can be
+ * run only once.
+ *
+ * @return true if this task is periodic
+ */
+ boolean isPeriodic();
+}
diff --git a/concurrent/src/main/java/java/util/concurrent/ScheduledThreadPoolExecutor.java b/concurrent/src/main/java/java/util/concurrent/ScheduledThreadPoolExecutor.java
index 83ffb99..7e69936 100644
--- a/concurrent/src/main/java/java/util/concurrent/ScheduledThreadPoolExecutor.java
+++ b/concurrent/src/main/java/java/util/concurrent/ScheduledThreadPoolExecutor.java
@@ -4,10 +4,6 @@
* http://creativecommons.org/licenses/publicdomain
*/
-/*
- * Modified in Apache Harmony.
- */
-
package java.util.concurrent;
import java.util.concurrent.atomic.*;
import java.util.concurrent.locks.*;
@@ -27,6 +23,15 @@ import java.util.*;
* execution time are enabled in first-in-first-out (FIFO) order of
* submission.
*
+ * <p>When a submitted task is cancelled before it is run, execution
+ * is suppressed. By default, such a cancelled task is not
+ * automatically removed from the work queue until its delay
+ * elapses. While this enables further inspection and monitoring, it
+ * may also cause unbounded retention of cancelled tasks. To avoid
+ * this, set {@link #setRemoveOnCancelPolicy} to {@code true}, which
+ * causes tasks to be immediately removed from the work queue at
+ * time of cancellation.
+ *
* <p>Successive executions of a task scheduled via
* <code>scheduleAtFixedRate</code> or
* <code>scheduleWithFixedDelay</code> do not overlap. While different
@@ -37,9 +42,47 @@ import java.util.*;
*
* <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 {@code
- * corePoolSize} threads and an unbounded queue, adjustments to {@code
- * maximumPoolSize} have no useful effect.
+ * particular, because it acts as a fixed-sized pool using
+ * {@code corePoolSize} threads and an unbounded queue, adjustments
+ * to {@code maximumPoolSize} have no useful effect. Additionally, it
+ * is almost never a good idea to set {@code corePoolSize} to zero or
+ * use {@code allowCoreThreadTimeOut} because this may leave the pool
+ * without threads to handle tasks once they become eligible to run.
+ *
+ * <p><b>Extension notes:</b> This class overrides the
+ * {@link ThreadPoolExecutor#execute execute} and
+ * {@link AbstractExecutorService#submit(Runnable) submit}
+ * methods to generate internal {@link ScheduledFuture} objects to
+ * control per-task delays and scheduling. To preserve
+ * functionality, any further overrides of these methods in
+ * subclasses must invoke superclass versions, which effectively
+ * disables additional task customization. However, this class
+ * provides alternative protected extension method
+ * {@code decorateTask} (one version each for {@code Runnable} and
+ * {@code Callable}) that can be used to customize the concrete task
+ * types used to execute commands entered via {@code execute},
+ * {@code submit}, {@code schedule}, {@code scheduleAtFixedRate},
+ * and {@code scheduleWithFixedDelay}. By default, a
+ * {@code ScheduledThreadPoolExecutor} uses a task type extending
+ * {@link FutureTask}. However, this may be modified or replaced using
+ * subclasses of the form:
+ *
+ * <pre> {@code
+ * public class CustomScheduledExecutor extends ScheduledThreadPoolExecutor {
+ *
+ * static class CustomTask<V> implements RunnableScheduledFuture<V> { ... }
+ *
+ * protected <V> RunnableScheduledFuture<V> decorateTask(
+ * Runnable r, RunnableScheduledFuture<V> task) {
+ * return new CustomTask<V>(r, task);
+ * }
+ *
+ * protected <V> RunnableScheduledFuture<V> decorateTask(
+ * Callable<V> c, RunnableScheduledFuture<V> task) {
+ * return new CustomTask<V>(c, task);
+ * }
+ * // ... add constructors, etc.
+ * }}</pre>
*
* @since 1.5
* @author Doug Lea
@@ -96,23 +139,15 @@ public class ScheduledThreadPoolExecutor
*/
private static final AtomicLong sequencer = new AtomicLong(0);
-
- /**
- * Value of System.nanoTime upon static initialization. This is
- * used as an offset by now() to avoid wraparound of time values
- * that would make them appear negative.
- */
- static final long initialNanoTime = System.nanoTime();
-
/**
* Returns current nanosecond time.
*/
- static long now() {
- return System.nanoTime() - initialNanoTime;
+ final long now() {
+ return System.nanoTime();
}
private class ScheduledFutureTask<V>
- extends FutureTask<V> implements ScheduledFuture<V> {
+ extends FutureTask<V> implements RunnableScheduledFuture<V> {
/** Sequence number to break ties FIFO */
private final long sequenceNumber;
@@ -129,7 +164,7 @@ public class ScheduledThreadPoolExecutor
private final long period;
/** The actual task to be re-enqueued by reExecutePeriodic */
- ScheduledFutureTask<V> outerTask = this;
+ RunnableScheduledFuture<V> outerTask = this;
/**
* Index into delay queue, to support faster cancellation.
@@ -167,8 +202,7 @@ public class ScheduledThreadPoolExecutor
}
public long getDelay(TimeUnit unit) {
- long d = time - now();
- return d<=0? 0 : unit.convert(d, TimeUnit.NANOSECONDS);
+ return unit.convert(time - now(), TimeUnit.NANOSECONDS);
}
public int compareTo(Delayed other) {
@@ -208,7 +242,7 @@ public class ScheduledThreadPoolExecutor
if (p > 0)
time += p;
else
- time = now() - p;
+ time = triggerTime(-p);
}
public boolean cancel(boolean mayInterruptIfRunning) {
@@ -257,7 +291,7 @@ public class ScheduledThreadPoolExecutor
*
* @param task the task
*/
- private void delayedExecute(ScheduledFutureTask<?> task) {
+ private void delayedExecute(RunnableScheduledFuture<?> task) {
if (isShutdown())
reject(task);
else {
@@ -277,7 +311,7 @@ public class ScheduledThreadPoolExecutor
*
* @param task the task
*/
- void reExecutePeriodic(ScheduledFutureTask<?> task) {
+ void reExecutePeriodic(RunnableScheduledFuture<?> task) {
if (canRunInCurrentRunState(true)) {
super.getQueue().add(task);
if (!canRunInCurrentRunState(true) && remove(task))
@@ -302,9 +336,9 @@ public class ScheduledThreadPoolExecutor
else {
// Traverse snapshot to avoid iterator exceptions
for (Object e : q.toArray()) {
- if (e instanceof ScheduledFutureTask) {
- ScheduledFutureTask<?> t =
- (ScheduledFutureTask<?>)e;
+ if (e instanceof RunnableScheduledFuture) {
+ RunnableScheduledFuture<?> t =
+ (RunnableScheduledFuture<?>)e;
if ((t.isPeriodic() ? !keepPeriodic : !keepDelayed) ||
t.isCancelled()) { // also remove if already cancelled
if (q.remove(t))
@@ -317,11 +351,43 @@ public class ScheduledThreadPoolExecutor
}
/**
+ * Modifies or replaces the task used to execute a runnable.
+ * This method can be used to override the concrete
+ * class used for managing internal tasks.
+ * The default implementation simply returns the given task.
+ *
+ * @param runnable the submitted Runnable
+ * @param task the task created to execute the runnable
+ * @return a task that can execute the runnable
+ * @since 1.6
+ */
+ protected <V> RunnableScheduledFuture<V> decorateTask(
+ Runnable runnable, RunnableScheduledFuture<V> task) {
+ return task;
+ }
+
+ /**
+ * Modifies or replaces the task used to execute a callable.
+ * This method can be used to override the concrete
+ * class used for managing internal tasks.
+ * The default implementation simply returns the given task.
+ *
+ * @param callable the submitted Callable
+ * @param task the task created to execute the callable
+ * @return a task that can execute the callable
+ * @since 1.6
+ */
+ protected <V> RunnableScheduledFuture<V> decorateTask(
+ Callable<V> callable, RunnableScheduledFuture<V> task) {
+ return task;
+ }
+
+ /**
* Creates a new {@code ScheduledThreadPoolExecutor} with the
* given core pool size.
*
* @param corePoolSize the number of threads to keep in the pool, even
- * if they are idle
+ * if they are idle, unless {@code allowCoreThreadTimeOut} is set
* @throws IllegalArgumentException if {@code corePoolSize < 0}
*/
public ScheduledThreadPoolExecutor(int corePoolSize) {
@@ -334,7 +400,7 @@ public class ScheduledThreadPoolExecutor
* given initial parameters.
*
* @param corePoolSize the number of threads to keep in the pool, even
- * if they are idle
+ * if they are idle, unless {@code allowCoreThreadTimeOut} is set
* @param threadFactory the factory to use when the executor
* creates a new thread
* @throws IllegalArgumentException if {@code corePoolSize < 0}
@@ -351,7 +417,7 @@ public class ScheduledThreadPoolExecutor
* initial parameters.
*
* @param corePoolSize the number of threads to keep in the pool, even
- * if they are idle
+ * if they are idle, unless {@code allowCoreThreadTimeOut} is set
* @param handler the handler to use when execution is blocked
* because the thread bounds and queue capacities are reached
* @throws IllegalArgumentException if {@code corePoolSize < 0}
@@ -368,7 +434,7 @@ public class ScheduledThreadPoolExecutor
* initial parameters.
*
* @param corePoolSize the number of threads to keep in the pool, even
- * if they are idle
+ * if they are idle, unless {@code allowCoreThreadTimeOut} is set
* @param threadFactory the factory to use when the executor
* creates a new thread
* @param handler the handler to use when execution is blocked
@@ -385,17 +451,35 @@ public class ScheduledThreadPoolExecutor
}
/**
- * Returns the trigger time of a delayed action
+ * Returns the trigger time of a delayed action.
*/
- private static long nextTriggerTime(long delay, TimeUnit unit) {
- long triggerTime;
- long now = now();
- if (delay <= 0)
- return now; // avoid negative trigger times
- else if ((triggerTime = now + unit.toNanos(delay)) < 0)
- return Long.MAX_VALUE; // avoid numerical overflow
- else
- return triggerTime;
+ private long triggerTime(long delay, TimeUnit unit) {
+ return triggerTime(unit.toNanos((delay < 0) ? 0 : delay));
+ }
+
+ /**
+ * Returns the trigger time of a delayed action.
+ */
+ long triggerTime(long delay) {
+ return now() +
+ ((delay < (Long.MAX_VALUE >> 1)) ? delay : overflowFree(delay));
+ }
+
+ /**
+ * Constrains the values of all delays in the queue to be within
+ * Long.MAX_VALUE of each other, to avoid overflow in compareTo.
+ * This may occur if a task is eligible to be dequeued, but has
+ * not yet been, while some other task is added with a delay of
+ * Long.MAX_VALUE.
+ */
+ private long overflowFree(long delay) {
+ Delayed head = (Delayed) super.getQueue().peek();
+ if (head != null) {
+ long headDelay = head.getDelay(TimeUnit.NANOSECONDS);
+ if (headDelay < 0 && (delay - headDelay < 0))
+ delay = Long.MAX_VALUE + headDelay;
+ }
+ return delay;
}
/**
@@ -407,9 +491,9 @@ public class ScheduledThreadPoolExecutor
TimeUnit unit) {
if (command == null || unit == null)
throw new NullPointerException();
- long triggerTime = nextTriggerTime(delay, unit);
- ScheduledFutureTask<?> t
- = new ScheduledFutureTask<Void>(command, null, triggerTime);
+ RunnableScheduledFuture<?> t = decorateTask(command,
+ new ScheduledFutureTask<Void>(command, null,
+ triggerTime(delay, unit)));
delayedExecute(t);
return t;
}
@@ -423,9 +507,9 @@ public class ScheduledThreadPoolExecutor
TimeUnit unit) {
if (callable == null || unit == null)
throw new NullPointerException();
- long triggerTime = nextTriggerTime(delay, unit);
- ScheduledFutureTask<V> t
- = new ScheduledFutureTask<V>(callable, triggerTime);
+ RunnableScheduledFuture<V> t = decorateTask(callable,
+ new ScheduledFutureTask<V>(callable,
+ triggerTime(delay, unit)));
delayedExecute(t);
return t;
}
@@ -443,16 +527,15 @@ public class ScheduledThreadPoolExecutor
throw new NullPointerException();
if (period <= 0)
throw new IllegalArgumentException();
- if (initialDelay < 0) initialDelay = 0;
- long triggerTime = nextTriggerTime(initialDelay, unit);
ScheduledFutureTask<Void> sft =
new ScheduledFutureTask<Void>(command,
null,
- triggerTime,
+ triggerTime(initialDelay, unit),
unit.toNanos(period));
- sft.outerTask = sft;
- delayedExecute(sft);
- return sft;
+ RunnableScheduledFuture<Void> t = decorateTask(command, sft);
+ sft.outerTask = t;
+ delayedExecute(t);
+ return t;
}
/**
@@ -468,15 +551,15 @@ public class ScheduledThreadPoolExecutor
throw new NullPointerException();
if (delay <= 0)
throw new IllegalArgumentException();
- long triggerTime = nextTriggerTime(initialDelay, unit);
ScheduledFutureTask<Void> sft =
new ScheduledFutureTask<Void>(command,
null,
- triggerTime,
+ triggerTime(initialDelay, unit),
unit.toNanos(-delay));
- sft.outerTask = sft;
- delayedExecute(sft);
- return sft;
+ RunnableScheduledFuture<Void> t = decorateTask(command, sft);
+ sft.outerTask = t;
+ delayedExecute(t);
+ return t;
}
/**
@@ -595,6 +678,33 @@ public class ScheduledThreadPoolExecutor
}
/**
+ * Sets the policy on whether cancelled tasks should be immediately
+ * removed from the work queue at time of cancellation. This value is
+ * by default {@code false}.
+ *
+ * @param value if {@code true}, remove on cancellation, else don't
+ * @see #getRemoveOnCancelPolicy
+ * @since 1.7
+ */
+ /*public*/ void setRemoveOnCancelPolicy(boolean value) { // android-changed
+ removeOnCancel = value;
+ }
+
+ /**
+ * Gets the policy on whether cancelled tasks should be immediately
+ * removed from the work queue at time of cancellation. This value is
+ * by default {@code false}.
+ *
+ * @return {@code true} if cancelled tasks are immediately removed
+ * from the queue
+ * @see #setRemoveOnCancelPolicy
+ * @since 1.7
+ */
+ /*public*/ boolean getRemoveOnCancelPolicy() { // android-changed
+ return removeOnCancel;
+ }
+
+ /**
* Initiates an orderly shutdown in which previously submitted
* tasks are executed, but no new tasks will be accepted.
* Invocation has no additional effect if already shut down.
@@ -688,8 +798,8 @@ public class ScheduledThreadPoolExecutor
*/
private static final int INITIAL_CAPACITY = 16;
- private ScheduledFutureTask[] queue =
- new ScheduledFutureTask[INITIAL_CAPACITY];
+ private RunnableScheduledFuture[] queue =
+ new RunnableScheduledFuture[INITIAL_CAPACITY];
private final ReentrantLock lock = new ReentrantLock();
private int size = 0;
@@ -720,7 +830,7 @@ public class ScheduledThreadPoolExecutor
/**
* Set f's heapIndex if it is a ScheduledFutureTask.
*/
- private void setIndex(ScheduledFutureTask f, int idx) {
+ private void setIndex(RunnableScheduledFuture f, int idx) {
if (f instanceof ScheduledFutureTask)
((ScheduledFutureTask)f).heapIndex = idx;
}
@@ -729,10 +839,10 @@ public class ScheduledThreadPoolExecutor
* Sift element added at bottom up to its heap-ordered spot.
* Call only when holding lock.
*/
- private void siftUp(int k, ScheduledFutureTask key) {
+ private void siftUp(int k, RunnableScheduledFuture key) {
while (k > 0) {
int parent = (k - 1) >>> 1;
- ScheduledFutureTask e = queue[parent];
+ RunnableScheduledFuture e = queue[parent];
if (key.compareTo(e) >= 0)
break;
queue[k] = e;
@@ -747,11 +857,11 @@ public class ScheduledThreadPoolExecutor
* Sift element added at top down to its heap-ordered spot.
* Call only when holding lock.
*/
- private void siftDown(int k, ScheduledFutureTask key) {
+ private void siftDown(int k, RunnableScheduledFuture key) {
int half = size >>> 1;
while (k < half) {
int child = (k << 1) + 1;
- ScheduledFutureTask c = queue[child];
+ RunnableScheduledFuture c = queue[child];
int right = child + 1;
if (right < size && c.compareTo(queue[right]) > 0)
c = queue[child = right];
@@ -773,7 +883,7 @@ public class ScheduledThreadPoolExecutor
int newCapacity = oldCapacity + (oldCapacity >> 1); // grow 50%
if (newCapacity < 0) // overflow
newCapacity = Integer.MAX_VALUE;
- queue = Java6Arrays.copyOf(queue, newCapacity);
+ queue = Arrays.copyOf(queue, newCapacity);
}
/**
@@ -816,7 +926,7 @@ public class ScheduledThreadPoolExecutor
setIndex(queue[i], -1);
int s = --size;
- ScheduledFutureTask replacement = queue[s];
+ RunnableScheduledFuture replacement = queue[s];
queue[s] = null;
if (s != i) {
siftDown(i, replacement);
@@ -847,7 +957,7 @@ public class ScheduledThreadPoolExecutor
return Integer.MAX_VALUE;
}
- public ScheduledFutureTask peek() {
+ public RunnableScheduledFuture peek() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
@@ -860,7 +970,7 @@ public class ScheduledThreadPoolExecutor
public boolean offer(Runnable x) {
if (x == null)
throw new NullPointerException();
- ScheduledFutureTask e = (ScheduledFutureTask)x;
+ RunnableScheduledFuture e = (RunnableScheduledFuture)x;
final ReentrantLock lock = this.lock;
lock.lock();
try {
@@ -902,9 +1012,9 @@ public class ScheduledThreadPoolExecutor
* holding lock.
* @param f the task to remove and return
*/
- private ScheduledFutureTask finishPoll(ScheduledFutureTask f) {
+ private RunnableScheduledFuture finishPoll(RunnableScheduledFuture f) {
int s = --size;
- ScheduledFutureTask x = queue[s];
+ RunnableScheduledFuture x = queue[s];
queue[s] = null;
if (s != 0)
siftDown(0, x);
@@ -912,11 +1022,11 @@ public class ScheduledThreadPoolExecutor
return f;
}
- public ScheduledFutureTask poll() {
+ public RunnableScheduledFuture poll() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
- ScheduledFutureTask first = queue[0];
+ RunnableScheduledFuture first = queue[0];
if (first == null || first.getDelay(TimeUnit.NANOSECONDS) > 0)
return null;
else
@@ -926,12 +1036,12 @@ public class ScheduledThreadPoolExecutor
}
}
- public ScheduledFutureTask take() throws InterruptedException {
+ public RunnableScheduledFuture take() throws InterruptedException {
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
for (;;) {
- ScheduledFutureTask first = queue[0];
+ RunnableScheduledFuture first = queue[0];
if (first == null)
available.await();
else {
@@ -959,14 +1069,14 @@ public class ScheduledThreadPoolExecutor
}
}
- public ScheduledFutureTask poll(long timeout, TimeUnit unit)
+ public RunnableScheduledFuture poll(long timeout, TimeUnit unit)
throws InterruptedException {
long nanos = unit.toNanos(timeout);
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
for (;;) {
- ScheduledFutureTask first = queue[0];
+ RunnableScheduledFuture first = queue[0];
if (first == null) {
if (nanos <= 0)
return null;
@@ -1005,7 +1115,7 @@ public class ScheduledThreadPoolExecutor
lock.lock();
try {
for (int i = 0; i < size; i++) {
- ScheduledFutureTask t = queue[i];
+ RunnableScheduledFuture t = queue[i];
if (t != null) {
queue[i] = null;
setIndex(t, -1);
@@ -1021,8 +1131,8 @@ public class ScheduledThreadPoolExecutor
* Return and remove first element only if it is expired.
* Used only by drainTo. Call only when holding lock.
*/
- private ScheduledFutureTask pollExpired() {
- ScheduledFutureTask first = queue[0];
+ private RunnableScheduledFuture pollExpired() {
+ RunnableScheduledFuture first = queue[0];
if (first == null || first.getDelay(TimeUnit.NANOSECONDS) > 0)
return null;
return finishPoll(first);
@@ -1036,7 +1146,7 @@ public class ScheduledThreadPoolExecutor
final ReentrantLock lock = this.lock;
lock.lock();
try {
- ScheduledFutureTask first;
+ RunnableScheduledFuture first;
int n = 0;
while ((first = pollExpired()) != null) {
c.add(first);
@@ -1058,7 +1168,7 @@ public class ScheduledThreadPoolExecutor
final ReentrantLock lock = this.lock;
lock.lock();
try {
- ScheduledFutureTask first;
+ RunnableScheduledFuture first;
int n = 0;
while (n < maxElements && (first = pollExpired()) != null) {
c.add(first);
@@ -1074,7 +1184,7 @@ public class ScheduledThreadPoolExecutor
final ReentrantLock lock = this.lock;
lock.lock();
try {
- return Java6Arrays.copyOf(queue, size, Object[].class);
+ return Arrays.copyOf(queue, size, Object[].class);
} finally {
lock.unlock();
}
@@ -1086,7 +1196,7 @@ public class ScheduledThreadPoolExecutor
lock.lock();
try {
if (a.length < size)
- return (T[]) Java6Arrays.copyOf(queue, size, a.getClass());
+ return (T[]) Arrays.copyOf(queue, size, a.getClass());
System.arraycopy(queue, 0, a, 0, size);
if (a.length > size)
a[size] = null;
@@ -1097,18 +1207,18 @@ public class ScheduledThreadPoolExecutor
}
public Iterator<Runnable> iterator() {
- return new Itr(Java6Arrays.copyOf(queue, size));
+ return new Itr(Arrays.copyOf(queue, size));
}
/**
* Snapshot iterator that works off copy of underlying q array.
*/
private class Itr implements Iterator<Runnable> {
- final ScheduledFutureTask[] array;
+ final RunnableScheduledFuture[] array;
int cursor = 0; // index of next element to return
int lastRet = -1; // index of last element, or -1 if no such
- Itr(ScheduledFutureTask[] array) {
+ Itr(RunnableScheduledFuture[] array) {
this.array = array;
}
diff --git a/concurrent/src/main/java/java/util/concurrent/Semaphore.java b/concurrent/src/main/java/java/util/concurrent/Semaphore.java
index 1052364..1f5c00e 100644
--- a/concurrent/src/main/java/java/util/concurrent/Semaphore.java
+++ b/concurrent/src/main/java/java/util/concurrent/Semaphore.java
@@ -212,10 +212,8 @@ public class Semaphore implements java.io.Serializable {
}
protected int tryAcquireShared(int acquires) {
- Thread current = Thread.currentThread();
for (;;) {
- Thread first = getFirstQueuedThread();
- if (first != null && first != current)
+ if (hasQueuedPredecessors())
return -1;
int available = getState();
int remaining = available - acquires;
diff --git a/concurrent/src/main/java/java/util/concurrent/SynchronousQueue.java b/concurrent/src/main/java/java/util/concurrent/SynchronousQueue.java
index 0d297ff..5f9e8d7 100644
--- a/concurrent/src/main/java/java/util/concurrent/SynchronousQueue.java
+++ b/concurrent/src/main/java/java/util/concurrent/SynchronousQueue.java
@@ -419,9 +419,9 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
else if (s.waiter == null)
s.waiter = w; // establish waiter so can park next iter
else if (!timed)
- LockSupport.park();
+ LockSupport.park(this);
else if (nanos > spinForTimeoutThreshold)
- LockSupport.parkNanos(nanos);
+ LockSupport.parkNanos(this, nanos);
}
}
@@ -711,9 +711,9 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
else if (s.waiter == null)
s.waiter = w;
else if (!timed)
- LockSupport.park();
+ LockSupport.park(this);
else if (nanos > spinForTimeoutThreshold)
- LockSupport.parkNanos(nanos);
+ LockSupport.parkNanos(this, nanos);
}
}
@@ -991,19 +991,6 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
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>.
@@ -1011,7 +998,7 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
* @return an empty iterator
*/
public Iterator<E> iterator() {
- return new EmptyIterator<E>();
+ return Collections.<E>emptySet().iterator(); // android-changed
}
/**
diff --git a/concurrent/src/main/java/java/util/concurrent/ThreadPoolExecutor.java b/concurrent/src/main/java/java/util/concurrent/ThreadPoolExecutor.java
index d0c934d..c362c99 100644
--- a/concurrent/src/main/java/java/util/concurrent/ThreadPoolExecutor.java
+++ b/concurrent/src/main/java/java/util/concurrent/ThreadPoolExecutor.java
@@ -92,9 +92,12 @@ import java.util.*;
* threads will be constructed. This parameter can also be changed
* dynamically using method {@link #setKeepAliveTime}. Using a value
* of {@code Long.MAX_VALUE} {@link TimeUnit#NANOSECONDS} effectively
- * disables idle threads from ever terminating prior to shut down. The
- * keep-alive policy applies only when there are more than
- * corePoolSizeThreads.</dd>
+ * disables idle threads from ever terminating prior to shut down. By
+ * default, the keep-alive policy applies only when there are more
+ * than corePoolSizeThreads. But method {@link
+ * #allowCoreThreadTimeOut(boolean)} can be used to apply this
+ * time-out policy to core threads as well, so long as the
+ * keepAliveTime value is non-zero. </dd>
*
* <dt>Queuing</dt>
*
@@ -228,7 +231,8 @@ import java.util.*;
* you would like to ensure that unreferenced pools are reclaimed even
* if users forget to call {@link #shutdown}, then you must arrange
* that unused threads eventually die, by setting appropriate
- * keep-alive times using a lower bound of zero core threads. </dd>
+ * keep-alive times, using a lower bound of zero core threads and/or
+ * setting {@link #allowCoreThreadTimeOut(boolean)}. </dd>
*
* </dl>
*
@@ -473,13 +477,22 @@ public class ThreadPoolExecutor extends AbstractExecutorService {
/**
* Timeout in nanoseconds for idle threads waiting for work.
* Threads use this timeout when there are more than corePoolSize
- * present. Otherwise they wait forever for new work.
+ * present or if allowCoreThreadTimeOut. Otherwise they wait
+ * forever for new work.
*/
private volatile long keepAliveTime;
/**
+ * If false (default), core threads stay alive even when idle.
+ * If true, core threads use keepAliveTime to time out waiting
+ * for work.
+ */
+ private volatile boolean allowCoreThreadTimeOut;
+
+ /**
* Core pool size is the minimum number of workers to keep alive
- * (and not allow to time out etc).
+ * (and not allow to time out etc) unless allowCoreThreadTimeOut
+ * is set, in which case the minimum is zero.
*/
private volatile int corePoolSize;
@@ -941,7 +954,7 @@ public class ThreadPoolExecutor extends AbstractExecutorService {
int c = ctl.get();
if (runStateLessThan(c, STOP)) {
if (!completedAbruptly) {
- int min = corePoolSize;
+ int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
if (min == 0 && ! workQueue.isEmpty())
min = 1;
if (workerCountOf(c) >= min)
@@ -961,7 +974,7 @@ public class ThreadPoolExecutor extends AbstractExecutorService {
* 3. The pool is shutdown and the queue is empty.
* 4. This worker timed out waiting for a task, and timed-out
* workers are subject to termination (that is,
- * {@code workerCount > corePoolSize})
+ * {@code allowCoreThreadTimeOut || workerCount > corePoolSize})
* both before and after the timed wait.
*
* @return task, or null if the worker must exit, in which case
@@ -985,7 +998,7 @@ public class ThreadPoolExecutor extends AbstractExecutorService {
for (;;) {
int wc = workerCountOf(c);
- timed = wc > corePoolSize;
+ timed = allowCoreThreadTimeOut || wc > corePoolSize;
if (wc <= maximumPoolSize && ! (timedOut && timed))
break;
@@ -1096,7 +1109,7 @@ public class ThreadPoolExecutor extends AbstractExecutorService {
* methods instead of this general purpose constructor.
*
* @param corePoolSize the number of threads to keep in the pool, even
- * if they are idle
+ * if they are idle, unless {@code allowCoreThreadTimeOut} is set
* @param maximumPoolSize the maximum number of threads to allow in the
* pool
* @param keepAliveTime when the number of threads is greater than
@@ -1127,7 +1140,7 @@ public class ThreadPoolExecutor extends AbstractExecutorService {
* parameters and default rejected execution handler.
*
* @param corePoolSize the number of threads to keep in the pool, even
- * if they are idle
+ * if they are idle, unless {@code allowCoreThreadTimeOut} is set
* @param maximumPoolSize the maximum number of threads to allow in the
* pool
* @param keepAliveTime when the number of threads is greater than
@@ -1162,7 +1175,7 @@ public class ThreadPoolExecutor extends AbstractExecutorService {
* parameters and default thread factory.
*
* @param corePoolSize the number of threads to keep in the pool, even
- * if they are idle
+ * if they are idle, unless {@code allowCoreThreadTimeOut} is set
* @param maximumPoolSize the maximum number of threads to allow in the
* pool
* @param keepAliveTime when the number of threads is greater than
@@ -1197,7 +1210,7 @@ public class ThreadPoolExecutor extends AbstractExecutorService {
* parameters.
*
* @param corePoolSize the number of threads to keep in the pool, even
- * if they are idle
+ * if they are idle, unless {@code allowCoreThreadTimeOut} is set
* @param maximumPoolSize the maximum number of threads to allow in the
* pool
* @param keepAliveTime when the number of threads is greater than
@@ -1518,6 +1531,50 @@ public class ThreadPoolExecutor extends AbstractExecutorService {
}
/**
+ * Returns true if this pool allows core threads to time out and
+ * terminate if no tasks arrive within the keepAlive time, being
+ * replaced if needed when new tasks arrive. When true, the same
+ * keep-alive policy applying to non-core threads applies also to
+ * core threads. When false (the default), core threads are never
+ * terminated due to lack of incoming tasks.
+ *
+ * @return {@code true} if core threads are allowed to time out,
+ * else {@code false}
+ *
+ * @since 1.6
+ */
+ public boolean allowsCoreThreadTimeOut() {
+ return allowCoreThreadTimeOut;
+ }
+
+ /**
+ * Sets the policy governing whether core threads may time out and
+ * terminate if no tasks arrive within the keep-alive time, being
+ * replaced if needed when new tasks arrive. When false, core
+ * threads are never terminated due to lack of incoming
+ * tasks. When true, the same keep-alive policy applying to
+ * non-core threads applies also to core threads. To avoid
+ * continual thread replacement, the keep-alive time must be
+ * greater than zero when setting {@code true}. This method
+ * should in general be called before the pool is actively used.
+ *
+ * @param value {@code true} if should time out, else {@code false}
+ * @throws IllegalArgumentException if value is {@code true}
+ * and the current keep-alive time is not greater than zero
+ *
+ * @since 1.6
+ */
+ public void allowCoreThreadTimeOut(boolean value) {
+ if (value && keepAliveTime <= 0)
+ throw new IllegalArgumentException("Core threads must have nonzero keep alive times");
+ if (value != allowCoreThreadTimeOut) {
+ allowCoreThreadTimeOut = value;
+ if (value)
+ interruptIdleWorkers();
+ }
+ }
+
+ /**
* Sets the maximum allowed number of threads. This overrides any
* value set in the constructor. If the new value is smaller than
* the current value, excess existing threads will be
@@ -1564,6 +1621,8 @@ public class ThreadPoolExecutor extends AbstractExecutorService {
public void setKeepAliveTime(long time, TimeUnit unit) {
if (time < 0)
throw new IllegalArgumentException();
+ if (time == 0 && allowsCoreThreadTimeOut())
+ throw new IllegalArgumentException("Core threads must have nonzero keep alive times");
long keepAliveTime = unit.toNanos(time);
long delta = keepAliveTime - this.keepAliveTime;
this.keepAliveTime = keepAliveTime;
diff --git a/concurrent/src/main/java/java/util/concurrent/TimeUnit.java b/concurrent/src/main/java/java/util/concurrent/TimeUnit.java
index 412d28a..ae78fda 100644
--- a/concurrent/src/main/java/java/util/concurrent/TimeUnit.java
+++ b/concurrent/src/main/java/java/util/concurrent/TimeUnit.java
@@ -40,7 +40,6 @@ package java.util.concurrent;
* @author Doug Lea
*/
public enum TimeUnit {
- /** TimeUnit which represents one nanosecond. */
NANOSECONDS {
public long toNanos(long d) { return d; }
public long toMicros(long d) { return d/(C1/C0); }
@@ -52,7 +51,6 @@ public enum TimeUnit {
public long convert(long d, TimeUnit u) { return u.toNanos(d); }
int excessNanos(long d, long m) { return (int)(d - (m*C2)); }
},
- /** TimeUnit which represents one microsecond. */
MICROSECONDS {
public long toNanos(long d) { return x(d, C1/C0, MAX/(C1/C0)); }
public long toMicros(long d) { return d; }
@@ -64,7 +62,6 @@ public enum TimeUnit {
public long convert(long d, TimeUnit u) { return u.toMicros(d); }
int excessNanos(long d, long m) { return (int)((d*C1) - (m*C2)); }
},
- /** TimeUnit which represents one millisecond. */
MILLISECONDS {
public long toNanos(long d) { return x(d, C2/C0, MAX/(C2/C0)); }
public long toMicros(long d) { return x(d, C2/C1, MAX/(C2/C1)); }
@@ -76,7 +73,6 @@ public enum TimeUnit {
public long convert(long d, TimeUnit u) { return u.toMillis(d); }
int excessNanos(long d, long m) { return 0; }
},
- /** TimeUnit which represents one second. */
SECONDS {
public long toNanos(long d) { return x(d, C3/C0, MAX/(C3/C0)); }
public long toMicros(long d) { return x(d, C3/C1, MAX/(C3/C1)); }
@@ -87,6 +83,39 @@ public enum TimeUnit {
public long toDays(long d) { return d/(C6/C3); }
public long convert(long d, TimeUnit u) { return u.toSeconds(d); }
int excessNanos(long d, long m) { return 0; }
+ },
+ MINUTES {
+ public long toNanos(long d) { return x(d, C4/C0, MAX/(C4/C0)); }
+ public long toMicros(long d) { return x(d, C4/C1, MAX/(C4/C1)); }
+ public long toMillis(long d) { return x(d, C4/C2, MAX/(C4/C2)); }
+ public long toSeconds(long d) { return x(d, C4/C3, MAX/(C4/C3)); }
+ public long toMinutes(long d) { return d; }
+ public long toHours(long d) { return d/(C5/C4); }
+ public long toDays(long d) { return d/(C6/C4); }
+ public long convert(long d, TimeUnit u) { return u.toMinutes(d); }
+ int excessNanos(long d, long m) { return 0; }
+ },
+ HOURS {
+ public long toNanos(long d) { return x(d, C5/C0, MAX/(C5/C0)); }
+ public long toMicros(long d) { return x(d, C5/C1, MAX/(C5/C1)); }
+ public long toMillis(long d) { return x(d, C5/C2, MAX/(C5/C2)); }
+ public long toSeconds(long d) { return x(d, C5/C3, MAX/(C5/C3)); }
+ public long toMinutes(long d) { return x(d, C5/C4, MAX/(C5/C4)); }
+ public long toHours(long d) { return d; }
+ public long toDays(long d) { return d/(C6/C5); }
+ public long convert(long d, TimeUnit u) { return u.toHours(d); }
+ int excessNanos(long d, long m) { return 0; }
+ },
+ DAYS {
+ public long toNanos(long d) { return x(d, C6/C0, MAX/(C6/C0)); }
+ public long toMicros(long d) { return x(d, C6/C1, MAX/(C6/C1)); }
+ public long toMillis(long d) { return x(d, C6/C2, MAX/(C6/C2)); }
+ public long toSeconds(long d) { return x(d, C6/C3, MAX/(C6/C3)); }
+ public long toMinutes(long d) { return x(d, C6/C4, MAX/(C6/C4)); }
+ public long toHours(long d) { return x(d, C6/C5, MAX/(C6/C5)); }
+ public long toDays(long d) { return d; }
+ public long convert(long d, TimeUnit u) { return u.toDays(d); }
+ int excessNanos(long d, long m) { return 0; }
};
// Handy constants for conversion methods
@@ -193,8 +222,9 @@ public enum TimeUnit {
* or <tt>Long.MIN_VALUE</tt> if conversion would negatively
* overflow, or <tt>Long.MAX_VALUE</tt> if it would positively overflow.
* @see #convert
+ * @since 1.6
*/
- long toMinutes(long duration) {
+ public long toMinutes(long duration) {
throw new AbstractMethodError();
}
@@ -205,8 +235,9 @@ public enum TimeUnit {
* or <tt>Long.MIN_VALUE</tt> if conversion would negatively
* overflow, or <tt>Long.MAX_VALUE</tt> if it would positively overflow.
* @see #convert
+ * @since 1.6
*/
- long toHours(long duration) {
+ public long toHours(long duration) {
throw new AbstractMethodError();
}
@@ -215,8 +246,9 @@ public enum TimeUnit {
* @param duration the duration
* @return the converted duration
* @see #convert
+ * @since 1.6
*/
- long toDays(long duration) {
+ public long toDays(long duration) {
throw new AbstractMethodError();
}
diff --git a/concurrent/src/main/java/java/util/concurrent/atomic/AtomicBoolean.java b/concurrent/src/main/java/java/util/concurrent/atomic/AtomicBoolean.java
index ba60556..c774d21 100644
--- a/concurrent/src/main/java/java/util/concurrent/atomic/AtomicBoolean.java
+++ b/concurrent/src/main/java/java/util/concurrent/atomic/AtomicBoolean.java
@@ -21,10 +21,7 @@ import sun.misc.Unsafe;
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 Unsafe unsafe = UnsafeAccess.THE_ONE; // android-changed
private static final long valueOffset;
static {
@@ -103,6 +100,17 @@ public class AtomicBoolean implements java.io.Serializable {
}
/**
+ * Eventually sets to the given value.
+ *
+ * @param newValue the new value
+ * @since 1.6
+ */
+ public final void lazySet(boolean newValue) {
+ int v = newValue ? 1 : 0;
+ unsafe.putOrderedInt(this, valueOffset, v);
+ }
+
+ /**
* Atomically sets to the given value and returns the previous value.
*
* @param newValue the new value
diff --git a/concurrent/src/main/java/java/util/concurrent/atomic/AtomicInteger.java b/concurrent/src/main/java/java/util/concurrent/atomic/AtomicInteger.java
index 1aa32f4..16dd568 100644
--- a/concurrent/src/main/java/java/util/concurrent/atomic/AtomicInteger.java
+++ b/concurrent/src/main/java/java/util/concurrent/atomic/AtomicInteger.java
@@ -24,9 +24,7 @@ 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 Unsafe unsafe = UnsafeAccess.THE_ONE; // android-changed
private static final long valueOffset;
static {
@@ -72,6 +70,16 @@ public class AtomicInteger extends Number implements java.io.Serializable {
}
/**
+ * Eventually sets to the given value.
+ *
+ * @param newValue the new value
+ * @since 1.6
+ */
+ public final void lazySet(int newValue) {
+ unsafe.putOrderedInt(this, valueOffset, newValue);
+ }
+
+ /**
* Atomically sets to the given value and returns the old value.
*
* @param newValue the new value
diff --git a/concurrent/src/main/java/java/util/concurrent/atomic/AtomicIntegerArray.java b/concurrent/src/main/java/java/util/concurrent/atomic/AtomicIntegerArray.java
index 312c76d..b6d6cc5 100644
--- a/concurrent/src/main/java/java/util/concurrent/atomic/AtomicIntegerArray.java
+++ b/concurrent/src/main/java/java/util/concurrent/atomic/AtomicIntegerArray.java
@@ -19,33 +19,30 @@ import java.util.*;
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 Unsafe unsafe = UnsafeAccess.THE_ONE; // 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) {
+ private long checkedByteOffset(int i) {
if (i < 0 || i >= array.length)
throw new IndexOutOfBoundsException("index " + i);
- // BEGIN android-changed
- // avoid memory corruption
+
+ return byteOffset(i);
+ }
+
+ private static long byteOffset(int i) {
return base + (long) i * scale;
- // END android-changed
}
/**
- * Creates a new AtomicIntegerArray of given length.
+ * Creates a new AtomicIntegerArray of the given length, with all
+ * elements initially zero.
*
* @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);
}
/**
@@ -56,17 +53,8 @@ public class AtomicIntegerArray implements java.io.Serializable {
* @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]);
- }
+ // Visibility guaranteed by final field guarantees
+ this.array = array.clone();
}
/**
@@ -85,7 +73,11 @@ public class AtomicIntegerArray implements java.io.Serializable {
* @return the current value
*/
public final int get(int i) {
- return unsafe.getIntVolatile(array, rawIndex(i));
+ return getRaw(checkedByteOffset(i));
+ }
+
+ private int getRaw(long offset) {
+ return unsafe.getIntVolatile(array, offset);
}
/**
@@ -95,7 +87,18 @@ public class AtomicIntegerArray implements java.io.Serializable {
* @param newValue the new value
*/
public final void set(int i, int newValue) {
- unsafe.putIntVolatile(array, rawIndex(i), newValue);
+ unsafe.putIntVolatile(array, checkedByteOffset(i), newValue);
+ }
+
+ /**
+ * Eventually sets the element at position {@code i} to the given value.
+ *
+ * @param i the index
+ * @param newValue the new value
+ * @since 1.6
+ */
+ public final void lazySet(int i, int newValue) {
+ unsafe.putOrderedInt(array, checkedByteOffset(i), newValue);
}
/**
@@ -107,9 +110,10 @@ public class AtomicIntegerArray implements java.io.Serializable {
* @return the previous value
*/
public final int getAndSet(int i, int newValue) {
+ long offset = checkedByteOffset(i);
while (true) {
- int current = get(i);
- if (compareAndSet(i, current, newValue))
+ int current = getRaw(offset);
+ if (compareAndSetRaw(offset, current, newValue))
return current;
}
}
@@ -125,8 +129,11 @@ public class AtomicIntegerArray implements java.io.Serializable {
* 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);
+ return compareAndSetRaw(checkedByteOffset(i), expect, update);
+ }
+
+ private boolean compareAndSetRaw(long offset, int expect, int update) {
+ return unsafe.compareAndSwapInt(array, offset, expect, update);
}
/**
@@ -153,12 +160,7 @@ public class AtomicIntegerArray implements java.io.Serializable {
* @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;
- }
+ return getAndAdd(i, 1);
}
/**
@@ -168,12 +170,7 @@ public class AtomicIntegerArray implements java.io.Serializable {
* @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;
- }
+ return getAndAdd(i, -1);
}
/**
@@ -184,10 +181,10 @@ public class AtomicIntegerArray implements java.io.Serializable {
* @return the previous value
*/
public final int getAndAdd(int i, int delta) {
+ long offset = checkedByteOffset(i);
while (true) {
- int current = get(i);
- int next = current + delta;
- if (compareAndSet(i, current, next))
+ int current = getRaw(offset);
+ if (compareAndSetRaw(offset, current, current + delta))
return current;
}
}
@@ -199,12 +196,7 @@ public class AtomicIntegerArray implements java.io.Serializable {
* @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;
- }
+ return addAndGet(i, 1);
}
/**
@@ -214,12 +206,7 @@ public class AtomicIntegerArray implements java.io.Serializable {
* @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;
- }
+ return addAndGet(i, -1);
}
/**
@@ -230,22 +217,32 @@ public class AtomicIntegerArray implements java.io.Serializable {
* @return the updated value
*/
public final int addAndGet(int i, int delta) {
+ long offset = checkedByteOffset(i);
while (true) {
- int current = get(i);
+ int current = getRaw(offset);
int next = current + delta;
- if (compareAndSet(i, current, next))
+ if (compareAndSetRaw(offset, current, next))
return next;
}
}
/**
* Returns the String representation of the current values of array.
- * @return 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);
+ int iMax = array.length - 1;
+ if (iMax == -1)
+ return "[]";
+
+ StringBuilder b = new StringBuilder();
+ b.append('[');
+ for (int i = 0; ; i++) {
+ b.append(getRaw(byteOffset(i)));
+ if (i == iMax)
+ return b.append(']').toString();
+ b.append(", ");
+ }
}
}
diff --git a/concurrent/src/main/java/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java b/concurrent/src/main/java/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java
index f8d2c81..476bb0a 100644
--- a/concurrent/src/main/java/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java
+++ b/concurrent/src/main/java/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java
@@ -5,12 +5,10 @@
*/
package java.util.concurrent.atomic;
+import dalvik.system.VMStack;
import sun.misc.Unsafe;
import java.lang.reflect.*;
-import org.apache.harmony.kernel.vm.VM;
-import dalvik.system.VMStack;
-
/**
* A reflection-based utility that enables atomic updates to
* designated {@code volatile int} fields of designated classes.
@@ -100,6 +98,17 @@ public abstract class AtomicIntegerFieldUpdater<T> {
public abstract void set(T obj, int newValue);
/**
+ * Eventually sets the field of the given object managed by this
+ * updater to the given updated value.
+ *
+ * @param obj An object whose field to set
+ * @param newValue the new value
+ * @since 1.6
+ */
+ public abstract void lazySet(T obj, int newValue);
+
+
+ /**
* Gets the current value held in the field of the given object managed
* by this updater.
*
@@ -226,9 +235,7 @@ public abstract class AtomicIntegerFieldUpdater<T> {
* 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 static final Unsafe unsafe = UnsafeAccess.THE_ONE; // android-changed
private final long offset;
private final Class<T> tclass;
private final Class cclass;
@@ -244,6 +251,7 @@ public abstract class AtomicIntegerFieldUpdater<T> {
// END android-changed
modifiers = field.getModifiers();
+ // BEGIN android-added
SecurityManager smgr = System.getSecurityManager();
if (smgr != null) {
int type = Modifier.isPublic(modifiers)
@@ -251,6 +259,13 @@ public abstract class AtomicIntegerFieldUpdater<T> {
smgr.checkMemberAccess(tclass, type);
smgr.checkPackageAccess(tclass.getPackage().getName());
}
+ // END android-added
+ // BEGIN android-removed
+ // modifiers = field.getModifiers();
+ // sun.reflect.misc.ReflectUtil.ensureMemberAccess(
+ // caller, tclass, null, modifiers);
+ // sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass);
+ // END android-removed
} catch (Exception ex) {
throw new RuntimeException(ex);
}
@@ -290,6 +305,11 @@ public abstract class AtomicIntegerFieldUpdater<T> {
unsafe.putIntVolatile(obj, offset, newValue);
}
+ public void lazySet(T obj, int newValue) {
+ if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj);
+ unsafe.putOrderedInt(obj, offset, newValue);
+ }
+
public final int get(T obj) {
if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj);
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
index 9b56002..e1f5dc7 100644
--- a/concurrent/src/main/java/java/util/concurrent/atomic/AtomicLong.java
+++ b/concurrent/src/main/java/java/util/concurrent/atomic/AtomicLong.java
@@ -24,9 +24,7 @@ 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 Unsafe unsafe = UnsafeAccess.THE_ONE; // android-changed
private static final long valueOffset;
/**
@@ -97,6 +95,16 @@ public class AtomicLong extends Number implements java.io.Serializable {
}
/**
+ * Eventually sets to the given value.
+ *
+ * @param newValue the new value
+ * @since 1.6
+ */
+ public final void lazySet(long newValue) {
+ unsafe.putOrderedLong(this, valueOffset, newValue);
+ }
+
+ /**
* Atomically sets to the given value and returns the old value.
*
* @param newValue the new value
diff --git a/concurrent/src/main/java/java/util/concurrent/atomic/AtomicLongArray.java b/concurrent/src/main/java/java/util/concurrent/atomic/AtomicLongArray.java
index 187acbc..33e6914 100644
--- a/concurrent/src/main/java/java/util/concurrent/atomic/AtomicLongArray.java
+++ b/concurrent/src/main/java/java/util/concurrent/atomic/AtomicLongArray.java
@@ -18,33 +18,30 @@ import java.util.*;
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 Unsafe unsafe = UnsafeAccess.THE_ONE; // 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) {
+ private long checkedByteOffset(int i) {
if (i < 0 || i >= array.length)
throw new IndexOutOfBoundsException("index " + i);
- // BEGIN android-changed
- // avoid memory corruption
+
+ return byteOffset(i);
+ }
+
+ private static long byteOffset(int i) {
return base + (long) i * scale;
- // END android-changed
}
/**
- * Creates a new AtomicLongArray of given length.
+ * Creates a new AtomicLongArray of the given length, with all
+ * elements initially zero.
*
* @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);
}
/**
@@ -55,17 +52,8 @@ public class AtomicLongArray implements java.io.Serializable {
* @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]);
- }
+ // Visibility guaranteed by final field guarantees
+ this.array = array.clone();
}
/**
@@ -84,7 +72,11 @@ public class AtomicLongArray implements java.io.Serializable {
* @return the current value
*/
public final long get(int i) {
- return unsafe.getLongVolatile(array, rawIndex(i));
+ return getRaw(checkedByteOffset(i));
+ }
+
+ private long getRaw(long offset) {
+ return unsafe.getLongVolatile(array, offset);
}
/**
@@ -94,10 +86,22 @@ public class AtomicLongArray implements java.io.Serializable {
* @param newValue the new value
*/
public final void set(int i, long newValue) {
- unsafe.putLongVolatile(array, rawIndex(i), newValue);
+ unsafe.putLongVolatile(array, checkedByteOffset(i), newValue);
}
/**
+ * Eventually sets the element at position {@code i} to the given value.
+ *
+ * @param i the index
+ * @param newValue the new value
+ * @since 1.6
+ */
+ public final void lazySet(int i, long newValue) {
+ unsafe.putOrderedLong(array, checkedByteOffset(i), newValue);
+ }
+
+
+ /**
* Atomically sets the element at position {@code i} to the given value
* and returns the old value.
*
@@ -106,16 +110,17 @@ public class AtomicLongArray implements java.io.Serializable {
* @return the previous value
*/
public final long getAndSet(int i, long newValue) {
+ long offset = checkedByteOffset(i);
while (true) {
- long current = get(i);
- if (compareAndSet(i, current, newValue))
+ long current = getRaw(offset);
+ if (compareAndSetRaw(offset, current, newValue))
return current;
}
}
/**
- * Atomically sets the value to the given updated value
- * if the current value {@code ==} the expected value.
+ * Atomically sets the element at position {@code i} to the given
+ * updated value if the current value {@code ==} the expected value.
*
* @param i the index
* @param expect the expected value
@@ -124,13 +129,16 @@ public class AtomicLongArray implements java.io.Serializable {
* 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);
+ return compareAndSetRaw(checkedByteOffset(i), expect, update);
+ }
+
+ private boolean compareAndSetRaw(long offset, long expect, long update) {
+ return unsafe.compareAndSwapLong(array, offset, expect, update);
}
/**
- * Atomically sets the value to the given updated value
- * if the current value {@code ==} the expected value.
+ * Atomically sets the element at position {@code i} to the given
+ * updated value if the current value {@code ==} the expected value.
*
* <p>May <a href="package-summary.html#Spurious">fail spuriously</a>
* and does not provide ordering guarantees, so is only rarely an
@@ -152,12 +160,7 @@ public class AtomicLongArray implements java.io.Serializable {
* @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;
- }
+ return getAndAdd(i, 1);
}
/**
@@ -167,12 +170,7 @@ public class AtomicLongArray implements java.io.Serializable {
* @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;
- }
+ return getAndAdd(i, -1);
}
/**
@@ -183,10 +181,10 @@ public class AtomicLongArray implements java.io.Serializable {
* @return the previous value
*/
public final long getAndAdd(int i, long delta) {
+ long offset = checkedByteOffset(i);
while (true) {
- long current = get(i);
- long next = current + delta;
- if (compareAndSet(i, current, next))
+ long current = getRaw(offset);
+ if (compareAndSetRaw(offset, current, current + delta))
return current;
}
}
@@ -198,12 +196,7 @@ public class AtomicLongArray implements java.io.Serializable {
* @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;
- }
+ return addAndGet(i, 1);
}
/**
@@ -213,12 +206,7 @@ public class AtomicLongArray implements java.io.Serializable {
* @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;
- }
+ return addAndGet(i, -1);
}
/**
@@ -229,22 +217,32 @@ public class AtomicLongArray implements java.io.Serializable {
* @return the updated value
*/
public long addAndGet(int i, long delta) {
+ long offset = checkedByteOffset(i);
while (true) {
- long current = get(i);
+ long current = getRaw(offset);
long next = current + delta;
- if (compareAndSet(i, current, next))
+ if (compareAndSetRaw(offset, current, next))
return next;
}
}
/**
* Returns the String representation of the current values of array.
- * @return 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);
+ int iMax = array.length - 1;
+ if (iMax == -1)
+ return "[]";
+
+ StringBuilder b = new StringBuilder();
+ b.append('[');
+ for (int i = 0; ; i++) {
+ b.append(getRaw(byteOffset(i)));
+ if (i == iMax)
+ return b.append(']').toString();
+ b.append(", ");
+ }
}
}
diff --git a/concurrent/src/main/java/java/util/concurrent/atomic/AtomicLongFieldUpdater.java b/concurrent/src/main/java/java/util/concurrent/atomic/AtomicLongFieldUpdater.java
index d97c2e4..427a9e1 100644
--- a/concurrent/src/main/java/java/util/concurrent/atomic/AtomicLongFieldUpdater.java
+++ b/concurrent/src/main/java/java/util/concurrent/atomic/AtomicLongFieldUpdater.java
@@ -5,12 +5,10 @@
*/
package java.util.concurrent.atomic;
+import dalvik.system.VMStack;
import sun.misc.Unsafe;
import java.lang.reflect.*;
-import org.apache.harmony.kernel.vm.VM;
-import dalvik.system.VMStack;
-
/**
* A reflection-based utility that enables atomic updates to
* designated {@code volatile long} fields of designated classes.
@@ -103,6 +101,16 @@ public abstract class AtomicLongFieldUpdater<T> {
public abstract void set(T obj, long newValue);
/**
+ * Eventually sets the field of the given object managed by this
+ * updater to the given updated value.
+ *
+ * @param obj An object whose field to set
+ * @param newValue the new value
+ * @since 1.6
+ */
+ public abstract void lazySet(T obj, long newValue);
+
+ /**
* Gets the current value held in the field of the given object managed
* by this updater.
*
@@ -226,9 +234,7 @@ public abstract class AtomicLongFieldUpdater<T> {
}
private static class CASUpdater<T> extends AtomicLongFieldUpdater<T> {
- // BEGIN android-changed
- private static final Unsafe unsafe = UnsafeAccess.THE_ONE;
- // END android-changed
+ private static final Unsafe unsafe = UnsafeAccess.THE_ONE; // android-changed
private final long offset;
private final Class<T> tclass;
private final Class cclass;
@@ -239,10 +245,9 @@ public abstract class AtomicLongFieldUpdater<T> {
int modifiers = 0;
try {
field = tclass.getDeclaredField(fieldName);
- // BEGIN android-changed
- caller = VMStack.getStackClass2();
- // END android-changed
+ caller = VMStack.getStackClass2(); // android-changed
modifiers = field.getModifiers();
+ // BEGIN android-added
SecurityManager smgr = System.getSecurityManager();
if (smgr != null) {
int type = Modifier.isPublic(modifiers)
@@ -250,6 +255,12 @@ public abstract class AtomicLongFieldUpdater<T> {
smgr.checkMemberAccess(tclass, type);
smgr.checkPackageAccess(tclass.getPackage().getName());
}
+ // END android-added
+ // BEGIN android-removed
+ // sun.reflect.misc.ReflectUtil.ensureMemberAccess(
+ // caller, tclass, null, modifiers);
+ // sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass);
+ // END android-removed
} catch (Exception ex) {
throw new RuntimeException(ex);
}
@@ -289,6 +300,11 @@ public abstract class AtomicLongFieldUpdater<T> {
unsafe.putLongVolatile(obj, offset, newValue);
}
+ public void lazySet(T obj, long newValue) {
+ if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj);
+ unsafe.putOrderedLong(obj, offset, newValue);
+ }
+
public long get(T obj) {
if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj);
return unsafe.getLongVolatile(obj, offset);
@@ -312,9 +328,7 @@ public abstract class AtomicLongFieldUpdater<T> {
private static class LockedUpdater<T> extends AtomicLongFieldUpdater<T> {
- // BEGIN android-changed
- private static final Unsafe unsafe = UnsafeAccess.THE_ONE;
- // END android-changed
+ private static final Unsafe unsafe = UnsafeAccess.THE_ONE; // android-changed
private final long offset;
private final Class<T> tclass;
private final Class cclass;
@@ -325,10 +339,9 @@ public abstract class AtomicLongFieldUpdater<T> {
int modifiers = 0;
try {
field = tclass.getDeclaredField(fieldName);
- // BEGIN android-changed
- caller = VMStack.getStackClass2();
- // END android-changed
+ caller = VMStack.getStackClass2(); // android-changed
modifiers = field.getModifiers();
+ // BEGIN android-added
SecurityManager smgr = System.getSecurityManager();
if (smgr != null) {
int type = Modifier.isPublic(modifiers)
@@ -336,6 +349,12 @@ public abstract class AtomicLongFieldUpdater<T> {
smgr.checkMemberAccess(tclass, type);
smgr.checkPackageAccess(tclass.getPackage().getName());
}
+ // END android-added
+ // BEGIN android-removed
+ // sun.reflect.misc.ReflectUtil.ensureMemberAccess(
+ // caller, tclass, null, modifiers);
+ // sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass);
+ // END android-removed
} catch (Exception ex) {
throw new RuntimeException(ex);
}
diff --git a/concurrent/src/main/java/java/util/concurrent/atomic/AtomicReference.java b/concurrent/src/main/java/java/util/concurrent/atomic/AtomicReference.java
index 1de9b1c..f041bbd 100644
--- a/concurrent/src/main/java/java/util/concurrent/atomic/AtomicReference.java
+++ b/concurrent/src/main/java/java/util/concurrent/atomic/AtomicReference.java
@@ -18,9 +18,7 @@ import sun.misc.Unsafe;
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 Unsafe unsafe = UnsafeAccess.THE_ONE; // android-changed
private static final long valueOffset;
static {
@@ -66,6 +64,16 @@ public class AtomicReference<V> implements java.io.Serializable {
}
/**
+ * Eventually sets to the given value.
+ *
+ * @param newValue the new value
+ * @since 1.6
+ */
+ public final void lazySet(V newValue) {
+ unsafe.putOrderedObject(this, valueOffset, newValue);
+ }
+
+ /**
* Atomically sets the value to the given updated value
* if the current value {@code ==} the expected value.
* @param expect the expected value
diff --git a/concurrent/src/main/java/java/util/concurrent/atomic/AtomicReferenceArray.java b/concurrent/src/main/java/java/util/concurrent/atomic/AtomicReferenceArray.java
index fff6a1e..2501c2b 100644
--- a/concurrent/src/main/java/java/util/concurrent/atomic/AtomicReferenceArray.java
+++ b/concurrent/src/main/java/java/util/concurrent/atomic/AtomicReferenceArray.java
@@ -20,31 +20,30 @@ import java.util.*;
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 Unsafe unsafe = UnsafeAccess.THE_ONE; // 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) {
+ private long checkedByteOffset(int i) {
if (i < 0 || i >= array.length)
throw new IndexOutOfBoundsException("index " + i);
- // BEGIN android-changed
- // avoid memory corruption
+
+ return byteOffset(i);
+ }
+
+ private static long byteOffset(int i) {
return base + (long) i * scale;
- // END android-changed
}
/**
- * Creates a new AtomicReferenceArray of given length.
+ * Creates a new AtomicReferenceArray of the given length, with all
+ * elements initially zero.
+ *
* @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);
}
/**
@@ -55,18 +54,8 @@ public class AtomicReferenceArray<E> implements java.io.Serializable {
* @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);
- }
+ // Visibility guaranteed by final field guarantees
+ this.array = array.clone();
}
/**
@@ -85,7 +74,11 @@ public class AtomicReferenceArray<E> implements java.io.Serializable {
* @return the current value
*/
public final E get(int i) {
- return (E) unsafe.getObjectVolatile(array, rawIndex(i));
+ return getRaw(checkedByteOffset(i));
+ }
+
+ private E getRaw(long offset) {
+ return (E) unsafe.getObjectVolatile(array, offset);
}
/**
@@ -95,9 +88,21 @@ public class AtomicReferenceArray<E> implements java.io.Serializable {
* @param newValue the new value
*/
public final void set(int i, E newValue) {
- unsafe.putObjectVolatile(array, rawIndex(i), newValue);
+ unsafe.putObjectVolatile(array, checkedByteOffset(i), newValue);
+ }
+
+ /**
+ * Eventually sets the element at position {@code i} to the given value.
+ *
+ * @param i the index
+ * @param newValue the new value
+ * @since 1.6
+ */
+ public final void lazySet(int i, E newValue) {
+ unsafe.putOrderedObject(array, checkedByteOffset(i), newValue);
}
+
/**
* Atomically sets the element at position {@code i} to the given
* value and returns the old value.
@@ -107,9 +112,10 @@ public class AtomicReferenceArray<E> implements java.io.Serializable {
* @return the previous value
*/
public final E getAndSet(int i, E newValue) {
+ long offset = checkedByteOffset(i);
while (true) {
- E current = get(i);
- if (compareAndSet(i, current, newValue))
+ E current = (E) getRaw(offset);
+ if (compareAndSetRaw(offset, current, newValue))
return current;
}
}
@@ -117,6 +123,7 @@ public class AtomicReferenceArray<E> implements java.io.Serializable {
/**
* Atomically sets the element at position {@code i} to the given
* updated value if the current value {@code ==} the expected value.
+ *
* @param i the index
* @param expect the expected value
* @param update the new value
@@ -124,8 +131,11 @@ public class AtomicReferenceArray<E> implements java.io.Serializable {
* 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);
+ return compareAndSetRaw(checkedByteOffset(i), expect, update);
+ }
+
+ private boolean compareAndSetRaw(long offset, E expect, E update) {
+ return unsafe.compareAndSwapObject(array, offset, expect, update);
}
/**
@@ -147,12 +157,21 @@ public class AtomicReferenceArray<E> implements java.io.Serializable {
/**
* Returns the String representation of the current values of array.
- * @return 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);
+ int iMax = array.length - 1;
+ if (iMax == -1)
+ return "[]";
+
+ StringBuilder b = new StringBuilder();
+ b.append('[');
+ for (int i = 0; ; i++) {
+ b.append(getRaw(byteOffset(i)));
+ if (i == iMax)
+ return b.append(']').toString();
+ b.append(", ");
+ }
}
}
diff --git a/concurrent/src/main/java/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java b/concurrent/src/main/java/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java
index fae134f..e53f2e9 100644
--- a/concurrent/src/main/java/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java
+++ b/concurrent/src/main/java/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java
@@ -5,12 +5,10 @@
*/
package java.util.concurrent.atomic;
+import dalvik.system.VMStack;
import sun.misc.Unsafe;
import java.lang.reflect.*;
-import org.apache.harmony.kernel.vm.VM;
-import dalvik.system.VMStack;
-
/**
* A reflection-based utility that enables atomic updates to
* designated {@code volatile} reference fields of designated
@@ -118,6 +116,16 @@ public abstract class AtomicReferenceFieldUpdater<T, V> {
public abstract void set(T obj, V newValue);
/**
+ * Eventually sets the field of the given object managed by this
+ * updater to the given updated value.
+ *
+ * @param obj An object whose field to set
+ * @param newValue the new value
+ * @since 1.6
+ */
+ public abstract void lazySet(T obj, V newValue);
+
+ /**
* Gets the current value held in the field of the given object managed
* by this updater.
*
@@ -144,9 +152,7 @@ public abstract class AtomicReferenceFieldUpdater<T, V> {
private static final class AtomicReferenceFieldUpdaterImpl<T,V>
extends AtomicReferenceFieldUpdater<T,V> {
- // BEGIN android-changed
- private static final Unsafe unsafe = UnsafeAccess.THE_ONE;
- // END android-changed
+ private static final Unsafe unsafe = Unsafe.getUnsafe();
private final long offset;
private final Class<T> tclass;
private final Class<V> vclass;
@@ -173,10 +179,9 @@ public abstract class AtomicReferenceFieldUpdater<T, V> {
int modifiers = 0;
try {
field = tclass.getDeclaredField(fieldName);
- // BEGIN android-changed
- caller = VMStack.getStackClass2();
- // END android-changed
+ caller = VMStack.getStackClass2(); // android-changed
modifiers = field.getModifiers();
+ // BEGIN android-added
SecurityManager smgr = System.getSecurityManager();
if (smgr != null) {
int type = Modifier.isPublic(modifiers)
@@ -184,6 +189,12 @@ public abstract class AtomicReferenceFieldUpdater<T, V> {
smgr.checkMemberAccess(tclass, type);
smgr.checkPackageAccess(tclass.getPackage().getName());
}
+ // END android-added
+ // BEGIN android-removed
+ // sun.reflect.misc.ReflectUtil.ensureMemberAccess(
+ // caller, tclass, null, modifiers);
+ // sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass);
+ // END android-removed
fieldClass = field.getType();
} catch (Exception ex) {
throw new RuntimeException(ex);
@@ -245,6 +256,14 @@ public abstract class AtomicReferenceFieldUpdater<T, V> {
unsafe.putObjectVolatile(obj, offset, newValue);
}
+ public void lazySet(T obj, V newValue) {
+ if (obj == null || obj.getClass() != tclass || cclass != null ||
+ (newValue != null && vclass != null &&
+ vclass != newValue.getClass()))
+ updateCheck(obj, newValue);
+ unsafe.putOrderedObject(obj, offset, newValue);
+ }
+
public V get(T obj) {
if (obj == null || obj.getClass() != tclass || cclass != null)
targetCheck(obj);
diff --git a/concurrent/src/main/java/java/util/concurrent/atomic/package-info.java b/concurrent/src/main/java/java/util/concurrent/atomic/package-info.java
index 2252e5c..4a4375d 100644
--- a/concurrent/src/main/java/java/util/concurrent/atomic/package-info.java
+++ b/concurrent/src/main/java/java/util/concurrent/atomic/package-info.java
@@ -63,6 +63,14 @@
* <li> {@code set} has the memory effects of writing (assigning) a
* {@code volatile} variable.
*
+ * <li> {@code lazySet} has the memory effects of writing (assigning)
+ * a {@code volatile} variable except that it permits reorderings with
+ * subsequent (but not previous) memory actions that do not themselves
+ * impose reordering constraints with ordinary non-{@code volatile}
+ * writes. Among other usage contexts, {@code lazySet} may apply when
+ * nulling out, for the sake of garbage collection, a reference that is
+ * never accessed again.
+ *
* <li>{@code weakCompareAndSet} atomically reads and conditionally
* writes a variable but does <em>not</em>
* create any happens-before orderings, so provides no guarantees
diff --git a/concurrent/src/main/java/java/util/concurrent/locks/AbstractOwnableSynchronizer.java b/concurrent/src/main/java/java/util/concurrent/locks/AbstractOwnableSynchronizer.java
index bf2fe16..f3780e5 100644
--- a/concurrent/src/main/java/java/util/concurrent/locks/AbstractOwnableSynchronizer.java
+++ b/concurrent/src/main/java/java/util/concurrent/locks/AbstractOwnableSynchronizer.java
@@ -15,10 +15,11 @@ package java.util.concurrent.locks;
* appropriately maintained values to help control and monitor access
* and provide diagnostics.
*
+ * @since 1.6
* @author Doug Lea
*/
-abstract class AbstractOwnableSynchronizer
- implements java.io.Serializable {
+public abstract class AbstractOwnableSynchronizer
+ implements java.io.Serializable {
/** Use serial ID even though all fields transient. */
private static final long serialVersionUID = 3737899427754241961L;
@@ -53,4 +54,4 @@ abstract class AbstractOwnableSynchronizer
protected final Thread getExclusiveOwnerThread() {
return exclusiveOwnerThread;
}
-} \ No newline at end of file
+}
diff --git a/concurrent/src/main/java/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java b/concurrent/src/main/java/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java
new file mode 100644
index 0000000..d805259
--- /dev/null
+++ b/concurrent/src/main/java/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java
@@ -0,0 +1,2073 @@
+/*
+ * 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;
+
+/**
+ * A version of {@link AbstractQueuedSynchronizer} in
+ * which synchronization state is maintained as a <tt>long</tt>.
+ * This class has exactly the same structure, properties, and methods
+ * as <tt>AbstractQueuedSynchronizer</tt> with the exception
+ * that all state-related parameters and results are defined
+ * as <tt>long</tt> rather than <tt>int</tt>. This class
+ * may be useful when creating synchronizers such as
+ * multilevel locks and barriers that require
+ * 64 bits of state.
+ *
+ * <p>See {@link AbstractQueuedSynchronizer} for usage
+ * notes and examples.
+ *
+ * @since 1.6
+ * @author Doug Lea
+ */
+public abstract class AbstractQueuedLongSynchronizer
+ extends AbstractOwnableSynchronizer
+ implements java.io.Serializable {
+
+ private static final long serialVersionUID = 7373984972572414692L;
+
+ /*
+ To keep sources in sync, the remainder of this source file is
+ exactly cloned from AbstractQueuedSynchronizer, replacing class
+ name and changing ints related with sync state to longs. Please
+ keep it that way.
+ */
+
+ /**
+ * Creates a new <tt>AbstractQueuedLongSynchronizer</tt> instance
+ * with initial synchronization state of zero.
+ */
+ protected AbstractQueuedLongSynchronizer() { }
+
+ /**
+ * 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, unless we can identify an uncancelled
+ * predecessor who will carry this responsibility.
+ *
+ * <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 {
+ /** Marker to indicate a node is waiting in shared mode */
+ static final Node SHARED = new Node();
+ /** Marker to indicate a node is waiting in exclusive mode */
+ static final Node EXCLUSIVE = null;
+
+ /** waitStatus value to indicate thread has cancelled */
+ static final int CANCELLED = 1;
+ /** waitStatus value to indicate successor's thread needs unparking */
+ static final int SIGNAL = -1;
+ /** waitStatus value to indicate thread is waiting on condition */
+ static final int CONDITION = -2;
+ /**
+ * waitStatus value to indicate the next acquireShared should
+ * unconditionally propagate
+ */
+ static final int PROPAGATE = -3;
+
+ /**
+ * Status field, taking on only the values:
+ * SIGNAL: The successor of this node is (or will soon be)
+ * blocked (via park), so the current node must
+ * unpark its successor when it releases or
+ * cancels. To avoid races, acquire methods must
+ * first indicate they need a signal,
+ * then retry the atomic acquire, and then,
+ * on failure, block.
+ * CANCELLED: This node is cancelled due to timeout or interrupt.
+ * Nodes never leave this state. In particular,
+ * a thread with cancelled node never again blocks.
+ * CONDITION: This node is currently on a condition queue.
+ * It will not be used as a sync queue node
+ * until transferred, at which time the status
+ * will be set to 0. (Use of this value here has
+ * nothing to do with the other uses of the
+ * field, but simplifies mechanics.)
+ * PROPAGATE: A releaseShared should be propagated to other
+ * nodes. This is set (for head node only) in
+ * doReleaseShared to ensure propagation
+ * continues, even if other operations have
+ * since intervened.
+ * 0: None of the above
+ *
+ * The values are arranged numerically to simplify use.
+ * Non-negative values mean that a node doesn't need to
+ * signal. So, most code doesn't need to check for particular
+ * values, just for sign.
+ *
+ * The field is initialized to 0 for normal sync nodes, and
+ * CONDITION for condition nodes. It is modified using CAS
+ * (or when possible, unconditional volatile writes).
+ */
+ volatile int waitStatus;
+
+ /**
+ * Link to predecessor node that current node/thread relies on
+ * for checking waitStatus. Assigned during enqueing, and nulled
+ * out (for sake of GC) only upon dequeuing. Also, upon
+ * cancellation of a predecessor, we short-circuit while
+ * finding a non-cancelled one, which will always exist
+ * because the head node is never cancelled: A node becomes
+ * head only as a result of successful acquire. A
+ * cancelled thread never succeeds in acquiring, and a thread only
+ * cancels itself, not any other node.
+ */
+ volatile Node prev;
+
+ /**
+ * Link to the successor node that the current node/thread
+ * unparks upon release. Assigned during enqueuing, adjusted
+ * when bypassing cancelled predecessors, and nulled out (for
+ * sake of GC) when dequeued. The enq operation does not
+ * assign next field of a predecessor until after attachment,
+ * so seeing a null next field does not necessarily mean that
+ * node is at end of queue. However, if a next field appears
+ * to be null, we can scan prev's from the tail to
+ * double-check. The next field of cancelled nodes is set to
+ * point to the node itself instead of null, to make life
+ * easier for isOnSyncQueue.
+ */
+ volatile Node next;
+
+ /**
+ * The thread that enqueued this node. Initialized on
+ * construction and nulled out after use.
+ */
+ volatile Thread thread;
+
+ /**
+ * Link to next node waiting on condition, or the special
+ * value SHARED. Because condition queues are accessed only
+ * when holding in exclusive mode, we just need a simple
+ * linked queue to hold nodes while they are waiting on
+ * conditions. They are then transferred to the queue to
+ * re-acquire. And because conditions can only be exclusive,
+ * we save a field by using special value to indicate shared
+ * mode.
+ */
+ Node nextWaiter;
+
+ /**
+ * Returns true if node is waiting in shared mode
+ */
+ final boolean isShared() {
+ return nextWaiter == SHARED;
+ }
+
+ /**
+ * Returns previous node, or throws NullPointerException if null.
+ * Use when predecessor cannot be null. The null check could
+ * be elided, but is present to help the VM.
+ *
+ * @return the predecessor of this node
+ */
+ final Node predecessor() throws NullPointerException {
+ Node p = prev;
+ if (p == null)
+ throw new NullPointerException();
+ else
+ return p;
+ }
+
+ Node() { // Used to establish initial head or SHARED marker
+ }
+
+ Node(Thread thread, Node mode) { // Used by addWaiter
+ this.nextWaiter = mode;
+ this.thread = thread;
+ }
+
+ Node(Thread thread, int waitStatus) { // Used by Condition
+ this.waitStatus = waitStatus;
+ this.thread = thread;
+ }
+ }
+
+ /**
+ * Head of the wait queue, lazily initialized. Except for
+ * initialization, it is modified only via method setHead. Note:
+ * If head exists, its waitStatus is guaranteed not to be
+ * CANCELLED.
+ */
+ private transient volatile Node head;
+
+ /**
+ * Tail of the wait queue, lazily initialized. Modified only via
+ * method enq to add new wait node.
+ */
+ private transient volatile Node tail;
+
+ /**
+ * The synchronization state.
+ */
+ private volatile long state;
+
+ /**
+ * Returns the current value of synchronization state.
+ * This operation has memory semantics of a <tt>volatile</tt> read.
+ * @return current state value
+ */
+ protected final long 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(long newState) {
+ state = newState;
+ }
+
+ /**
+ * Atomically sets synchronization state to the given updated
+ * value if the current state value equals the expected value.
+ * This operation has memory semantics of a <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(long expect, long update) {
+ // See below for intrinsics setup to support this
+ return unsafe.compareAndSwapLong(this, stateOffset, expect, update);
+ }
+
+ // Queuing utilities
+
+ /**
+ * The number of nanoseconds for which it is faster to spin
+ * rather than to use timed park. A rough estimate suffices
+ * to improve responsiveness with very short timeouts.
+ */
+ static final long spinForTimeoutThreshold = 1000L;
+
+ /**
+ * Inserts node into queue, initializing if necessary. See picture above.
+ * @param node the node to insert
+ * @return node's predecessor
+ */
+ private Node enq(final Node node) {
+ for (;;) {
+ Node t = tail;
+ if (t == null) { // Must initialize
+ if (compareAndSetHead(new Node()))
+ tail = head;
+ } else {
+ node.prev = t;
+ if (compareAndSetTail(t, node)) {
+ t.next = node;
+ return t;
+ }
+ }
+ }
+ }
+
+ /**
+ * Creates and enqueues node for current thread and given mode.
+ *
+ * @param mode Node.EXCLUSIVE for exclusive, Node.SHARED for shared
+ * @return the new node
+ */
+ private Node addWaiter(Node mode) {
+ Node node = new Node(Thread.currentThread(), mode);
+ // Try the fast path of enq; backup to full enq on failure
+ Node pred = tail;
+ if (pred != null) {
+ node.prev = pred;
+ if (compareAndSetTail(pred, node)) {
+ pred.next = node;
+ return node;
+ }
+ }
+ enq(node);
+ return node;
+ }
+
+ /**
+ * Sets head of queue to be node, thus dequeuing. Called only by
+ * acquire methods. Also nulls out unused fields for sake of GC
+ * and to suppress unnecessary signals and traversals.
+ *
+ * @param node the node
+ */
+ private void setHead(Node node) {
+ head = node;
+ node.thread = null;
+ node.prev = null;
+ }
+
+ /**
+ * Wakes up node's successor, if one exists.
+ *
+ * @param node the node
+ */
+ private void unparkSuccessor(Node node) {
+ /*
+ * If status is negative (i.e., possibly needing signal) try
+ * to clear in anticipation of signalling. It is OK if this
+ * fails or if status is changed by waiting thread.
+ */
+ int ws = node.waitStatus;
+ if (ws < 0)
+ compareAndSetWaitStatus(node, ws, 0);
+
+ /*
+ * Thread to unpark is held in successor, which is normally
+ * just the next node. But if cancelled or apparently null,
+ * traverse backwards from tail to find the actual
+ * non-cancelled successor.
+ */
+ Node s = node.next;
+ if (s == null || s.waitStatus > 0) {
+ s = null;
+ for (Node t = tail; t != null && t != node; t = t.prev)
+ if (t.waitStatus <= 0)
+ s = t;
+ }
+ if (s != null)
+ LockSupport.unpark(s.thread);
+ }
+
+ /**
+ * Release action for shared mode -- signal successor and ensure
+ * propagation. (Note: For exclusive mode, release just amounts
+ * to calling unparkSuccessor of head if it needs signal.)
+ */
+ private void doReleaseShared() {
+ /*
+ * Ensure that a release propagates, even if there are other
+ * in-progress acquires/releases. This proceeds in the usual
+ * way of trying to unparkSuccessor of head if it needs
+ * signal. But if it does not, status is set to PROPAGATE to
+ * ensure that upon release, propagation continues.
+ * Additionally, we must loop in case a new node is added
+ * while we are doing this. Also, unlike other uses of
+ * unparkSuccessor, we need to know if CAS to reset status
+ * fails, if so rechecking.
+ */
+ for (;;) {
+ Node h = head;
+ if (h != null && h != tail) {
+ int ws = h.waitStatus;
+ if (ws == Node.SIGNAL) {
+ if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))
+ continue; // loop to recheck cases
+ unparkSuccessor(h);
+ }
+ else if (ws == 0 &&
+ !compareAndSetWaitStatus(h, 0, Node.PROPAGATE))
+ continue; // loop on failed CAS
+ }
+ if (h == head) // loop if head changed
+ break;
+ }
+ }
+
+ /**
+ * Sets head of queue, and checks if successor may be waiting
+ * in shared mode, if so propagating if either propagate > 0 or
+ * PROPAGATE status was set.
+ *
+ * @param node the node
+ * @param propagate the return value from a tryAcquireShared
+ */
+ private void setHeadAndPropagate(Node node, long propagate) {
+ Node h = head; // Record old head for check below
+ setHead(node);
+ /*
+ * Try to signal next queued node if:
+ * Propagation was indicated by caller,
+ * or was recorded (as h.waitStatus) by a previous operation
+ * (note: this uses sign-check of waitStatus because
+ * PROPAGATE status may transition to SIGNAL.)
+ * and
+ * The next node is waiting in shared mode,
+ * or we don't know, because it appears null
+ *
+ * The conservatism in both of these checks may cause
+ * unnecessary wake-ups, but only when there are multiple
+ * racing acquires/releases, so most need signals now or soon
+ * anyway.
+ */
+ if (propagate > 0 || h == null || h.waitStatus < 0) {
+ Node s = node.next;
+ if (s == null || s.isShared())
+ doReleaseShared();
+ }
+ }
+
+ // Utilities for various versions of acquire
+
+ /**
+ * Cancels an ongoing attempt to acquire.
+ *
+ * @param node the node
+ */
+ private void cancelAcquire(Node node) {
+ // Ignore if node doesn't exist
+ if (node == null)
+ return;
+
+ node.thread = null;
+
+ // Skip cancelled predecessors
+ Node pred = node.prev;
+ while (pred.waitStatus > 0)
+ node.prev = pred = pred.prev;
+
+ // predNext is the apparent node to unsplice. CASes below will
+ // fail if not, in which case, we lost race vs another cancel
+ // or signal, so no further action is necessary.
+ Node predNext = pred.next;
+
+ // Can use unconditional write instead of CAS here.
+ // After this atomic step, other Nodes can skip past us.
+ // Before, we are free of interference from other threads.
+ node.waitStatus = Node.CANCELLED;
+
+ // If we are the tail, remove ourselves.
+ if (node == tail && compareAndSetTail(node, pred)) {
+ compareAndSetNext(pred, predNext, null);
+ } else {
+ // If successor needs signal, try to set pred's next-link
+ // so it will get one. Otherwise wake it up to propagate.
+ int ws;
+ if (pred != head &&
+ ((ws = pred.waitStatus) == Node.SIGNAL ||
+ (ws <= 0 && compareAndSetWaitStatus(pred, ws, Node.SIGNAL))) &&
+ pred.thread != null) {
+ Node next = node.next;
+ if (next != null && next.waitStatus <= 0)
+ compareAndSetNext(pred, predNext, next);
+ } else {
+ unparkSuccessor(node);
+ }
+
+ node.next = node; // help GC
+ }
+ }
+
+ /**
+ * Checks and updates status for a node that failed to acquire.
+ * Returns true if thread should block. This is the main signal
+ * control in all acquire loops. Requires that pred == node.prev
+ *
+ * @param pred node's predecessor holding status
+ * @param node the node
+ * @return {@code true} if thread should block
+ */
+ private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
+ int ws = pred.waitStatus;
+ if (ws == Node.SIGNAL)
+ /*
+ * This node has already set status asking a release
+ * to signal it, so it can safely park.
+ */
+ return true;
+ if (ws > 0) {
+ /*
+ * Predecessor was cancelled. Skip over predecessors and
+ * indicate retry.
+ */
+ do {
+ node.prev = pred = pred.prev;
+ } while (pred.waitStatus > 0);
+ pred.next = node;
+ } else {
+ /*
+ * waitStatus must be 0 or PROPAGATE. Indicate that we
+ * need a signal, but don't park yet. Caller will need to
+ * retry to make sure it cannot acquire before parking.
+ */
+ compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
+ }
+ return false;
+ }
+
+ /**
+ * Convenience method to interrupt current thread.
+ */
+ private static void selfInterrupt() {
+ Thread.currentThread().interrupt();
+ }
+
+ /**
+ * Convenience method to park and then check if interrupted
+ *
+ * @return {@code true} if interrupted
+ */
+ private final boolean parkAndCheckInterrupt() {
+ LockSupport.park(this);
+ return Thread.interrupted();
+ }
+
+ /*
+ * Various flavors of acquire, varying in exclusive/shared and
+ * control modes. Each is mostly the same, but annoyingly
+ * different. Only a little bit of factoring is possible due to
+ * interactions of exception mechanics (including ensuring that we
+ * cancel if tryAcquire throws exception) and other control, at
+ * least not without hurting performance too much.
+ */
+
+ /**
+ * Acquires in exclusive uninterruptible mode for thread already in
+ * queue. Used by condition wait methods as well as acquire.
+ *
+ * @param node the node
+ * @param arg the acquire argument
+ * @return {@code true} if interrupted while waiting
+ */
+ final boolean acquireQueued(final Node node, long arg) {
+ boolean failed = true;
+ try {
+ boolean interrupted = false;
+ for (;;) {
+ final Node p = node.predecessor();
+ if (p == head && tryAcquire(arg)) {
+ setHead(node);
+ p.next = null; // help GC
+ failed = false;
+ return interrupted;
+ }
+ if (shouldParkAfterFailedAcquire(p, node) &&
+ parkAndCheckInterrupt())
+ interrupted = true;
+ }
+ } finally {
+ if (failed)
+ cancelAcquire(node);
+ }
+ }
+
+ /**
+ * Acquires in exclusive interruptible mode.
+ * @param arg the acquire argument
+ */
+ private void doAcquireInterruptibly(long arg)
+ throws InterruptedException {
+ final Node node = addWaiter(Node.EXCLUSIVE);
+ boolean failed = true;
+ try {
+ for (;;) {
+ final Node p = node.predecessor();
+ if (p == head && tryAcquire(arg)) {
+ setHead(node);
+ p.next = null; // help GC
+ failed = false;
+ return;
+ }
+ if (shouldParkAfterFailedAcquire(p, node) &&
+ parkAndCheckInterrupt())
+ throw new InterruptedException();
+ }
+ } finally {
+ if (failed)
+ cancelAcquire(node);
+ }
+ }
+
+ /**
+ * Acquires in exclusive timed mode.
+ *
+ * @param arg the acquire argument
+ * @param nanosTimeout max wait time
+ * @return {@code true} if acquired
+ */
+ private boolean doAcquireNanos(long arg, long nanosTimeout)
+ throws InterruptedException {
+ long lastTime = System.nanoTime();
+ final Node node = addWaiter(Node.EXCLUSIVE);
+ boolean failed = true;
+ try {
+ for (;;) {
+ final Node p = node.predecessor();
+ if (p == head && tryAcquire(arg)) {
+ setHead(node);
+ p.next = null; // help GC
+ failed = false;
+ return true;
+ }
+ if (nanosTimeout <= 0)
+ return false;
+ if (shouldParkAfterFailedAcquire(p, node) &&
+ nanosTimeout > spinForTimeoutThreshold)
+ LockSupport.parkNanos(this, nanosTimeout);
+ long now = System.nanoTime();
+ nanosTimeout -= now - lastTime;
+ lastTime = now;
+ if (Thread.interrupted())
+ throw new InterruptedException();
+ }
+ } finally {
+ if (failed)
+ cancelAcquire(node);
+ }
+ }
+
+ /**
+ * Acquires in shared uninterruptible mode.
+ * @param arg the acquire argument
+ */
+ private void doAcquireShared(long arg) {
+ final Node node = addWaiter(Node.SHARED);
+ boolean failed = true;
+ try {
+ boolean interrupted = false;
+ for (;;) {
+ final Node p = node.predecessor();
+ if (p == head) {
+ long r = tryAcquireShared(arg);
+ if (r >= 0) {
+ setHeadAndPropagate(node, r);
+ p.next = null; // help GC
+ if (interrupted)
+ selfInterrupt();
+ failed = false;
+ return;
+ }
+ }
+ if (shouldParkAfterFailedAcquire(p, node) &&
+ parkAndCheckInterrupt())
+ interrupted = true;
+ }
+ } finally {
+ if (failed)
+ cancelAcquire(node);
+ }
+ }
+
+ /**
+ * Acquires in shared interruptible mode.
+ * @param arg the acquire argument
+ */
+ private void doAcquireSharedInterruptibly(long arg)
+ throws InterruptedException {
+ final Node node = addWaiter(Node.SHARED);
+ boolean failed = true;
+ try {
+ for (;;) {
+ final Node p = node.predecessor();
+ if (p == head) {
+ long r = tryAcquireShared(arg);
+ if (r >= 0) {
+ setHeadAndPropagate(node, r);
+ p.next = null; // help GC
+ failed = false;
+ return;
+ }
+ }
+ if (shouldParkAfterFailedAcquire(p, node) &&
+ parkAndCheckInterrupt())
+ throw new InterruptedException();
+ }
+ } finally {
+ if (failed)
+ cancelAcquire(node);
+ }
+ }
+
+ /**
+ * Acquires in shared timed mode.
+ *
+ * @param arg the acquire argument
+ * @param nanosTimeout max wait time
+ * @return {@code true} if acquired
+ */
+ private boolean doAcquireSharedNanos(long arg, long nanosTimeout)
+ throws InterruptedException {
+
+ long lastTime = System.nanoTime();
+ final Node node = addWaiter(Node.SHARED);
+ boolean failed = true;
+ try {
+ for (;;) {
+ final Node p = node.predecessor();
+ if (p == head) {
+ long r = tryAcquireShared(arg);
+ if (r >= 0) {
+ setHeadAndPropagate(node, r);
+ p.next = null; // help GC
+ failed = false;
+ return true;
+ }
+ }
+ if (nanosTimeout <= 0)
+ return false;
+ if (shouldParkAfterFailedAcquire(p, node) &&
+ nanosTimeout > spinForTimeoutThreshold)
+ LockSupport.parkNanos(this, nanosTimeout);
+ long now = System.nanoTime();
+ nanosTimeout -= now - lastTime;
+ lastTime = now;
+ if (Thread.interrupted())
+ throw new InterruptedException();
+ }
+ } finally {
+ if (failed)
+ cancelAcquire(node);
+ }
+ }
+
+ // Main exported methods
+
+ /**
+ * Attempts to acquire in exclusive mode. This method should query
+ * if the state of the object permits it to be acquired in the
+ * exclusive mode, and if so to acquire it.
+ *
+ * <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 {@code true} if successful. Upon success, this object has
+ * been acquired.
+ * @throws IllegalMonitorStateException if acquiring would place this
+ * synchronizer in an illegal state. This exception must be
+ * thrown in a consistent fashion for synchronization to work
+ * correctly.
+ * @throws UnsupportedOperationException if exclusive mode is not supported
+ */
+ protected boolean tryAcquire(long arg) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Attempts to set the state to reflect a release in exclusive
+ * mode.
+ *
+ * <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 {@code true} if this object is now in a fully released
+ * state, so that any waiting threads may attempt to acquire;
+ * and {@code false} otherwise.
+ * @throws IllegalMonitorStateException if releasing would place this
+ * synchronizer in an illegal state. This exception must be
+ * thrown in a consistent fashion for synchronization to work
+ * correctly.
+ * @throws UnsupportedOperationException if exclusive mode is not supported
+ */
+ protected boolean tryRelease(long arg) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Attempts to acquire in shared mode. This method should query if
+ * the state of the object permits it to be acquired in the shared
+ * mode, and if so to acquire it.
+ *
+ * <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 if acquisition in shared
+ * mode succeeded but no subsequent shared-mode acquire can
+ * succeed; and a positive value if acquisition in shared
+ * mode succeeded and subsequent shared-mode acquires might
+ * also succeed, in which case a subsequent waiting thread
+ * must check availability. (Support for three different
+ * return values enables this method to be used in contexts
+ * where acquires only sometimes act exclusively.) Upon
+ * success, this object has been acquired.
+ * @throws IllegalMonitorStateException if acquiring would place this
+ * synchronizer in an illegal state. This exception must be
+ * thrown in a consistent fashion for synchronization to work
+ * correctly.
+ * @throws UnsupportedOperationException if shared mode is not supported
+ */
+ protected long tryAcquireShared(long arg) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Attempts to set the state to reflect a release in shared mode.
+ *
+ * <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 {@code true} if this release of shared mode may permit a
+ * waiting acquire (shared or exclusive) to succeed; and
+ * {@code false} otherwise
+ * @throws IllegalMonitorStateException if releasing would place this
+ * synchronizer in an illegal state. This exception must be
+ * thrown in a consistent fashion for synchronization to work
+ * correctly.
+ * @throws UnsupportedOperationException if shared mode is not supported
+ */
+ protected boolean tryReleaseShared(long arg) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Returns {@code true} if synchronization is held exclusively with
+ * respect to the current (calling) thread. This method is invoked
+ * upon each call to a non-waiting {@link ConditionObject} method.
+ * (Waiting methods instead invoke {@link #release}.)
+ *
+ * <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 {@code true} if synchronization is held exclusively;
+ * {@code false} otherwise
+ * @throws UnsupportedOperationException if conditions are not supported
+ */
+ protected boolean isHeldExclusively() {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Acquires in exclusive mode, ignoring interrupts. Implemented
+ * by invoking at least once {@link #tryAcquire},
+ * returning on success. Otherwise the thread is queued, possibly
+ * repeatedly blocking and unblocking, invoking {@link
+ * #tryAcquire} until success. This method can be used
+ * to implement method {@link Lock#lock}.
+ *
+ * @param arg the acquire argument. This value is conveyed to
+ * {@link #tryAcquire} but is otherwise uninterpreted and
+ * can represent anything you like.
+ */
+ public final void acquire(long arg) {
+ if (!tryAcquire(arg) &&
+ acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
+ selfInterrupt();
+ }
+
+ /**
+ * Acquires in exclusive mode, aborting if interrupted.
+ * Implemented by first checking interrupt status, then invoking
+ * at least once {@link #tryAcquire}, returning on
+ * success. Otherwise the thread is queued, possibly repeatedly
+ * blocking and unblocking, invoking {@link #tryAcquire}
+ * until success or the thread is interrupted. This method can be
+ * used to implement method {@link Lock#lockInterruptibly}.
+ *
+ * @param arg the acquire argument. This value is conveyed to
+ * {@link #tryAcquire} but is otherwise uninterpreted and
+ * can represent anything you like.
+ * @throws InterruptedException if the current thread is interrupted
+ */
+ public final void acquireInterruptibly(long arg) throws InterruptedException {
+ if (Thread.interrupted())
+ throw new InterruptedException();
+ if (!tryAcquire(arg))
+ doAcquireInterruptibly(arg);
+ }
+
+ /**
+ * Attempts to acquire in exclusive mode, aborting if interrupted,
+ * and failing if the given timeout elapses. Implemented by first
+ * checking interrupt status, then invoking at least once {@link
+ * #tryAcquire}, returning on success. Otherwise, the thread is
+ * queued, possibly repeatedly blocking and unblocking, invoking
+ * {@link #tryAcquire} until success or the thread is interrupted
+ * or the timeout elapses. This method can be used to implement
+ * method {@link Lock#tryLock(long, TimeUnit)}.
+ *
+ * @param arg the acquire argument. This value is conveyed to
+ * {@link #tryAcquire} but is otherwise uninterpreted and
+ * can represent anything you like.
+ * @param nanosTimeout the maximum number of nanoseconds to wait
+ * @return {@code true} if acquired; {@code false} if timed out
+ * @throws InterruptedException if the current thread is interrupted
+ */
+ public final boolean tryAcquireNanos(long arg, long nanosTimeout) throws InterruptedException {
+ if (Thread.interrupted())
+ throw new InterruptedException();
+ return tryAcquire(arg) ||
+ doAcquireNanos(arg, nanosTimeout);
+ }
+
+ /**
+ * Releases in exclusive mode. Implemented by unblocking one or
+ * more threads if {@link #tryRelease} returns true.
+ * This method can be used to implement method {@link Lock#unlock}.
+ *
+ * @param arg the release argument. This value is conveyed to
+ * {@link #tryRelease} but is otherwise uninterpreted and
+ * can represent anything you like.
+ * @return the value returned from {@link #tryRelease}
+ */
+ public final boolean release(long arg) {
+ if (tryRelease(arg)) {
+ Node h = head;
+ if (h != null && h.waitStatus != 0)
+ unparkSuccessor(h);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Acquires in shared mode, ignoring interrupts. Implemented by
+ * first invoking at least once {@link #tryAcquireShared},
+ * returning on success. Otherwise the thread is queued, possibly
+ * repeatedly blocking and unblocking, invoking {@link
+ * #tryAcquireShared} until success.
+ *
+ * @param arg the acquire argument. This value is conveyed to
+ * {@link #tryAcquireShared} but is otherwise uninterpreted
+ * and can represent anything you like.
+ */
+ public final void acquireShared(long arg) {
+ if (tryAcquireShared(arg) < 0)
+ doAcquireShared(arg);
+ }
+
+ /**
+ * Acquires in shared mode, aborting if interrupted. Implemented
+ * by first checking interrupt status, then invoking at least once
+ * {@link #tryAcquireShared}, returning on success. Otherwise the
+ * thread is queued, possibly repeatedly blocking and unblocking,
+ * invoking {@link #tryAcquireShared} until success or the thread
+ * is interrupted.
+ * @param arg the acquire argument
+ * This value is conveyed to {@link #tryAcquireShared} but is
+ * otherwise uninterpreted and can represent anything
+ * you like.
+ * @throws InterruptedException if the current thread is interrupted
+ */
+ public final void acquireSharedInterruptibly(long arg) throws InterruptedException {
+ if (Thread.interrupted())
+ throw new InterruptedException();
+ if (tryAcquireShared(arg) < 0)
+ doAcquireSharedInterruptibly(arg);
+ }
+
+ /**
+ * Attempts to acquire in shared mode, aborting if interrupted, and
+ * failing if the given timeout elapses. Implemented by first
+ * checking interrupt status, then invoking at least once {@link
+ * #tryAcquireShared}, returning on success. Otherwise, the
+ * thread is queued, possibly repeatedly blocking and unblocking,
+ * invoking {@link #tryAcquireShared} until success or the thread
+ * is interrupted or the timeout elapses.
+ *
+ * @param arg the acquire argument. This value is conveyed to
+ * {@link #tryAcquireShared} but is otherwise uninterpreted
+ * and can represent anything you like.
+ * @param nanosTimeout the maximum number of nanoseconds to wait
+ * @return {@code true} if acquired; {@code false} if timed out
+ * @throws InterruptedException if the current thread is interrupted
+ */
+ public final boolean tryAcquireSharedNanos(long arg, long nanosTimeout) throws InterruptedException {
+ if (Thread.interrupted())
+ throw new InterruptedException();
+ return tryAcquireShared(arg) >= 0 ||
+ doAcquireSharedNanos(arg, nanosTimeout);
+ }
+
+ /**
+ * Releases in shared mode. Implemented by unblocking one or more
+ * threads if {@link #tryReleaseShared} returns true.
+ *
+ * @param arg the release argument. This value is conveyed to
+ * {@link #tryReleaseShared} but is otherwise uninterpreted
+ * and can represent anything you like.
+ * @return the value returned from {@link #tryReleaseShared}
+ */
+ public final boolean releaseShared(long arg) {
+ if (tryReleaseShared(arg)) {
+ doReleaseShared();
+ return true;
+ }
+ return false;
+ }
+
+ // Queue inspection methods
+
+ /**
+ * Queries whether any threads are waiting to acquire. Note that
+ * because cancellations due to interrupts and timeouts may occur
+ * at any time, a {@code true} return does not guarantee that any
+ * other thread will ever acquire.
+ *
+ * <p>In this implementation, this operation returns in
+ * constant time.
+ *
+ * @return {@code true} if there may be other threads waiting to acquire
+ */
+ public final boolean hasQueuedThreads() {
+ return head != tail;
+ }
+
+ /**
+ * Queries whether any threads have ever contended to acquire this
+ * synchronizer; that is if an acquire method has ever blocked.
+ *
+ * <p>In this implementation, this operation returns in
+ * constant time.
+ *
+ * @return {@code true} if there has ever been contention
+ */
+ public final boolean hasContended() {
+ return head != null;
+ }
+
+ /**
+ * Returns the first (longest-waiting) thread in the queue, or
+ * {@code null} if no threads are currently queued.
+ *
+ * <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
+ * {@code null} if no threads are currently queued
+ */
+ public final Thread getFirstQueuedThread() {
+ // handle only fast path, else relay
+ return (head == tail) ? null : fullGetFirstQueuedThread();
+ }
+
+ /**
+ * Version of getFirstQueuedThread called when fastpath fails
+ */
+ private Thread fullGetFirstQueuedThread() {
+ /*
+ * The first node is normally head.next. Try to get its
+ * thread field, ensuring consistent reads: If thread
+ * field is nulled out or s.prev is no longer head, then
+ * some other thread(s) concurrently performed setHead in
+ * between some of our reads. We try this twice before
+ * resorting to traversal.
+ */
+ Node h, s;
+ Thread st;
+ if (((h = head) != null && (s = h.next) != null &&
+ s.prev == head && (st = s.thread) != null) ||
+ ((h = head) != null && (s = h.next) != null &&
+ s.prev == head && (st = s.thread) != null))
+ return st;
+
+ /*
+ * Head's next field might not have been set yet, or may have
+ * been unset after setHead. So we must check to see if tail
+ * is actually first node. If not, we continue on, safely
+ * traversing from tail back to head to find first,
+ * guaranteeing termination.
+ */
+
+ Node t = tail;
+ Thread firstThread = null;
+ while (t != null && t != head) {
+ Thread tt = t.thread;
+ if (tt != null)
+ firstThread = tt;
+ t = t.prev;
+ }
+ return firstThread;
+ }
+
+ /**
+ * Returns true if the given thread is currently queued.
+ *
+ * <p>This implementation traverses the queue to determine
+ * presence of the given thread.
+ *
+ * @param thread the thread
+ * @return {@code true} if the given thread is on the queue
+ * @throws NullPointerException if the thread is null
+ */
+ public final boolean isQueued(Thread thread) {
+ if (thread == null)
+ throw new NullPointerException();
+ for (Node p = tail; p != null; p = p.prev)
+ if (p.thread == thread)
+ return true;
+ return false;
+ }
+
+ /**
+ * Returns {@code true} if the apparent first queued thread, if one
+ * exists, is waiting in exclusive mode. If this method returns
+ * {@code true}, and the current thread is attempting to acquire in
+ * shared mode (that is, this method is invoked from {@link
+ * #tryAcquireShared}) then it is guaranteed that the current thread
+ * is not the first queued thread. Used only as a heuristic in
+ * ReentrantReadWriteLock.
+ */
+ final boolean apparentlyFirstQueuedIsExclusive() {
+ Node h, s;
+ return (h = head) != null &&
+ (s = h.next) != null &&
+ !s.isShared() &&
+ s.thread != null;
+ }
+
+ /**
+ * Queries whether any threads have been waiting to acquire longer
+ * than the current thread.
+ *
+ * <p>An invocation of this method is equivalent to (but may be
+ * more efficient than):
+ * <pre> {@code
+ * getFirstQueuedThread() != Thread.currentThread() &&
+ * hasQueuedThreads()}</pre>
+ *
+ * <p>Note that because cancellations due to interrupts and
+ * timeouts may occur at any time, a {@code true} return does not
+ * guarantee that some other thread will acquire before the current
+ * thread. Likewise, it is possible for another thread to win a
+ * race to enqueue after this method has returned {@code false},
+ * due to the queue being empty.
+ *
+ * <p>This method is designed to be used by a fair synchronizer to
+ * avoid <a href="AbstractQueuedSynchronizer#barging">barging</a>.
+ * Such a synchronizer's {@link #tryAcquire} method should return
+ * {@code false}, and its {@link #tryAcquireShared} method should
+ * return a negative value, if this method returns {@code true}
+ * (unless this is a reentrant acquire). For example, the {@code
+ * tryAcquire} method for a fair, reentrant, exclusive mode
+ * synchronizer might look like this:
+ *
+ * <pre> {@code
+ * protected boolean tryAcquire(int arg) {
+ * if (isHeldExclusively()) {
+ * // A reentrant acquire; increment hold count
+ * return true;
+ * } else if (hasQueuedPredecessors()) {
+ * return false;
+ * } else {
+ * // try to acquire normally
+ * }
+ * }}</pre>
+ *
+ * @return {@code true} if there is a queued thread preceding the
+ * current thread, and {@code false} if the current thread
+ * is at the head of the queue or the queue is empty
+ * @since 1.7
+ */
+ /*public*/ final boolean hasQueuedPredecessors() { // android-changed
+ // The correctness of this depends on head being initialized
+ // before tail and on head.next being accurate if the current
+ // thread is first in queue.
+ Node t = tail; // Read fields in reverse initialization order
+ Node h = head;
+ Node s;
+ return h != t &&
+ ((s = h.next) == null || s.thread != Thread.currentThread());
+ }
+
+
+ // Instrumentation and monitoring methods
+
+ /**
+ * Returns an estimate of the number of threads waiting to
+ * acquire. The value is only an estimate because the number of
+ * threads may change dynamically while this method traverses
+ * internal data structures. This method is designed for use in
+ * monitoring system state, not for synchronization
+ * control.
+ *
+ * @return the estimated number of threads waiting to acquire
+ */
+ public final int getQueueLength() {
+ int n = 0;
+ for (Node p = tail; p != null; p = p.prev) {
+ if (p.thread != null)
+ ++n;
+ }
+ return n;
+ }
+
+ /**
+ * Returns a collection containing threads that may be waiting to
+ * acquire. Because the actual set of threads may change
+ * dynamically while constructing this result, the returned
+ * collection is only a best-effort estimate. The elements of the
+ * returned collection are in no particular order. This method is
+ * designed to facilitate construction of subclasses that provide
+ * more extensive monitoring facilities.
+ *
+ * @return the collection of threads
+ */
+ public final Collection<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 {@code "State ="}
+ * followed by the current value of {@link #getState}, and either
+ * {@code "nonempty"} or {@code "empty"} depending on whether the
+ * queue is empty.
+ *
+ * @return a string identifying this synchronizer, as well as its state
+ */
+ public String toString() {
+ long s = getState();
+ String q = hasQueuedThreads() ? "non" : "";
+ return super.toString() +
+ "[State = " + s + ", " + q + "empty queue]";
+ }
+
+
+ // Internal support methods for Conditions
+
+ /**
+ * Returns true if a node, always one that was initially placed on
+ * a condition queue, is now waiting to reacquire on sync queue.
+ * @param node the node
+ * @return true if is reacquiring
+ */
+ final boolean isOnSyncQueue(Node node) {
+ if (node.waitStatus == Node.CONDITION || node.prev == null)
+ return false;
+ if (node.next != null) // If has successor, it must be on queue
+ return true;
+ /*
+ * node.prev can be non-null, but not yet on queue because
+ * the CAS to place it on queue can fail. So we have to
+ * traverse from tail to make sure it actually made it. It
+ * will always be near the tail in calls to this method, and
+ * unless the CAS failed (which is unlikely), it will be
+ * there, so we hardly ever traverse much.
+ */
+ return findNodeFromTail(node);
+ }
+
+ /**
+ * Returns true if node is on sync queue by searching backwards from tail.
+ * Called only when needed by isOnSyncQueue.
+ * @return true if present
+ */
+ private boolean findNodeFromTail(Node node) {
+ Node t = tail;
+ for (;;) {
+ if (t == node)
+ return true;
+ if (t == null)
+ return false;
+ t = t.prev;
+ }
+ }
+
+ /**
+ * Transfers a node from a condition queue onto sync queue.
+ * Returns true if successful.
+ * @param node the node
+ * @return true if successfully transferred (else the node was
+ * cancelled before signal).
+ */
+ final boolean transferForSignal(Node node) {
+ /*
+ * If cannot change waitStatus, the node has been cancelled.
+ */
+ if (!compareAndSetWaitStatus(node, Node.CONDITION, 0))
+ return false;
+
+ /*
+ * Splice onto queue and try to set waitStatus of predecessor to
+ * indicate that thread is (probably) waiting. If cancelled or
+ * attempt to set waitStatus fails, wake up to resync (in which
+ * case the waitStatus can be transiently and harmlessly wrong).
+ */
+ Node p = enq(node);
+ int ws = p.waitStatus;
+ if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))
+ LockSupport.unpark(node.thread);
+ return true;
+ }
+
+ /**
+ * Transfers node, if necessary, to sync queue after a cancelled
+ * wait. Returns true if thread was cancelled before being
+ * signalled.
+ * @param current the waiting thread
+ * @param node its node
+ * @return true if cancelled before the node was signalled
+ */
+ final boolean transferAfterCancelledWait(Node node) {
+ if (compareAndSetWaitStatus(node, Node.CONDITION, 0)) {
+ enq(node);
+ return true;
+ }
+ /*
+ * If we lost out to a signal(), then we can't proceed
+ * until it finishes its enq(). Cancelling during an
+ * incomplete transfer is both rare and transient, so just
+ * spin.
+ */
+ while (!isOnSyncQueue(node))
+ Thread.yield();
+ return false;
+ }
+
+ /**
+ * Invokes release with current state value; returns saved state.
+ * Cancels node and throws exception on failure.
+ * @param node the condition node for this wait
+ * @return previous sync state
+ */
+ final long fullyRelease(Node node) {
+ boolean failed = true;
+ try {
+ long savedState = getState();
+ if (release(savedState)) {
+ failed = false;
+ return savedState;
+ } else {
+ throw new IllegalMonitorStateException();
+ }
+ } finally {
+ if (failed)
+ node.waitStatus = Node.CANCELLED;
+ }
+ }
+
+ // Instrumentation methods for conditions
+
+ /**
+ * Queries whether the given ConditionObject
+ * uses this synchronizer as its lock.
+ *
+ * @param condition the condition
+ * @return <tt>true</tt> if owned
+ * @throws NullPointerException if the condition is null
+ */
+ public final boolean owns(ConditionObject condition) {
+ if (condition == null)
+ throw new NullPointerException();
+ return condition.isOwnedBy(this);
+ }
+
+ /**
+ * Queries whether any threads are waiting on the given condition
+ * associated with this synchronizer. Note that because timeouts
+ * and interrupts may occur at any time, a <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 the condition is null
+ */
+ public final boolean hasWaiters(ConditionObject condition) {
+ if (!owns(condition))
+ throw new IllegalArgumentException("Not owner");
+ return condition.hasWaiters();
+ }
+
+ /**
+ * Returns an estimate of the number of threads waiting on the
+ * given condition associated with this synchronizer. Note that
+ * because timeouts and interrupts may occur at any time, the
+ * estimate serves only as an upper bound on the actual number of
+ * waiters. This method is designed for use in monitoring of the
+ * system state, not for synchronization control.
+ *
+ * @param condition the condition
+ * @return the estimated number of waiting threads
+ * @throws IllegalMonitorStateException if exclusive synchronization
+ * is not held
+ * @throws IllegalArgumentException if the given condition is
+ * not associated with this synchronizer
+ * @throws NullPointerException if the condition is null
+ */
+ public final int getWaitQueueLength(ConditionObject condition) {
+ if (!owns(condition))
+ throw new IllegalArgumentException("Not owner");
+ return condition.getWaitQueueLength();
+ }
+
+ /**
+ * Returns a collection containing those threads that may be
+ * waiting on the given condition associated with this
+ * synchronizer. Because the actual set of threads may change
+ * dynamically while constructing this result, the returned
+ * collection is only a best-effort estimate. The elements of the
+ * returned collection are in no particular order.
+ *
+ * @param condition the condition
+ * @return the collection of threads
+ * @throws IllegalMonitorStateException if exclusive synchronization
+ * is not held
+ * @throws IllegalArgumentException if the given condition is
+ * not associated with this synchronizer
+ * @throws NullPointerException if the condition is null
+ */
+ public final Collection<Thread> getWaitingThreads(ConditionObject condition) {
+ if (!owns(condition))
+ throw new IllegalArgumentException("Not owner");
+ return condition.getWaitingThreads();
+ }
+
+ /**
+ * Condition implementation for a {@link
+ * AbstractQueuedLongSynchronizer} serving as the basis of a {@link
+ * Lock} implementation.
+ *
+ * <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>AbstractQueuedLongSynchronizer</tt>.
+ *
+ * <p>This class is Serializable, but all fields are transient,
+ * so deserialized conditions have no waiters.
+ *
+ * @since 1.6
+ */
+ public class ConditionObject implements Condition, java.io.Serializable {
+ private static final long serialVersionUID = 1173984872572414699L;
+ /** First node of condition queue. */
+ private transient Node firstWaiter;
+ /** Last node of condition queue. */
+ private transient Node lastWaiter;
+
+ /**
+ * Creates a new <tt>ConditionObject</tt> instance.
+ */
+ public ConditionObject() { }
+
+ // Internal methods
+
+ /**
+ * Adds a new waiter to wait queue.
+ * @return its new wait node
+ */
+ private Node addConditionWaiter() {
+ Node t = lastWaiter;
+ // If lastWaiter is cancelled, clean out.
+ if (t != null && t.waitStatus != Node.CONDITION) {
+ unlinkCancelledWaiters();
+ t = lastWaiter;
+ }
+ Node node = new Node(Thread.currentThread(), Node.CONDITION);
+ if (t == null)
+ firstWaiter = node;
+ else
+ t.nextWaiter = node;
+ lastWaiter = node;
+ return node;
+ }
+
+ /**
+ * Removes and transfers nodes until hit non-cancelled one or
+ * null. Split out from signal in part to encourage compilers
+ * to inline the case of no waiters.
+ * @param first (non-null) the first node on condition queue
+ */
+ private void doSignal(Node first) {
+ do {
+ if ( (firstWaiter = first.nextWaiter) == null)
+ lastWaiter = null;
+ first.nextWaiter = null;
+ } while (!transferForSignal(first) &&
+ (first = firstWaiter) != null);
+ }
+
+ /**
+ * Removes and transfers all nodes.
+ * @param first (non-null) the first node on condition queue
+ */
+ private void doSignalAll(Node first) {
+ lastWaiter = firstWaiter = null;
+ do {
+ Node next = first.nextWaiter;
+ first.nextWaiter = null;
+ transferForSignal(first);
+ first = next;
+ } while (first != null);
+ }
+
+ /**
+ * Unlinks cancelled waiter nodes from condition queue.
+ * Called only while holding lock. This is called when
+ * cancellation occurred during condition wait, and upon
+ * insertion of a new waiter when lastWaiter is seen to have
+ * been cancelled. This method is needed to avoid garbage
+ * retention in the absence of signals. So even though it may
+ * require a full traversal, it comes into play only when
+ * timeouts or cancellations occur in the absence of
+ * signals. It traverses all nodes rather than stopping at a
+ * particular target to unlink all pointers to garbage nodes
+ * without requiring many re-traversals during cancellation
+ * storms.
+ */
+ private void unlinkCancelledWaiters() {
+ Node t = firstWaiter;
+ Node trail = null;
+ while (t != null) {
+ Node next = t.nextWaiter;
+ if (t.waitStatus != Node.CONDITION) {
+ t.nextWaiter = null;
+ if (trail == null)
+ firstWaiter = next;
+ else
+ trail.nextWaiter = next;
+ if (next == null)
+ lastWaiter = trail;
+ }
+ else
+ trail = t;
+ t = next;
+ }
+ }
+
+ // public methods
+
+ /**
+ * Moves the longest-waiting thread, if one exists, from the
+ * wait queue for this condition to the wait queue for the
+ * owning lock.
+ *
+ * @throws IllegalMonitorStateException if {@link #isHeldExclusively}
+ * returns {@code false}
+ */
+ public final void signal() {
+ if (!isHeldExclusively())
+ throw new IllegalMonitorStateException();
+ Node first = firstWaiter;
+ if (first != null)
+ doSignal(first);
+ }
+
+ /**
+ * Moves all threads from the wait queue for this condition to
+ * the wait queue for the owning lock.
+ *
+ * @throws IllegalMonitorStateException if {@link #isHeldExclusively}
+ * returns {@code false}
+ */
+ public final void signalAll() {
+ if (!isHeldExclusively())
+ throw new IllegalMonitorStateException();
+ Node first = firstWaiter;
+ if (first != null)
+ doSignalAll(first);
+ }
+
+ /**
+ * Implements uninterruptible condition wait.
+ * <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();
+ long savedState = fullyRelease(node);
+ boolean interrupted = false;
+ while (!isOnSyncQueue(node)) {
+ LockSupport.park(this);
+ if (Thread.interrupted())
+ interrupted = true;
+ }
+ if (acquireQueued(node, savedState) || interrupted)
+ selfInterrupt();
+ }
+
+ /*
+ * For interruptible waits, we need to track whether to throw
+ * InterruptedException, if interrupted while blocked on
+ * condition, versus reinterrupt current thread, if
+ * interrupted while blocked waiting to re-acquire.
+ */
+
+ /** Mode meaning to reinterrupt on exit from wait */
+ private static final int REINTERRUPT = 1;
+ /** Mode meaning to throw InterruptedException on exit from wait */
+ private static final int THROW_IE = -1;
+
+ /**
+ * Checks for interrupt, returning THROW_IE if interrupted
+ * before signalled, REINTERRUPT if after signalled, or
+ * 0 if not interrupted.
+ */
+ private int checkInterruptWhileWaiting(Node node) {
+ return Thread.interrupted() ?
+ (transferAfterCancelledWait(node) ? THROW_IE : REINTERRUPT) :
+ 0;
+ }
+
+ /**
+ * Throws InterruptedException, reinterrupts current thread, or
+ * does nothing, depending on mode.
+ */
+ private void reportInterruptAfterWait(int interruptMode)
+ throws InterruptedException {
+ if (interruptMode == THROW_IE)
+ throw new InterruptedException();
+ else if (interruptMode == REINTERRUPT)
+ selfInterrupt();
+ }
+
+ /**
+ * Implements interruptible condition wait.
+ * <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 InterruptedException.
+ * </ol>
+ */
+ public final void await() throws InterruptedException {
+ if (Thread.interrupted())
+ throw new InterruptedException();
+ Node node = addConditionWaiter();
+ long savedState = fullyRelease(node);
+ int interruptMode = 0;
+ while (!isOnSyncQueue(node)) {
+ LockSupport.park(this);
+ if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
+ break;
+ }
+ if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
+ interruptMode = REINTERRUPT;
+ if (node.nextWaiter != null) // clean up if cancelled
+ unlinkCancelledWaiters();
+ if (interruptMode != 0)
+ reportInterruptAfterWait(interruptMode);
+ }
+
+ /**
+ * Implements timed condition wait.
+ * <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>
+ */
+ public final long awaitNanos(long nanosTimeout) throws InterruptedException {
+ if (Thread.interrupted())
+ throw new InterruptedException();
+ Node node = addConditionWaiter();
+ long savedState = fullyRelease(node);
+ long lastTime = System.nanoTime();
+ int interruptMode = 0;
+ while (!isOnSyncQueue(node)) {
+ if (nanosTimeout <= 0L) {
+ transferAfterCancelledWait(node);
+ break;
+ }
+ LockSupport.parkNanos(this, nanosTimeout);
+ if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
+ break;
+
+ long now = System.nanoTime();
+ nanosTimeout -= now - lastTime;
+ lastTime = now;
+ }
+ if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
+ interruptMode = REINTERRUPT;
+ if (node.nextWaiter != null)
+ unlinkCancelledWaiters();
+ if (interruptMode != 0)
+ reportInterruptAfterWait(interruptMode);
+ return nanosTimeout - (System.nanoTime() - lastTime);
+ }
+
+ /**
+ * Implements absolute timed condition wait.
+ * <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>
+ */
+ public final boolean awaitUntil(Date deadline) throws InterruptedException {
+ if (deadline == null)
+ throw new NullPointerException();
+ long abstime = deadline.getTime();
+ if (Thread.interrupted())
+ throw new InterruptedException();
+ Node node = addConditionWaiter();
+ long savedState = fullyRelease(node);
+ boolean timedout = false;
+ int interruptMode = 0;
+ while (!isOnSyncQueue(node)) {
+ if (System.currentTimeMillis() > abstime) {
+ timedout = transferAfterCancelledWait(node);
+ break;
+ }
+ LockSupport.parkUntil(this, abstime);
+ if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
+ break;
+ }
+ if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
+ interruptMode = REINTERRUPT;
+ if (node.nextWaiter != null)
+ unlinkCancelledWaiters();
+ if (interruptMode != 0)
+ reportInterruptAfterWait(interruptMode);
+ return !timedout;
+ }
+
+ /**
+ * Implements timed condition wait.
+ * <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>
+ */
+ public final boolean await(long time, TimeUnit unit) throws InterruptedException {
+ if (unit == null)
+ throw new NullPointerException();
+ long nanosTimeout = unit.toNanos(time);
+ if (Thread.interrupted())
+ throw new InterruptedException();
+ Node node = addConditionWaiter();
+ long savedState = fullyRelease(node);
+ long lastTime = System.nanoTime();
+ boolean timedout = false;
+ int interruptMode = 0;
+ while (!isOnSyncQueue(node)) {
+ if (nanosTimeout <= 0L) {
+ timedout = transferAfterCancelledWait(node);
+ break;
+ }
+ if (nanosTimeout >= spinForTimeoutThreshold)
+ LockSupport.parkNanos(this, nanosTimeout);
+ if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
+ break;
+ long now = System.nanoTime();
+ nanosTimeout -= now - lastTime;
+ lastTime = now;
+ }
+ if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
+ interruptMode = REINTERRUPT;
+ if (node.nextWaiter != null)
+ unlinkCancelledWaiters();
+ if (interruptMode != 0)
+ reportInterruptAfterWait(interruptMode);
+ return !timedout;
+ }
+
+ // support for instrumentation
+
+ /**
+ * Returns true if this condition was created by the given
+ * synchronization object.
+ *
+ * @return {@code true} if owned
+ */
+ final boolean isOwnedBy(AbstractQueuedLongSynchronizer sync) {
+ return sync == AbstractQueuedLongSynchronizer.this;
+ }
+
+ /**
+ * Queries whether any threads are waiting on this condition.
+ * Implements {@link AbstractQueuedLongSynchronizer#hasWaiters}.
+ *
+ * @return {@code true} if there are any waiting threads
+ * @throws IllegalMonitorStateException if {@link #isHeldExclusively}
+ * returns {@code false}
+ */
+ protected final boolean hasWaiters() {
+ if (!isHeldExclusively())
+ throw new IllegalMonitorStateException();
+ for (Node w = firstWaiter; w != null; w = w.nextWaiter) {
+ if (w.waitStatus == Node.CONDITION)
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Returns an estimate of the number of threads waiting on
+ * this condition.
+ * Implements {@link AbstractQueuedLongSynchronizer#getWaitQueueLength}.
+ *
+ * @return the estimated number of waiting threads
+ * @throws IllegalMonitorStateException if {@link #isHeldExclusively}
+ * returns {@code false}
+ */
+ protected final int getWaitQueueLength() {
+ if (!isHeldExclusively())
+ throw new IllegalMonitorStateException();
+ int n = 0;
+ for (Node w = firstWaiter; w != null; w = w.nextWaiter) {
+ if (w.waitStatus == Node.CONDITION)
+ ++n;
+ }
+ return n;
+ }
+
+ /**
+ * Returns a collection containing those threads that may be
+ * waiting on this Condition.
+ * Implements {@link AbstractQueuedLongSynchronizer#getWaitingThreads}.
+ *
+ * @return the collection of threads
+ * @throws IllegalMonitorStateException if {@link #isHeldExclusively}
+ * returns {@code false}
+ */
+ protected final Collection<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 AtomicLong, which would be
+ * efficient and useful otherwise. So, as the lesser of evils, we
+ * natively implement using hotspot intrinsics API. And while we
+ * are at it, we do the same for other CASable fields (which could
+ * otherwise be done with atomic field updaters).
+ */
+ private static final Unsafe unsafe = Unsafe.getUnsafe();
+ private static final long stateOffset;
+ private static final long headOffset;
+ private static final long tailOffset;
+ private static final long waitStatusOffset;
+ private static final long nextOffset;
+
+ static {
+ try {
+ stateOffset = unsafe.objectFieldOffset
+ (AbstractQueuedLongSynchronizer.class.getDeclaredField("state"));
+ headOffset = unsafe.objectFieldOffset
+ (AbstractQueuedLongSynchronizer.class.getDeclaredField("head"));
+ tailOffset = unsafe.objectFieldOffset
+ (AbstractQueuedLongSynchronizer.class.getDeclaredField("tail"));
+ waitStatusOffset = unsafe.objectFieldOffset
+ (Node.class.getDeclaredField("waitStatus"));
+ nextOffset = unsafe.objectFieldOffset
+ (Node.class.getDeclaredField("next"));
+
+ } catch (Exception ex) { throw new Error(ex); }
+ }
+
+ /**
+ * CAS head field. Used only by enq.
+ */
+ private final boolean compareAndSetHead(Node update) {
+ return unsafe.compareAndSwapObject(this, headOffset, null, update);
+ }
+
+ /**
+ * CAS tail field. Used only by enq.
+ */
+ private final boolean compareAndSetTail(Node expect, Node update) {
+ return unsafe.compareAndSwapObject(this, tailOffset, expect, update);
+ }
+
+ /**
+ * CAS waitStatus field of a node.
+ */
+ private final static boolean compareAndSetWaitStatus(Node node,
+ int expect,
+ int update) {
+ return unsafe.compareAndSwapInt(node, waitStatusOffset,
+ expect, update);
+ }
+
+ /**
+ * CAS next field of a node.
+ */
+ private final static boolean compareAndSetNext(Node node,
+ Node expect,
+ Node update) {
+ return unsafe.compareAndSwapObject(node, nextOffset, expect, update);
+ }
+}
diff --git a/concurrent/src/main/java/java/util/concurrent/locks/AbstractQueuedSynchronizer.java b/concurrent/src/main/java/java/util/concurrent/locks/AbstractQueuedSynchronizer.java
index 8b9821e..66498e3 100644
--- a/concurrent/src/main/java/java/util/concurrent/locks/AbstractQueuedSynchronizer.java
+++ b/concurrent/src/main/java/java/util/concurrent/locks/AbstractQueuedSynchronizer.java
@@ -94,6 +94,12 @@ import sun.misc.Unsafe;
* means of using this class. All other methods are declared
* <tt>final</tt> because they cannot be independently varied.
*
+ * <p>You may also find the inherited methods from {@link
+ * AbstractOwnableSynchronizer} useful to keep track of the thread
+ * owning an exclusive synchronizer. You are encouraged to use them
+ * -- this enables monitoring and diagnostic tools to assist users in
+ * determining which threads hold locks.
+ *
* <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:
@@ -119,8 +125,9 @@ import sun.misc.Unsafe;
* disable barging by internally invoking one or more of the inspection
* methods, thereby providing a <em>fair</em> FIFO acquisition order.
* In particular, most fair synchronizers can define <tt>tryAcquire</tt>
- * to return <tt>false</tt> if predecessors are queued. Other variations
- * are possible.
+ * to return <tt>false</tt> if {@link #hasQueuedPredecessors} (a method
+ * specifically designed to be used by fair synchronizers) returns
+ * <tt>true</tt>. Other variations are possible.
*
* <p>Throughput and scalability are generally highest for the
* default barging (also known as <em>greedy</em>,
@@ -152,7 +159,10 @@ import sun.misc.Unsafe;
*
* <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
+ * represent the locked state. While a non-reentrant lock
+ * does not strictly require recording of the current owner
+ * thread, this class does so anyway to make usage easier to monitor.
+ * It also supports conditions and exposes
* one of the instrumentation methods:
*
* <pre>
@@ -168,13 +178,18 @@ import sun.misc.Unsafe;
* // Acquire the lock if state is zero
* public boolean tryAcquire(int acquires) {
* assert acquires == 1; // Otherwise unused
- * return compareAndSetState(0, 1);
+ * if (compareAndSetState(0, 1)) {
+ * setExclusiveOwnerThread(Thread.currentThread());
+ * return true;
+ * }
+ * return false;
* }
*
* // Release the lock by setting state to zero
* protected boolean tryRelease(int releases) {
* assert releases == 1; // Otherwise unused
* if (getState() == 0) throw new IllegalMonitorStateException();
+ * setExclusiveOwnerThread(null);
* setState(0);
* return true;
* }
@@ -787,7 +802,7 @@ public abstract class AbstractQueuedSynchronizer
* @return {@code true} if interrupted
*/
private final boolean parkAndCheckInterrupt() {
- LockSupport.park();
+ LockSupport.park(this);
return Thread.interrupted();
}
@@ -882,7 +897,7 @@ public abstract class AbstractQueuedSynchronizer
return false;
if (shouldParkAfterFailedAcquire(p, node) &&
nanosTimeout > spinForTimeoutThreshold)
- LockSupport.parkNanos(nanosTimeout);
+ LockSupport.parkNanos(this, nanosTimeout);
long now = System.nanoTime();
nanosTimeout -= now - lastTime;
lastTime = now;
@@ -986,7 +1001,7 @@ public abstract class AbstractQueuedSynchronizer
return false;
if (shouldParkAfterFailedAcquire(p, node) &&
nanosTimeout > spinForTimeoutThreshold)
- LockSupport.parkNanos(nanosTimeout);
+ LockSupport.parkNanos(this, nanosTimeout);
long now = System.nanoTime();
nanosTimeout -= now - lastTime;
lastTime = now;
@@ -1458,8 +1473,10 @@ public abstract class AbstractQueuedSynchronizer
* @return {@code true} if there is a queued thread preceding the
* current thread, and {@code false} if the current thread
* is at the head of the queue or the queue is empty
+ * @since 1.7
+ * @hide
*/
- final boolean hasQueuedPredecessors() {
+ public final boolean hasQueuedPredecessors() {
// The correctness of this depends on head being initialized
// before tail and on head.next being accurate if the current
// thread is first in queue.
@@ -1926,7 +1943,7 @@ public abstract class AbstractQueuedSynchronizer
int savedState = fullyRelease(node);
boolean interrupted = false;
while (!isOnSyncQueue(node)) {
- LockSupport.park();
+ LockSupport.park(this);
if (Thread.interrupted())
interrupted = true;
}
@@ -1993,7 +2010,7 @@ public abstract class AbstractQueuedSynchronizer
int savedState = fullyRelease(node);
int interruptMode = 0;
while (!isOnSyncQueue(node)) {
- LockSupport.park();
+ LockSupport.park(this);
if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
break;
}
@@ -2040,7 +2057,7 @@ public abstract class AbstractQueuedSynchronizer
transferAfterCancelledWait(node);
break;
}
- LockSupport.parkNanos(nanosTimeout);
+ LockSupport.parkNanos(this, nanosTimeout);
if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
break;
@@ -2094,7 +2111,7 @@ public abstract class AbstractQueuedSynchronizer
timedout = transferAfterCancelledWait(node);
break;
}
- LockSupport.parkUntil(abstime);
+ LockSupport.parkUntil(this, abstime);
if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
break;
}
@@ -2146,7 +2163,7 @@ public abstract class AbstractQueuedSynchronizer
break;
}
if (nanosTimeout >= spinForTimeoutThreshold)
- LockSupport.parkNanos(nanosTimeout);
+ LockSupport.parkNanos(this, nanosTimeout);
if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
break;
long now = System.nanoTime();
diff --git a/concurrent/src/main/java/java/util/concurrent/locks/Condition.java b/concurrent/src/main/java/java/util/concurrent/locks/Condition.java
index 03be58f..d75de51 100644
--- a/concurrent/src/main/java/java/util/concurrent/locks/Condition.java
+++ b/concurrent/src/main/java/java/util/concurrent/locks/Condition.java
@@ -421,6 +421,15 @@ public interface Condition {
* <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 {@code await}.
+ *
+ * <p><b>Implementation Considerations</b>
+ *
+ * <p>The current thread is assumed to hold the lock associated
+ * with this {@code Condition} when this method is called. It is
+ * up to the implementation to determine if this is the case and
+ * if not, how to respond. Typically, an exception will be thrown
+ * (such as {@link IllegalMonitorStateException}) and the
+ * implementation must document that fact.
*/
void signal();
@@ -430,6 +439,15 @@ public interface Condition {
* <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 {@code await}.
+ *
+ * <p><b>Implementation Considerations</b>
+ *
+ * <p>The current thread is assumed to hold the lock associated
+ * with this {@code Condition} when this method is called. It is
+ * up to the implementation to determine if this is the case and
+ * if not, how to respond. Typically, an exception will be thrown
+ * (such as {@link IllegalMonitorStateException}) and the
+ * implementation must document that fact.
*/
void signalAll();
}
diff --git a/concurrent/src/main/java/java/util/concurrent/locks/LockSupport.java b/concurrent/src/main/java/java/util/concurrent/locks/LockSupport.java
index b55b874..ac9a94f 100644
--- a/concurrent/src/main/java/java/util/concurrent/locks/LockSupport.java
+++ b/concurrent/src/main/java/java/util/concurrent/locks/LockSupport.java
@@ -36,6 +36,15 @@ import sun.misc.Unsafe;
* spinning, but must be paired with an {@code unpark} to be
* effective.
*
+ * <p>The three forms of {@code park} each also support a
+ * {@code blocker} object parameter. This object is recorded while
+ * the thread is blocked to permit monitoring and diagnostic tools to
+ * identify the reasons that threads are blocked. (Such tools may
+ * access blockers using method {@link #getBlocker}.) The use of these
+ * forms rather than the original forms without this parameter is
+ * strongly encouraged. The normal argument to supply as a
+ * {@code blocker} within a lock implementation is {@code this}.
+ *
* <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. The {@code park}
@@ -78,13 +87,25 @@ import sun.misc.Unsafe;
* }
* }}</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
+ // Hotspot implementation via intrinsics API
+ private static final Unsafe unsafe = UnsafeAccess.THE_ONE; // android-changed
+ private static final long parkBlockerOffset;
+
+ static {
+ try {
+ parkBlockerOffset = unsafe.objectFieldOffset
+ (java.lang.Thread.class.getDeclaredField("parkBlocker"));
+ } catch (Exception ex) { throw new Error(ex); }
+ }
+
+ private static void setBlocker(Thread t, Object arg) {
+ // Even though volatile, hotspot doesn't need a write barrier here.
+ unsafe.putObject(t, parkBlockerOffset, arg);
+ }
/**
* Makes available the permit for the given thread, if it
@@ -106,6 +127,136 @@ public class LockSupport {
* 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 {@link #unpark unpark} with the
+ * current thread as the target; or
+ *
+ * <li>Some other thread {@linkplain 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.
+ *
+ * @param blocker the synchronization object responsible for this
+ * thread parking
+ * @since 1.6
+ */
+ public static void park(Object blocker) {
+ Thread t = Thread.currentThread();
+ setBlocker(t, blocker);
+ unsafe.park(false, 0L);
+ setBlocker(t, null);
+ }
+
+ /**
+ * Disables the current thread for thread scheduling purposes, for up to
+ * the specified waiting time, unless the permit is available.
+ *
+ * <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 {@link #unpark unpark} with the
+ * current thread as the target; or
+ *
+ * <li>Some other thread {@linkplain 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 blocker the synchronization object responsible for this
+ * thread parking
+ * @param nanos the maximum number of nanoseconds to wait
+ * @since 1.6
+ */
+ public static void parkNanos(Object blocker, long nanos) {
+ if (nanos > 0) {
+ Thread t = Thread.currentThread();
+ setBlocker(t, blocker);
+ unsafe.park(false, nanos);
+ setBlocker(t, null);
+ }
+ }
+
+ /**
+ * Disables the current thread for thread scheduling purposes, until
+ * the specified deadline, unless the permit is available.
+ *
+ * <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 {@link #unpark unpark} with the
+ * current thread as the target; or
+ *
+ * <li>Some other thread {@linkplain 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 blocker the synchronization object responsible for this
+ * thread parking
+ * @param deadline the absolute time, in milliseconds from the Epoch,
+ * to wait until
+ * @since 1.6
+ */
+ public static void parkUntil(Object blocker, long deadline) {
+ Thread t = Thread.currentThread();
+ setBlocker(t, blocker);
+ unsafe.park(true, deadline);
+ setBlocker(t, null);
+ }
+
+ /**
+ * Returns the blocker object supplied to the most recent
+ * invocation of a park method that has not yet unblocked, or null
+ * if not blocked. The value returned is just a momentary
+ * snapshot -- the thread may have since unblocked or blocked on a
+ * different blocker object.
+ *
+ * @return the blocker
+ * @since 1.6
+ */
+ public static Object getBlocker(Thread t) {
+ return unsafe.getObjectVolatile(t, parkBlockerOffset);
+ }
+
+ /**
+ * 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
diff --git a/concurrent/src/main/java/java/util/concurrent/locks/ReentrantReadWriteLock.java b/concurrent/src/main/java/java/util/concurrent/locks/ReentrantReadWriteLock.java
index c923944..bfaff06 100644
--- a/concurrent/src/main/java/java/util/concurrent/locks/ReentrantReadWriteLock.java
+++ b/concurrent/src/main/java/java/util/concurrent/locks/ReentrantReadWriteLock.java
@@ -1161,6 +1161,32 @@ public class ReentrantReadWriteLock implements ReadWriteLock, java.io.Serializab
"[Locked by thread " + o.getName() + "]");
}
+ /**
+ * Queries if this write lock is held by the current thread.
+ * Identical in effect to {@link
+ * ReentrantReadWriteLock#isWriteLockedByCurrentThread}.
+ *
+ * @return {@code true} if the current thread holds this lock and
+ * {@code false} otherwise
+ * @since 1.6
+ */
+ public boolean isHeldByCurrentThread() {
+ return sync.isHeldExclusively();
+ }
+
+ /**
+ * Queries the number of holds on this write lock by the current
+ * thread. A thread has a hold on a lock for each lock action
+ * that is not matched by an unlock action. Identical in effect
+ * to {@link ReentrantReadWriteLock#getWriteHoldCount}.
+ *
+ * @return the number of holds on this lock by the current thread,
+ * or zero if this lock is not held by the current thread
+ * @since 1.6
+ */
+ public int getHoldCount() {
+ return sync.getWriteHoldCount();
+ }
}
// Instrumentation and status
@@ -1236,6 +1262,19 @@ public class ReentrantReadWriteLock implements ReadWriteLock, java.io.Serializab
}
/**
+ * Queries the number of reentrant read holds on this lock by the
+ * current thread. A reader thread has a hold on a lock for
+ * each lock action that is not matched by an unlock action.
+ *
+ * @return the number of holds on the read lock by the current thread,
+ * or zero if the read lock is not held by the current thread
+ * @since 1.6
+ */
+ public int getReadHoldCount() {
+ return sync.getReadHoldCount();
+ }
+
+ /**
* Returns a collection containing threads that may be waiting to
* acquire the write lock. Because the actual set of threads may
* change dynamically while constructing this result, the returned
diff --git a/concurrent/src/main/java/java/util/concurrent/locks/package-info.java b/concurrent/src/main/java/java/util/concurrent/locks/package-info.java
index 801ee9b..860acdd 100644
--- a/concurrent/src/main/java/java/util/concurrent/locks/package-info.java
+++ b/concurrent/src/main/java/java/util/concurrent/locks/package-info.java
@@ -34,10 +34,16 @@
*
* <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.
+ * synchronizers that rely on queuing blocked threads. The {@link
+ * java.util.concurrent.locks.AbstractQueuedLongSynchronizer} class
+ * provides the same functionality but extends support to 64 bits of
+ * synchronization state. Both extend class {@link
+ * java.util.concurrent.locks.AbstractOwnableSynchronizer}, a simple
+ * class that helps record the thread currently holding exclusive
+ * synchronization. The {@link java.util.concurrent.locks.LockSupport}
+ * class provides lower-level blocking and unblocking support that is
+ * useful for those developers implementing their own customized lock
+ * classes.
*
* @since 1.5
*/
diff --git a/concurrent/src/main/java/java/util/concurrent/package-info.java b/concurrent/src/main/java/java/util/concurrent/package-info.java
index d49ef25..dd3a22d 100644
--- a/concurrent/src/main/java/java/util/concurrent/package-info.java
+++ b/concurrent/src/main/java/java/util/concurrent/package-info.java
@@ -41,6 +41,10 @@
* a function, allows determination of whether execution has
* completed, and provides a means to cancel execution.
*
+ * A {@link java.util.concurrent.RunnableFuture} is a {@code Future}
+ * that possesses a {@code run} method that upon execution,
+ * sets its results.
+ *
* <p>
*
* <b>Implementations.</b>
@@ -59,6 +63,13 @@
* assists in coordinating the processing of groups of
* asynchronous tasks.
*
+ * <p>Class {@link java.util.concurrent.ForkJoinPool} provides an
+ * Executor primarily designed for processing instances of {@link
+ * java.util.concurrent.ForkJoinTask} and its subclasses. These
+ * classes employ a work-stealing scheduler that attains high
+ * throughput for tasks conforming to restrictions that often hold in
+ * computation-intensive parallel processing.
+ *
* <h2>Queues</h2>
*
* The {@link java.util.concurrent.ConcurrentLinkedQueue} class
@@ -77,6 +88,18 @@
* for producer-consumer, messaging, parallel tasking, and
* related concurrent designs.
*
+ * <p> Extended interface {@link java.util.concurrent.TransferQueue},
+ * and implementation {@link java.util.concurrent.LinkedTransferQueue}
+ * introduce a synchronous {@code transfer} method (along with related
+ * features) in which a producer may optionally block awaiting its
+ * consumer.
+ *
+ * <p>The {@link java.util.concurrent.BlockingDeque} interface
+ * extends {@code BlockingQueue} to support both FIFO and LIFO
+ * (stack-based) operations.
+ * Class {@link java.util.concurrent.LinkedBlockingDeque}
+ * provides an implementation.
+ *
* <h2>Timing</h2>
*
* The {@link java.util.concurrent.TimeUnit} class provides
@@ -97,28 +120,45 @@
*
* <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.
+ * Five classes aid common special-purpose synchronization idioms.
+ * <ul>
+ *
+ * <li>{@link java.util.concurrent.Semaphore} is a classic concurrency tool.
+ *
+ * <li>{@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.
+ *
+ * <li>A {@link java.util.concurrent.CyclicBarrier} is a resettable
+ * multiway synchronization point useful in some styles of parallel
+ * programming.
+ *
+ * <li>A {@link java.util.concurrent.Phaser} provides
+ * a more flexible form of barrier that may be used to control phased
+ * computation among multiple threads.
+ *
+ * <li>An {@link java.util.concurrent.Exchanger} allows two threads to
+ * exchange objects at a rendezvous point, and is useful in several
+ * pipeline designs.
+ *
+ * </ul>
*
* <h2>Concurrent Collections</h2>
*
* Besides Queues, this package supplies Collection implementations
* designed for use in multithreaded contexts:
* {@link java.util.concurrent.ConcurrentHashMap},
+ * {@link java.util.concurrent.ConcurrentSkipListMap},
+ * {@link java.util.concurrent.ConcurrentSkipListSet},
* {@link java.util.concurrent.CopyOnWriteArrayList}, and
* {@link java.util.concurrent.CopyOnWriteArraySet}.
* When many threads are expected to access a given collection, a
* {@code ConcurrentHashMap} is normally preferable to a synchronized
- * {@code HashMap}. A {@code CopyOnWriteArrayList} is preferable to a
- * synchronized {@code ArrayList} when the expected number of reads and
- * traversals greatly outnumber the number of updates to a list.
+ * {@code HashMap}, and a {@code ConcurrentSkipListMap} is normally
+ * preferable to a synchronized {@code TreeMap}.
+ * A {@code CopyOnWriteArrayList} is preferable to a synchronized
+ * {@code ArrayList} when the expected number of reads and traversals
+ * greatly outnumber the number of updates to a list.
* <p>The "Concurrent" prefix used with some classes in this package
* is a shorthand indicating several differences from similar
@@ -216,7 +256,8 @@
* in each thread <i>happen-before</i> those subsequent to the
* corresponding {@code exchange()} in another thread.
*
- * <li>Actions prior to calling {@code CyclicBarrier.await}
+ * <li>Actions prior to calling {@code CyclicBarrier.await} and
+ * {@code Phaser.awaitAdvance} (as well as its variants)
* <i>happen-before</i> actions performed by the barrier action, and
* actions performed by the barrier action <i>happen-before</i> actions
* subsequent to a successful return from the corresponding {@code await}