From 91770798d8b9280d48d30df2ed7f63b3ed9b036f Mon Sep 17 00:00:00 2001 From: Calin Juravle Date: Fri, 14 Jun 2013 16:48:53 +0100 Subject: Sync java.util.concurrent library up to 12.06.2013. CouncurrentHashMap was skipped from this sync. Change-Id: I29c67698a2e706b22e3cb5920c5fe91f1f15461c --- .../util/concurrent/AbstractExecutorService.java | 90 +- .../java/util/concurrent/ArrayBlockingQueue.java | 30 +- .../java/java/util/concurrent/BlockingDeque.java | 110 +- .../java/java/util/concurrent/BlockingQueue.java | 98 +- .../util/concurrent/BrokenBarrierException.java | 5 +- .../main/java/java/util/concurrent/Callable.java | 12 +- .../util/concurrent/CancellationException.java | 4 +- .../java/util/concurrent/CompletionService.java | 26 +- .../util/concurrent/ConcurrentLinkedDeque.java | 10 +- .../util/concurrent/ConcurrentLinkedQueue.java | 10 +- .../java/java/util/concurrent/ConcurrentMap.java | 29 +- .../util/concurrent/ConcurrentNavigableMap.java | 3 +- .../util/concurrent/ConcurrentSkipListMap.java | 159 +- .../util/concurrent/ConcurrentSkipListSet.java | 70 +- .../java/util/concurrent/CopyOnWriteArraySet.java | 62 +- .../java/java/util/concurrent/CountDownLatch.java | 28 +- .../java/util/concurrent/CountedCompleter.java | 715 ++++ .../java/java/util/concurrent/CyclicBarrier.java | 33 +- .../main/java/java/util/concurrent/DelayQueue.java | 62 +- .../main/java/java/util/concurrent/Delayed.java | 4 +- .../main/java/java/util/concurrent/Exchanger.java | 832 +++-- .../java/util/concurrent/ExecutionException.java | 10 +- .../main/java/java/util/concurrent/Executor.java | 14 +- .../java/java/util/concurrent/ExecutorService.java | 66 +- .../main/java/java/util/concurrent/Executors.java | 104 +- .../java/java/util/concurrent/ForkJoinPool.java | 3579 +++++++++++++------- .../java/java/util/concurrent/ForkJoinTask.java | 871 +++-- .../java/util/concurrent/ForkJoinWorkerThread.java | 892 +---- .../src/main/java/java/util/concurrent/Future.java | 54 +- .../main/java/java/util/concurrent/FutureTask.java | 42 +- .../java/util/concurrent/LinkedBlockingDeque.java | 9 +- .../java/util/concurrent/LinkedBlockingQueue.java | 17 +- .../java/util/concurrent/LinkedTransferQueue.java | 19 +- .../src/main/java/java/util/concurrent/Phaser.java | 18 +- .../util/concurrent/PriorityBlockingQueue.java | 75 +- .../java/java/util/concurrent/RecursiveAction.java | 24 +- .../java/java/util/concurrent/RecursiveTask.java | 2 +- .../concurrent/RejectedExecutionException.java | 10 +- .../java/java/util/concurrent/RunnableFuture.java | 4 +- .../util/concurrent/RunnableScheduledFuture.java | 6 +- .../util/concurrent/ScheduledExecutorService.java | 32 +- .../concurrent/ScheduledThreadPoolExecutor.java | 36 +- .../main/java/java/util/concurrent/Semaphore.java | 11 +- .../java/util/concurrent/SynchronousQueue.java | 177 +- .../java/util/concurrent/ThreadPoolExecutor.java | 326 +- .../main/java/java/util/concurrent/TimeUnit.java | 70 +- .../java/util/concurrent/TimeoutException.java | 6 +- .../java/util/concurrent/atomic/AtomicBoolean.java | 10 +- .../java/util/concurrent/atomic/AtomicInteger.java | 11 +- .../util/concurrent/atomic/AtomicIntegerArray.java | 8 +- .../atomic/AtomicIntegerFieldUpdater.java | 54 +- .../java/util/concurrent/atomic/AtomicLong.java | 11 +- .../util/concurrent/atomic/AtomicLongArray.java | 9 +- .../concurrent/atomic/AtomicLongFieldUpdater.java | 77 +- .../concurrent/atomic/AtomicMarkableReference.java | 6 +- .../util/concurrent/atomic/AtomicReference.java | 12 +- .../concurrent/atomic/AtomicReferenceArray.java | 20 +- .../atomic/AtomicReferenceFieldUpdater.java | 78 +- .../concurrent/atomic/AtomicStampedReference.java | 7 +- .../java/util/concurrent/atomic/package-info.java | 22 +- .../locks/AbstractOwnableSynchronizer.java | 10 +- .../locks/AbstractQueuedLongSynchronizer.java | 131 +- .../locks/AbstractQueuedSynchronizer.java | 175 +- .../java/java/util/concurrent/locks/Condition.java | 4 +- .../main/java/java/util/concurrent/locks/Lock.java | 9 +- .../java/util/concurrent/locks/LockSupport.java | 10 +- .../java/util/concurrent/locks/ReadWriteLock.java | 12 +- .../java/util/concurrent/locks/ReentrantLock.java | 26 +- .../concurrent/locks/ReentrantReadWriteLock.java | 28 +- .../java/java/util/concurrent/package-info.java | 9 +- 70 files changed, 5445 insertions(+), 4160 deletions(-) create mode 100644 luni/src/main/java/java/util/concurrent/CountedCompleter.java (limited to 'luni') diff --git a/luni/src/main/java/java/util/concurrent/AbstractExecutorService.java b/luni/src/main/java/java/util/concurrent/AbstractExecutorService.java index a7f7745..23e68bb 100644 --- a/luni/src/main/java/java/util/concurrent/AbstractExecutorService.java +++ b/luni/src/main/java/java/util/concurrent/AbstractExecutorService.java @@ -9,19 +9,19 @@ import java.util.*; /** * Provides default implementations of {@link ExecutorService} - * execution methods. This class implements the submit, - * invokeAny and invokeAll methods using a - * {@link RunnableFuture} returned by newTaskFor, which defaults + * execution methods. This class implements the {@code submit}, + * {@code invokeAny} and {@code invokeAll} methods using a + * {@link RunnableFuture} returned by {@code newTaskFor}, which defaults * to the {@link FutureTask} class provided in this package. For example, - * the implementation of submit(Runnable) creates an - * associated RunnableFuture that is executed and - * returned. Subclasses may override the newTaskFor methods - * to return RunnableFuture implementations other than - * FutureTask. + * the implementation of {@code submit(Runnable)} creates an + * associated {@code RunnableFuture} that is executed and + * returned. Subclasses may override the {@code newTaskFor} methods + * to return {@code RunnableFuture} implementations other than + * {@code FutureTask}. * - *

Extension example. Here is a sketch of a class + *

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

 {@code
  * public class CustomThreadPoolExecutor extends ThreadPoolExecutor {
  *
@@ -42,15 +42,15 @@ import java.util.*;
 public abstract class AbstractExecutorService implements ExecutorService {
 
     /**
-     * Returns a RunnableFuture for the given runnable and default
+     * Returns a {@code RunnableFuture} for the given runnable and default
      * value.
      *
      * @param runnable the runnable task being wrapped
      * @param value the default value for the returned future
-     * @return a RunnableFuture which when run will run the
-     * underlying runnable and which, as a Future, will yield
+     * @return a {@code RunnableFuture} which, when run, will run the
+     * underlying runnable and which, as a {@code Future}, will yield
      * the given value as its result and provide for cancellation of
-     * the underlying task.
+     * the underlying task
      * @since 1.6
      */
     protected  RunnableFuture newTaskFor(Runnable runnable, T value) {
@@ -58,13 +58,13 @@ public abstract class AbstractExecutorService implements ExecutorService {
     }
 
     /**
-     * Returns a RunnableFuture for the given callable task.
+     * Returns a {@code RunnableFuture} for the given callable task.
      *
      * @param callable the callable task being wrapped
-     * @return a RunnableFuture which when run will call the
-     * underlying callable and which, as a Future, will yield
+     * @return a {@code RunnableFuture} which, when run, will call the
+     * underlying callable and which, as a {@code Future}, will yield
      * the callable's result as its result and provide for
-     * cancellation of the underlying task.
+     * cancellation of the underlying task
      * @since 1.6
      */
     protected  RunnableFuture newTaskFor(Callable callable) {
@@ -108,14 +108,14 @@ public abstract class AbstractExecutorService implements ExecutorService {
      * the main mechanics of invokeAny.
      */
     private  T doInvokeAny(Collection> tasks,
-                            boolean timed, long nanos)
+                              boolean timed, long nanos)
         throws InterruptedException, ExecutionException, TimeoutException {
         if (tasks == null)
             throw new NullPointerException();
         int ntasks = tasks.size();
         if (ntasks == 0)
             throw new IllegalArgumentException();
-        List> futures= new ArrayList>(ntasks);
+        ArrayList> futures = new ArrayList>(ntasks);
         ExecutorCompletionService ecs =
             new ExecutorCompletionService(this);
 
@@ -129,7 +129,7 @@ public abstract class AbstractExecutorService implements ExecutorService {
             // Record exceptions so that if we fail to obtain any
             // result, we can throw the last exception we got.
             ExecutionException ee = null;
-            long lastTime = timed ? System.nanoTime() : 0;
+            final long deadline = timed ? System.nanoTime() + nanos : 0L;
             Iterator> it = tasks.iterator();
 
             // Start one task for sure; the rest incrementally
@@ -151,9 +151,7 @@ public abstract class AbstractExecutorService implements ExecutorService {
                         f = ecs.poll(nanos, TimeUnit.NANOSECONDS);
                         if (f == null)
                             throw new TimeoutException();
-                        long now = System.nanoTime();
-                        nanos -= now - lastTime;
-                        lastTime = now;
+                        nanos = deadline - System.nanoTime();
                     }
                     else
                         f = ecs.take();
@@ -175,8 +173,8 @@ public abstract class AbstractExecutorService implements ExecutorService {
             throw ee;
 
         } finally {
-            for (Future f : futures)
-                f.cancel(true);
+            for (int i = 0, size = futures.size(); i < size; i++)
+                futures.get(i).cancel(true);
         }
     }
 
@@ -200,7 +198,7 @@ public abstract class AbstractExecutorService implements ExecutorService {
         throws InterruptedException {
         if (tasks == null)
             throw new NullPointerException();
-        List> futures = new ArrayList>(tasks.size());
+        ArrayList> futures = new ArrayList>(tasks.size());
         boolean done = false;
         try {
             for (Callable t : tasks) {
@@ -208,7 +206,8 @@ public abstract class AbstractExecutorService implements ExecutorService {
                 futures.add(f);
                 execute(f);
             }
-            for (Future f : futures) {
+            for (int i = 0, size = futures.size(); i < size; i++) {
+                Future f = futures.get(i);
                 if (!f.isDone()) {
                     try {
                         f.get();
@@ -221,40 +220,39 @@ public abstract class AbstractExecutorService implements ExecutorService {
             return futures;
         } finally {
             if (!done)
-                for (Future f : futures)
-                    f.cancel(true);
+                for (int i = 0, size = futures.size(); i < size; i++)
+                    futures.get(i).cancel(true);
         }
     }
 
     public  List> invokeAll(Collection> tasks,
                                          long timeout, TimeUnit unit)
         throws InterruptedException {
-        if (tasks == null || unit == null)
+        if (tasks == null)
             throw new NullPointerException();
         long nanos = unit.toNanos(timeout);
-        List> futures = new ArrayList>(tasks.size());
+        ArrayList> futures = new ArrayList>(tasks.size());
         boolean done = false;
         try {
             for (Callable t : tasks)
                 futures.add(newTaskFor(t));
 
-            long lastTime = System.nanoTime();
+            final long deadline = System.nanoTime() + nanos;
+            final int size = futures.size();
 
             // Interleave time checks and calls to execute in case
             // executor doesn't have any/much parallelism.
-            Iterator> it = futures.iterator();
-            while (it.hasNext()) {
-                execute((Runnable)(it.next()));
-                long now = System.nanoTime();
-                nanos -= now - lastTime;
-                lastTime = now;
-                if (nanos <= 0)
+            for (int i = 0; i < size; i++) {
+                execute((Runnable)futures.get(i));
+                nanos = deadline - System.nanoTime();
+                if (nanos <= 0L)
                     return futures;
             }
 
-            for (Future f : futures) {
+            for (int i = 0; i < size; i++) {
+                Future f = futures.get(i);
                 if (!f.isDone()) {
-                    if (nanos <= 0)
+                    if (nanos <= 0L)
                         return futures;
                     try {
                         f.get(nanos, TimeUnit.NANOSECONDS);
@@ -263,17 +261,15 @@ public abstract class AbstractExecutorService implements ExecutorService {
                     } catch (TimeoutException toe) {
                         return futures;
                     }
-                    long now = System.nanoTime();
-                    nanos -= now - lastTime;
-                    lastTime = now;
+                    nanos = deadline - System.nanoTime();
                 }
             }
             done = true;
             return futures;
         } finally {
             if (!done)
-                for (Future f : futures)
-                    f.cancel(true);
+                for (int i = 0, size = futures.size(); i < size; i++)
+                    futures.get(i).cancel(true);
         }
     }
 
diff --git a/luni/src/main/java/java/util/concurrent/ArrayBlockingQueue.java b/luni/src/main/java/java/util/concurrent/ArrayBlockingQueue.java
index e30ab67..3cfe6d5 100644
--- a/luni/src/main/java/java/util/concurrent/ArrayBlockingQueue.java
+++ b/luni/src/main/java/java/util/concurrent/ArrayBlockingQueue.java
@@ -111,9 +111,9 @@ public class ArrayBlockingQueue extends AbstractQueue
     /**
      * Returns item at index i.
      */
+    @SuppressWarnings("unchecked")
     final E itemAt(int i) {
-        @SuppressWarnings("unchecked") E x = (E) items[i];
-        return x;
+        return (E) items[i];
     }
 
     /**
@@ -147,7 +147,8 @@ public class ArrayBlockingQueue extends AbstractQueue
         // assert lock.getHoldCount() == 1;
         // assert items[takeIndex] != null;
         final Object[] items = this.items;
-        @SuppressWarnings("unchecked") E x = (E) items[takeIndex];
+        @SuppressWarnings("unchecked")
+        E x = (E) items[takeIndex];
         items[takeIndex] = null;
         takeIndex = inc(takeIndex);
         count--;
@@ -396,7 +397,7 @@ public class ArrayBlockingQueue extends AbstractQueue
         final ReentrantLock lock = this.lock;
         lock.lock();
         try {
-            return (count == 0) ? null : itemAt(takeIndex);
+            return itemAt(takeIndex); // null when queue is empty
         } finally {
             lock.unlock();
         }
@@ -529,8 +530,13 @@ public class ArrayBlockingQueue extends AbstractQueue
         try {
             final int count = this.count;
             Object[] a = new Object[count];
-            for (int i = takeIndex, k = 0; k < count; i = inc(i), k++)
-                a[k] = items[i];
+            int n = items.length - takeIndex;
+            if (count <= n) {
+                System.arraycopy(items, takeIndex, a, 0, count);
+            } else {
+                System.arraycopy(items, takeIndex, a, 0, n);
+                System.arraycopy(items, 0, a, n, count - n);
+            }
             return a;
         } finally {
             lock.unlock();
@@ -583,8 +589,13 @@ public class ArrayBlockingQueue extends AbstractQueue
             if (len < count)
                 a = (T[])java.lang.reflect.Array.newInstance(
                     a.getClass().getComponentType(), count);
-            for (int i = takeIndex, k = 0; k < count; i = inc(i), k++)
-                a[k] = (T) items[i];
+            int n = items.length - takeIndex;
+            if (count <= n)
+                System.arraycopy(items, takeIndex, a, 0, count);
+            else {
+                System.arraycopy(items, takeIndex, a, 0, n);
+                System.arraycopy(items, 0, a, n, count - n);
+            }
             if (len > count)
                 a[count] = null;
             return a;
@@ -674,7 +685,8 @@ public class ArrayBlockingQueue extends AbstractQueue
             int i = 0;
             try {
                 while (i < n) {
-                    @SuppressWarnings("unchecked") E x = (E) items[take];
+                    @SuppressWarnings("unchecked")
+                    E x = (E) items[take];
                     c.add(x);
                     items[take] = null;
                     take = inc(take);
diff --git a/luni/src/main/java/java/util/concurrent/BlockingDeque.java b/luni/src/main/java/java/util/concurrent/BlockingDeque.java
index 34f103d..8a393ba 100644
--- a/luni/src/main/java/java/util/concurrent/BlockingDeque.java
+++ b/luni/src/main/java/java/util/concurrent/BlockingDeque.java
@@ -12,11 +12,11 @@ import java.util.*;
  * for the deque to become non-empty when retrieving an element, and wait for
  * space to become available in the deque when storing an element.
  *
- * 

BlockingDeque methods come in four forms, with different ways + *

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

Like any {@link BlockingQueue}, a BlockingDeque is thread safe, + *

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

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

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

* * - * - * + * + * * * * @@ -179,7 +179,7 @@ public interface BlockingDeque extends BlockingQueue, Deque { /** * Inserts the specified element at the front of this deque if it is * possible to do so immediately without violating capacity restrictions, - * throwing an IllegalStateException if no space is currently + * throwing an {@code IllegalStateException} if no space is currently * available. When using a capacity-restricted deque, it is generally * preferable to use {@link #offerFirst(Object) offerFirst}. * @@ -194,7 +194,7 @@ public interface BlockingDeque extends BlockingQueue, Deque { /** * Inserts the specified element at the end of this deque if it is * possible to do so immediately without violating capacity restrictions, - * throwing an IllegalStateException if no space is currently + * throwing an {@code IllegalStateException} if no space is currently * available. When using a capacity-restricted deque, it is generally * preferable to use {@link #offerLast(Object) offerLast}. * @@ -209,7 +209,7 @@ public interface BlockingDeque extends BlockingQueue, Deque { /** * Inserts the specified element at the front of this deque if it is * possible to do so immediately without violating capacity restrictions, - * returning true upon success and false if no space is + * returning {@code true} upon success and {@code false} if no space is * currently available. * When using a capacity-restricted deque, this method is generally * preferable to the {@link #addFirst(Object) addFirst} method, which can @@ -225,7 +225,7 @@ public interface BlockingDeque extends BlockingQueue, Deque { /** * Inserts the specified element at the end of this deque if it is * possible to do so immediately without violating capacity restrictions, - * returning true upon success and false if no space is + * returning {@code true} upon success and {@code false} if no space is * currently available. * When using a capacity-restricted deque, this method is generally * preferable to the {@link #addLast(Object) addLast} method, which can @@ -273,10 +273,10 @@ public interface BlockingDeque extends BlockingQueue, Deque { * * @param e the element to add * @param timeout how long to wait before giving up, in units of - * unit - * @param unit a TimeUnit determining how to interpret the - * timeout parameter - * @return true if successful, or false if + * {@code unit} + * @param unit a {@code TimeUnit} determining how to interpret the + * {@code timeout} parameter + * @return {@code true} if successful, or {@code false} if * the specified waiting time elapses before space is available * @throws InterruptedException if interrupted while waiting * @throws ClassCastException if the class of the specified element @@ -295,10 +295,10 @@ public interface BlockingDeque extends BlockingQueue, Deque { * * @param e the element to add * @param timeout how long to wait before giving up, in units of - * unit - * @param unit a TimeUnit determining how to interpret the - * timeout parameter - * @return true if successful, or false if + * {@code unit} + * @param unit a {@code TimeUnit} determining how to interpret the + * {@code timeout} parameter + * @return {@code true} if successful, or {@code false} if * the specified waiting time elapses before space is available * @throws InterruptedException if interrupted while waiting * @throws ClassCastException if the class of the specified element @@ -334,10 +334,10 @@ public interface BlockingDeque extends BlockingQueue, Deque { * become available. * * @param timeout how long to wait before giving up, in units of - * unit - * @param unit a TimeUnit determining how to interpret the - * timeout parameter - * @return the head of this deque, or null if the specified + * {@code unit} + * @param unit a {@code TimeUnit} determining how to interpret the + * {@code timeout} parameter + * @return the head of this deque, or {@code null} if the specified * waiting time elapses before an element is available * @throws InterruptedException if interrupted while waiting */ @@ -350,10 +350,10 @@ public interface BlockingDeque extends BlockingQueue, Deque { * become available. * * @param timeout how long to wait before giving up, in units of - * unit - * @param unit a TimeUnit determining how to interpret the - * timeout parameter - * @return the tail of this deque, or null if the specified + * {@code unit} + * @param unit a {@code TimeUnit} determining how to interpret the + * {@code timeout} parameter + * @return the tail of this deque, or {@code null} if the specified * waiting time elapses before an element is available * @throws InterruptedException if interrupted while waiting */ @@ -363,13 +363,13 @@ public interface BlockingDeque extends BlockingQueue, Deque { /** * Removes the first occurrence of the specified element from this deque. * If the deque does not contain the element, it is unchanged. - * More formally, removes the first element e such that - * o.equals(e) (if such an element exists). - * Returns true if this deque contained the specified element + * 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). * * @param o element to be removed from this deque, if present - * @return true if an element was removed as a result of this call + * @return {@code true} if an element was removed as a result of this call * @throws ClassCastException if the class of the specified element * is incompatible with this deque * (optional) @@ -381,13 +381,13 @@ public interface BlockingDeque extends BlockingQueue, Deque { /** * Removes the last occurrence of the specified element from this deque. * If the deque does not contain the element, it is unchanged. - * More formally, removes the last element e such that - * o.equals(e) (if such an element exists). - * Returns true if this deque contained the specified element + * More formally, removes the last 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). * * @param o element to be removed from this deque, if present - * @return true if an element was removed as a result of this call + * @return {@code true} if an element was removed as a result of this call * @throws ClassCastException if the class of the specified element * is incompatible with this deque * (optional) @@ -402,8 +402,8 @@ public interface BlockingDeque extends BlockingQueue, Deque { * Inserts the specified element into the queue represented by this deque * (in other words, at the tail of this deque) if it is possible to do so * immediately without violating capacity restrictions, returning - * true upon success and throwing an - * IllegalStateException if no space is currently available. + * {@code true} upon success and throwing an + * {@code IllegalStateException} if no space is currently available. * When using a capacity-restricted deque, it is generally preferable to * use {@link #offer(Object) offer}. * @@ -423,7 +423,7 @@ public interface BlockingDeque extends BlockingQueue, Deque { * Inserts the specified element into the queue represented by this deque * (in other words, at the tail of this deque) if it is possible to do so * immediately without violating capacity restrictions, returning - * true upon success and false if no space is currently + * {@code true} upon success and {@code false} if no space is currently * available. When using a capacity-restricted deque, this method is * generally preferable to the {@link #add} method, which can fail to * insert an element only by throwing an exception. @@ -465,8 +465,8 @@ public interface BlockingDeque extends BlockingQueue, Deque { * {@link #offerLast(Object,long,TimeUnit) offerLast}. * * @param e the element to add - * @return true if the element was added to this deque, else - * false + * @return {@code true} if the element was added to this deque, else + * {@code false} * @throws InterruptedException {@inheritDoc} * @throws ClassCastException if the class of the specified element * prevents it from being added to this deque @@ -493,11 +493,11 @@ public interface BlockingDeque extends BlockingQueue, Deque { /** * Retrieves and removes the head of the queue represented by this deque * (in other words, the first element of this deque), or returns - * null if this deque is empty. + * {@code null} if this deque is empty. * *

This method is equivalent to {@link #pollFirst()}. * - * @return the head of this deque, or null if this deque is empty + * @return the head of this deque, or {@code null} if this deque is empty */ E poll(); @@ -521,7 +521,7 @@ public interface BlockingDeque extends BlockingQueue, Deque { *

This method is equivalent to * {@link #pollFirst(long,TimeUnit) pollFirst}. * - * @return the head of this deque, or null if the + * @return the head of this deque, or {@code null} if the * specified waiting time elapses before an element is available * @throws InterruptedException if interrupted while waiting */ @@ -544,27 +544,27 @@ public interface BlockingDeque extends BlockingQueue, Deque { /** * Retrieves, but does not remove, the head of the queue represented by * this deque (in other words, the first element of this deque), or - * returns null if this deque is empty. + * returns {@code null} if this deque is empty. * *

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

This method is equivalent to * {@link #removeFirstOccurrence(Object) removeFirstOccurrence}. * * @param o element to be removed from this deque, if present - * @return true if this deque changed as a result of the call + * @return {@code true} if this deque changed as a result of the call * @throws ClassCastException if the class of the specified element * is incompatible with this deque * (optional) @@ -574,12 +574,12 @@ public interface BlockingDeque extends BlockingQueue, Deque { boolean remove(Object o); /** - * Returns true if this deque contains the specified element. - * More formally, returns true if and only if this deque contains - * at least one element e such that o.equals(e). + * 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 true if this deque contains the specified element + * @return {@code true} if this deque contains the specified element * @throws ClassCastException if the class of the specified element * is incompatible with this deque * (optional) diff --git a/luni/src/main/java/java/util/concurrent/BlockingQueue.java b/luni/src/main/java/java/util/concurrent/BlockingQueue.java index 6cfe52b..cc6d541 100644 --- a/luni/src/main/java/java/util/concurrent/BlockingQueue.java +++ b/luni/src/main/java/java/util/concurrent/BlockingQueue.java @@ -19,11 +19,11 @@ import java.util.Queue; * element, and wait for space to become available in the queue when * storing an element. * - *

BlockingQueue methods come in four forms, with different ways + *

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

*
BlockingQueue Method Equivalent BlockingDeque Method {@code BlockingQueue} Method Equivalent {@code BlockingDeque} Method
Insert
* - *

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

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

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

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

BlockingQueue implementations are designed to be used + *

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

BlockingQueue implementations are thread-safe. All + *

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

A BlockingQueue does not intrinsically support + *

A {@code BlockingQueue} does not intrinsically support * any kind of "close" or "shutdown" operation to * indicate that no more items will be added. The needs and usage of * such features tend to be implementation-dependent. For example, a @@ -100,7 +100,7 @@ import java.util.Queue; * *

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

 {@code
  * class Producer implements Runnable {
@@ -152,13 +152,13 @@ public interface BlockingQueue extends Queue {
     /**
      * Inserts the specified element into this queue if it is possible to do
      * so immediately without violating capacity restrictions, returning
-     * true upon success and throwing an
-     * IllegalStateException if no space is currently available.
+     * {@code true} upon success and throwing an
+     * {@code IllegalStateException} if no space is currently available.
      * When using a capacity-restricted queue, it is generally preferable to
      * use {@link #offer(Object) offer}.
      *
      * @param e the element to add
-     * @return true (as specified by {@link Collection#add})
+     * @return {@code true} (as specified by {@link Collection#add})
      * @throws IllegalStateException if the element cannot be added at this
      *         time due to capacity restrictions
      * @throws ClassCastException if the class of the specified element
@@ -172,14 +172,14 @@ public interface BlockingQueue extends Queue {
     /**
      * Inserts the specified element into this queue if it is possible to do
      * so immediately without violating capacity restrictions, returning
-     * true upon success and false if no space is currently
+     * {@code true} upon success and {@code false} if no space is currently
      * available.  When using a capacity-restricted queue, this method is
      * generally preferable to {@link #add}, which can fail to insert an
      * element only by throwing an exception.
      *
      * @param e the element to add
-     * @return true if the element was added to this queue, else
-     *         false
+     * @return {@code true} if the element was added to this queue, else
+     *         {@code false}
      * @throws ClassCastException if the class of the specified element
      *         prevents it from being added to this queue
      * @throws NullPointerException if the specified element is null
@@ -208,10 +208,10 @@ public interface BlockingQueue extends Queue {
      *
      * @param e the element to add
      * @param timeout how long to wait before giving up, in units of
-     *        unit
-     * @param unit a TimeUnit determining how to interpret the
-     *        timeout parameter
-     * @return true if successful, or false if
+     *        {@code unit}
+     * @param unit a {@code TimeUnit} determining how to interpret the
+     *        {@code timeout} parameter
+     * @return {@code true} if successful, or {@code false} if
      *         the specified waiting time elapses before space is available
      * @throws InterruptedException if interrupted while waiting
      * @throws ClassCastException if the class of the specified element
@@ -237,10 +237,10 @@ public interface BlockingQueue extends Queue {
      * specified wait time if necessary for an element to become available.
      *
      * @param timeout how long to wait before giving up, in units of
-     *        unit
-     * @param unit a TimeUnit determining how to interpret the
-     *        timeout parameter
-     * @return the head of this queue, or null if the
+     *        {@code unit}
+     * @param unit a {@code TimeUnit} determining how to interpret the
+     *        {@code timeout} parameter
+     * @return the head of this queue, or {@code null} if the
      *         specified waiting time elapses before an element is available
      * @throws InterruptedException if interrupted while waiting
      */
@@ -250,11 +250,11 @@ public interface BlockingQueue extends Queue {
     /**
      * Returns the number of additional elements that this queue can ideally
      * (in the absence of memory or resource constraints) accept without
-     * blocking, or Integer.MAX_VALUE if there is no intrinsic
+     * blocking, or {@code Integer.MAX_VALUE} if there is no intrinsic
      * limit.
      *
      * 

Note that you cannot always tell if an attempt to insert - * an element will succeed by inspecting remainingCapacity + * 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. * @@ -264,14 +264,14 @@ public interface BlockingQueue extends Queue { /** * Removes a single instance of the specified element from this queue, - * if it is present. More formally, removes an element e such - * that o.equals(e), if this queue contains one or more such + * 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 true 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 true if this queue changed as a result of the call + * @return {@code true} if this queue changed as a result of the call * @throws ClassCastException if the class of the specified element * is incompatible with this queue * (optional) @@ -281,12 +281,12 @@ public interface BlockingQueue extends Queue { boolean remove(Object o); /** - * Returns true if this queue contains the specified element. - * More formally, returns true if and only if this queue contains - * at least one element e such that o.equals(e). + * Returns {@code true} if this queue contains the specified element. + * More formally, returns {@code true} if and only if this queue contains + * at least one element {@code e} such that {@code o.equals(e)}. * * @param o object to be checked for containment in this queue - * @return true if this queue contains the specified element + * @return {@code true} if this queue contains the specified element * @throws ClassCastException if the class of the specified element * is incompatible with this queue * (optional) @@ -300,10 +300,10 @@ public interface BlockingQueue extends Queue { * to the given collection. This operation may be more * efficient than repeatedly polling this queue. A failure * encountered while attempting to add elements to - * collection c may result in elements being in neither, + * collection {@code c} may result in elements being in neither, * either or both collections when the associated exception is * thrown. Attempts to drain a queue to itself result in - * IllegalArgumentException. Further, the behavior of + * {@code IllegalArgumentException}. Further, the behavior of * this operation is undefined if the specified collection is * modified while the operation is in progress. * @@ -324,10 +324,10 @@ public interface BlockingQueue extends Queue { * Removes at most the given number of available elements from * this queue and adds them to the given collection. A failure * encountered while attempting to add elements to - * collection c may result in elements being in neither, + * collection {@code c} may result in elements being in neither, * either or both collections when the associated exception is * thrown. Attempts to drain a queue to itself result in - * IllegalArgumentException. Further, the behavior of + * {@code IllegalArgumentException}. Further, the behavior of * this operation is undefined if the specified collection is * modified while the operation is in progress. * diff --git a/luni/src/main/java/java/util/concurrent/BrokenBarrierException.java b/luni/src/main/java/java/util/concurrent/BrokenBarrierException.java index 76fae13..9fe707d 100644 --- a/luni/src/main/java/java/util/concurrent/BrokenBarrierException.java +++ b/luni/src/main/java/java/util/concurrent/BrokenBarrierException.java @@ -15,19 +15,18 @@ package java.util.concurrent; * * @since 1.5 * @author Doug Lea - * */ public class BrokenBarrierException extends Exception { private static final long serialVersionUID = 7117394618823254244L; /** - * Constructs a BrokenBarrierException with no specified detail + * Constructs a {@code BrokenBarrierException} with no specified detail * message. */ public BrokenBarrierException() {} /** - * Constructs a BrokenBarrierException with the specified + * Constructs a {@code BrokenBarrierException} with the specified * detail message. * * @param message the detail message diff --git a/luni/src/main/java/java/util/concurrent/Callable.java b/luni/src/main/java/java/util/concurrent/Callable.java index 293544b..a3b3883 100644 --- a/luni/src/main/java/java/util/concurrent/Callable.java +++ b/luni/src/main/java/java/util/concurrent/Callable.java @@ -9,21 +9,21 @@ package java.util.concurrent; /** * A task that returns a result and may throw an exception. * Implementors define a single method with no arguments called - * call. + * {@code call}. * - *

The Callable interface is similar to {@link + *

The {@code Callable} interface is similar to {@link * java.lang.Runnable}, in that both are designed for classes whose * instances are potentially executed by another thread. A - * Runnable, however, does not return a result and cannot + * {@code Runnable}, however, does not return a result and cannot * throw a checked exception. * - *

The {@link Executors} class contains utility methods to - * convert from other common forms to Callable classes. + *

The {@link Executors} class contains utility methods to + * convert from other common forms to {@code Callable} classes. * * @see Executor * @since 1.5 * @author Doug Lea - * @param the result type of method call + * @param the result type of method {@code call} */ public interface Callable { /** diff --git a/luni/src/main/java/java/util/concurrent/CancellationException.java b/luni/src/main/java/java/util/concurrent/CancellationException.java index dc452e4..25ab271 100644 --- a/luni/src/main/java/java/util/concurrent/CancellationException.java +++ b/luni/src/main/java/java/util/concurrent/CancellationException.java @@ -18,12 +18,12 @@ public class CancellationException extends IllegalStateException { private static final long serialVersionUID = -9202173006928992231L; /** - * Constructs a CancellationException with no detail message. + * Constructs a {@code CancellationException} with no detail message. */ public CancellationException() {} /** - * Constructs a CancellationException with the specified detail + * Constructs a {@code CancellationException} with the specified detail * message. * * @param message the detail message diff --git a/luni/src/main/java/java/util/concurrent/CompletionService.java b/luni/src/main/java/java/util/concurrent/CompletionService.java index 7b0931c..0607596 100644 --- a/luni/src/main/java/java/util/concurrent/CompletionService.java +++ b/luni/src/main/java/java/util/concurrent/CompletionService.java @@ -9,17 +9,17 @@ package java.util.concurrent; /** * A service that decouples the production of new asynchronous tasks * from the consumption of the results of completed tasks. Producers - * submit tasks for execution. Consumers take + * {@code submit} tasks for execution. Consumers {@code take} * completed tasks and process their results in the order they - * complete. A CompletionService can for example be used to - * manage asynchronous IO, in which tasks that perform reads are + * complete. A {@code CompletionService} can for example be used to + * manage asynchronous I/O, in which tasks that perform reads are * submitted in one part of a program or system, and then acted upon * in a different part of the program when the reads complete, * possibly in a different order than they were requested. * - *

Typically, a CompletionService relies on a separate + *

Typically, a {@code CompletionService} relies on a separate * {@link Executor} to actually execute the tasks, in which case the - * CompletionService only manages an internal completion + * {@code CompletionService} only manages an internal completion * queue. The {@link ExecutorCompletionService} class provides an * implementation of this approach. * @@ -28,7 +28,6 @@ package java.util.concurrent; * happen-before * actions taken by that task, which in turn happen-before * actions following a successful return from the corresponding {@code take()}. - * */ public interface CompletionService { /** @@ -52,7 +51,7 @@ public interface CompletionService { * @param task the task to submit * @param result the result to return upon successful completion * @return a Future representing pending completion of the task, - * and whose get() method will return the given + * and whose {@code get()} method will return the given * result value upon completion * @throws RejectedExecutionException if the task cannot be * scheduled for execution @@ -69,13 +68,12 @@ public interface CompletionService { */ Future take() throws InterruptedException; - /** * Retrieves and removes the Future representing the next - * completed task or null if none are present. + * completed task, or {@code null} if none are present. * * @return the Future representing the next completed task, or - * null if none are present + * {@code null} if none are present */ Future poll(); @@ -85,11 +83,11 @@ public interface CompletionService { * time if none are yet present. * * @param timeout how long to wait before giving up, in units of - * unit - * @param unit a TimeUnit determining how to interpret the - * timeout parameter + * {@code unit} + * @param unit a {@code TimeUnit} determining how to interpret the + * {@code timeout} parameter * @return the Future representing the next completed task or - * null if the specified waiting time elapses + * {@code null} if the specified waiting time elapses * before one is present * @throws InterruptedException if interrupted while waiting */ diff --git a/luni/src/main/java/java/util/concurrent/ConcurrentLinkedDeque.java b/luni/src/main/java/java/util/concurrent/ConcurrentLinkedDeque.java index 30adb36..54b53ae 100644 --- a/luni/src/main/java/java/util/concurrent/ConcurrentLinkedDeque.java +++ b/luni/src/main/java/java/util/concurrent/ConcurrentLinkedDeque.java @@ -63,7 +63,6 @@ import java.util.Queue; * @author Martin Buchholz * @param the type of elements held in this collection */ - public class ConcurrentLinkedDeque extends AbstractCollection implements Deque, java.io.Serializable { @@ -790,7 +789,7 @@ public class ConcurrentLinkedDeque * Creates an array list and fills it with elements of this list. * Used by toArray. * - * @return the arrayList + * @return the array list */ private ArrayList toArrayList() { ArrayList list = new ArrayList(); @@ -1360,11 +1359,10 @@ public class ConcurrentLinkedDeque } /** - * Saves the state to a stream (that is, serializes it). + * Saves this deque to a stream (that is, serializes it). * * @serialData All of the elements (each an {@code E}) in * the proper order, followed by a null - * @param s the stream */ private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException { @@ -1384,8 +1382,7 @@ public class ConcurrentLinkedDeque } /** - * Reconstitutes the instance from a stream (that is, deserializes it). - * @param s the stream + * Reconstitutes this deque from a stream (that is, deserializes it). */ private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { @@ -1408,7 +1405,6 @@ public class ConcurrentLinkedDeque initHeadTail(h, t); } - private boolean casHead(Node cmp, Node val) { return UNSAFE.compareAndSwapObject(this, headOffset, cmp, val); } diff --git a/luni/src/main/java/java/util/concurrent/ConcurrentLinkedQueue.java b/luni/src/main/java/java/util/concurrent/ConcurrentLinkedQueue.java index a0a26fd..873f825 100644 --- a/luni/src/main/java/java/util/concurrent/ConcurrentLinkedQueue.java +++ b/luni/src/main/java/java/util/concurrent/ConcurrentLinkedQueue.java @@ -69,7 +69,6 @@ import java.util.Queue; * @since 1.5 * @author Doug Lea * @param the type of elements held in this collection - * */ public class ConcurrentLinkedQueue extends AbstractQueue implements Queue, java.io.Serializable { @@ -218,7 +217,6 @@ public class ConcurrentLinkedQueue extends AbstractQueue */ private transient volatile Node tail; - /** * Creates a {@code ConcurrentLinkedQueue} that is initially empty. */ @@ -268,7 +266,7 @@ public class ConcurrentLinkedQueue extends AbstractQueue } /** - * Try to CAS head to p. If successful, repoint old head to itself + * Tries to CAS head to p. If successful, repoint old head to itself * as sentinel for succ(), below. */ final void updateHead(Node h, Node p) { @@ -717,11 +715,10 @@ public class ConcurrentLinkedQueue extends AbstractQueue } /** - * Saves the state to a stream (that is, serializes it). + * Saves this queue to a stream (that is, serializes it). * * @serialData All of the elements (each an {@code E}) in * the proper order, followed by a null - * @param s the stream */ private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException { @@ -741,8 +738,7 @@ public class ConcurrentLinkedQueue extends AbstractQueue } /** - * Reconstitutes the instance from a stream (that is, deserializes it). - * @param s the stream + * Reconstitutes this queue from a stream (that is, deserializes it). */ private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { diff --git a/luni/src/main/java/java/util/concurrent/ConcurrentMap.java b/luni/src/main/java/java/util/concurrent/ConcurrentMap.java index 3405acf..27feeb2 100644 --- a/luni/src/main/java/java/util/concurrent/ConcurrentMap.java +++ b/luni/src/main/java/java/util/concurrent/ConcurrentMap.java @@ -13,7 +13,7 @@ import java.util.Map; /** * A {@link java.util.Map} providing additional atomic - * putIfAbsent, remove, and replace methods. + * {@code putIfAbsent}, {@code remove}, and {@code replace} methods. * *

Memory consistency effects: As with other concurrent * collections, actions in a thread prior to placing an object into a @@ -27,7 +27,7 @@ import java.util.Map; * @param the type of keys maintained by this map * @param the type of mapped values */ -public interface ConcurrentMap extends Map { +public interface ConcurrentMap extends Map { /** * If the specified key is not already associated * with a value, associate it with the given value. @@ -43,11 +43,11 @@ public interface ConcurrentMap extends Map { * @param key key with which the specified value is to be associated * @param value value to be associated with the specified key * @return the previous value associated with the specified key, or - * null if there was no mapping for the key. - * (A null return can also indicate that the map - * previously associated null with the key, + * {@code null} if there was no mapping for the key. + * (A {@code null} return can also indicate that the map + * previously associated {@code null} with the key, * if the implementation supports null values.) - * @throws UnsupportedOperationException if the put operation + * @throws UnsupportedOperationException if the {@code put} operation * is not supported by this map * @throws ClassCastException if the class of the specified key or value * prevents it from being stored in this map @@ -55,7 +55,6 @@ public interface ConcurrentMap extends Map { * and this map does not permit null keys or values * @throws IllegalArgumentException if some property of the specified key * or value prevents it from being stored in this map - * */ V putIfAbsent(K key, V value); @@ -73,8 +72,8 @@ public interface ConcurrentMap extends Map { * * @param key key with which the specified value is associated * @param value value expected to be associated with the specified key - * @return true if the value was removed - * @throws UnsupportedOperationException if the remove operation + * @return {@code true} if the value was removed + * @throws UnsupportedOperationException if the {@code remove} operation * is not supported by this map * @throws ClassCastException if the key or value is of an inappropriate * type for this map @@ -100,8 +99,8 @@ public interface ConcurrentMap extends Map { * @param key key with which the specified value is associated * @param oldValue value expected to be associated with the specified key * @param newValue value to be associated with the specified key - * @return true if the value was replaced - * @throws UnsupportedOperationException if the put operation + * @return {@code true} if the value was replaced + * @throws UnsupportedOperationException if the {@code put} operation * is not supported by this map * @throws ClassCastException if the class of a specified key or value * prevents it from being stored in this map @@ -126,11 +125,11 @@ public interface ConcurrentMap extends Map { * @param key key with which the specified value is associated * @param value value to be associated with the specified key * @return the previous value associated with the specified key, or - * null if there was no mapping for the key. - * (A null return can also indicate that the map - * previously associated null with the key, + * {@code null} if there was no mapping for the key. + * (A {@code null} return can also indicate that the map + * previously associated {@code null} with the key, * if the implementation supports null values.) - * @throws UnsupportedOperationException if the put operation + * @throws UnsupportedOperationException if the {@code put} operation * is not supported by this map * @throws ClassCastException if the class of the specified key or value * prevents it from being stored in this map diff --git a/luni/src/main/java/java/util/concurrent/ConcurrentNavigableMap.java b/luni/src/main/java/java/util/concurrent/ConcurrentNavigableMap.java index ea99886..e87fbee 100644 --- a/luni/src/main/java/java/util/concurrent/ConcurrentNavigableMap.java +++ b/luni/src/main/java/java/util/concurrent/ConcurrentNavigableMap.java @@ -38,7 +38,6 @@ public interface ConcurrentNavigableMap */ ConcurrentNavigableMap headMap(K toKey, boolean inclusive); - /** * @throws ClassCastException {@inheritDoc} * @throws NullPointerException {@inheritDoc} @@ -73,7 +72,7 @@ public interface ConcurrentNavigableMap * reflected in the descending map, and vice-versa. * *

The returned map has an ordering equivalent to - * {@link Collections#reverseOrder(Comparator) Collections.reverseOrder}(comparator()). + * {@link Collections#reverseOrder(Comparator) Collections.reverseOrder}{@code (comparator())}. * The expression {@code m.descendingMap().descendingMap()} returns a * view of {@code m} essentially equivalent to {@code m}. * diff --git a/luni/src/main/java/java/util/concurrent/ConcurrentSkipListMap.java b/luni/src/main/java/java/util/concurrent/ConcurrentSkipListMap.java index d0d6f14..803cd49 100644 --- a/luni/src/main/java/java/util/concurrent/ConcurrentSkipListMap.java +++ b/luni/src/main/java/java/util/concurrent/ConcurrentSkipListMap.java @@ -20,8 +20,8 @@ import java.util.*; *

This class implements a concurrent variant of SkipLists * providing expected average log(n) time cost for the - * containsKey, get, put and - * remove operations and their variants. Insertion, removal, + * {@code containsKey}, {@code get}, {@code put} and + * {@code remove} operations and their variants. Insertion, removal, * update, and access operations safely execute concurrently by * multiple threads. Iterators are weakly consistent, returning * elements reflecting the state of the map at some point at or since @@ -30,28 +30,28 @@ import java.util.*; * other operations. Ascending key ordered views and their iterators * are faster than descending ones. * - *

All Map.Entry pairs returned by methods in this class + *

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

Beware that, unlike in most collections, the size + *

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

This class and its views and iterators implement all of the * optional methods of the {@link Map} and {@link Iterator} * interfaces. Like most other concurrent collections, this class does - * not permit the use of null keys or values because some + * not permit the use of {@code null} keys or values because some * null return values cannot be reliably distinguished from the absence of * elements. * @@ -60,6 +60,7 @@ import java.util.*; * @param the type of mapped values * @since 1.6 */ +@SuppressWarnings("unchecked") public class ConcurrentSkipListMap extends AbstractMap implements ConcurrentNavigableMap, Cloneable, @@ -408,7 +409,7 @@ public class ConcurrentSkipListMap extends AbstractMap * 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() { @@ -457,7 +458,7 @@ public class ConcurrentSkipListMap extends AbstractMap * 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. + * is deleted, else null */ V getValidValue() { Object v = value; @@ -810,7 +811,7 @@ public class ConcurrentSkipListMap extends AbstractMap * 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 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 */ @@ -934,7 +935,7 @@ public class ConcurrentSkipListMap extends AbstractMap * 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 + * snapshotted by callers to provide correct insertion level. * @param indexLevel the level of the index */ private void addIndex(Index idx, HeadIndex h, int indexLevel) { @@ -1359,7 +1360,7 @@ public class ConcurrentSkipListMap extends AbstractMap * comparator. * * @param comparator the comparator that will be used to order this map. - * If null, the {@linkplain Comparable natural + * If {@code null}, the {@linkplain Comparable natural * ordering} of the keys will be used. */ public ConcurrentSkipListMap(Comparator comparator) { @@ -1373,7 +1374,7 @@ public class ConcurrentSkipListMap extends AbstractMap * the keys. * * @param m the map whose mappings are to be placed in this map - * @throws ClassCastException if the keys in m are not + * @throws ClassCastException if the keys in {@code m} are not * {@link Comparable}, or are not mutually comparable * @throws NullPointerException if the specified map or any of its keys * or values are null @@ -1400,7 +1401,7 @@ public class ConcurrentSkipListMap extends AbstractMap } /** - * Returns a shallow copy of this ConcurrentSkipListMap + * Returns a shallow copy of this {@code ConcurrentSkipListMap} * instance. (The keys and values themselves are not cloned.) * * @return a shallow copy of this map @@ -1477,11 +1478,11 @@ public class ConcurrentSkipListMap extends AbstractMap /* ---------------- Serialization -------------- */ /** - * Saves the state of this map to a stream (that is, serializes it). + * Saves this map to a stream (that is, serializes it). * * @serialData The key (Object) and value (Object) for each * key-value mapping represented by the map, followed by - * null. The key-value mappings are emitted in key-order + * {@code null}. The key-value mappings are emitted in key-order * (as determined by the Comparator, or by the keys' natural * ordering if no Comparator). */ @@ -1502,9 +1503,7 @@ public class ConcurrentSkipListMap extends AbstractMap } /** - * Reconstitutes the map from a stream (that is, deserializes it). - * - * @param s the stream + * Reconstitutes this map from a stream (that is, deserializes it). */ private void readObject(final java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { @@ -1567,11 +1566,11 @@ public class ConcurrentSkipListMap extends AbstractMap /* ------ Map API methods ------ */ /** - * Returns true if this map contains a mapping for the specified + * Returns {@code true} if this map contains a mapping for the specified * key. * * @param key key whose presence in this map is to be tested - * @return true if this map contains a mapping for the specified key + * @return {@code true} if this map contains a mapping for the specified key * @throws ClassCastException if the specified key cannot be compared * with the keys currently in the map * @throws NullPointerException if the specified key is null @@ -1606,7 +1605,7 @@ public class ConcurrentSkipListMap extends AbstractMap * @param key key with which the specified value is to be associated * @param value value to be associated with the specified key * @return the previous value associated with the specified key, or - * null if there was no mapping for the key + * {@code null} if there was no mapping for the key * @throws ClassCastException if the specified key cannot be compared * with the keys currently in the map * @throws NullPointerException if the specified key or value is null @@ -1622,7 +1621,7 @@ public class ConcurrentSkipListMap extends AbstractMap * * @param key key for which mapping should be removed * @return the previous value associated with the specified key, or - * null if there was no mapping for the key + * {@code null} if there was no mapping for the key * @throws ClassCastException if the specified key cannot be compared * with the keys currently in the map * @throws NullPointerException if the specified key is null @@ -1632,15 +1631,15 @@ public class ConcurrentSkipListMap extends AbstractMap } /** - * Returns true if this map maps one or more keys to the + * Returns {@code true} if this map maps one or more keys to the * specified value. This operation requires time linear in the * map size. Additionally, it is possible for the map to change * during execution of this method, in which case the returned * result may be inaccurate. * * @param value value whose presence in this map is to be tested - * @return true if a mapping to value exists; - * false otherwise + * @return {@code true} if a mapping to {@code value} exists; + * {@code false} otherwise * @throws NullPointerException if the specified value is null */ public boolean containsValue(Object value) { @@ -1656,8 +1655,8 @@ public class ConcurrentSkipListMap extends AbstractMap /** * Returns the number of key-value mappings in this map. If this map - * contains more than Integer.MAX_VALUE elements, it - * returns Integer.MAX_VALUE. + * contains more than {@code Integer.MAX_VALUE} elements, it + * returns {@code Integer.MAX_VALUE}. * *

Beware that, unlike in most collections, this method is * NOT a constant-time operation. Because of the @@ -1680,8 +1679,8 @@ public class ConcurrentSkipListMap extends AbstractMap } /** - * Returns true if this map contains no key-value mappings. - * @return true if this map contains no key-value mappings + * Returns {@code true} if this map contains no key-value mappings. + * @return {@code true} if this map contains no key-value mappings */ public boolean isEmpty() { return findFirst() == null; @@ -1743,12 +1742,12 @@ public class ConcurrentSkipListMap extends AbstractMap * The collection is backed by the map, so changes to the map are * reflected in the collection, and vice-versa. The collection * supports element removal, which removes the corresponding - * mapping from the map, via the Iterator.remove, - * Collection.remove, removeAll, - * retainAll and clear operations. It does not - * support the add or addAll operations. + * mapping from the map, via the {@code Iterator.remove}, + * {@code Collection.remove}, {@code removeAll}, + * {@code retainAll} and {@code clear} operations. It does not + * support the {@code add} or {@code addAll} operations. * - *

The view's iterator is a "weakly consistent" iterator + *

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) @@ -1765,20 +1764,20 @@ public class ConcurrentSkipListMap extends AbstractMap * The set is backed by the map, so changes to the map are * reflected in the set, and vice-versa. The set supports element * removal, which removes the corresponding mapping from the map, - * via the Iterator.remove, Set.remove, - * removeAll, retainAll and clear - * operations. It does not support the add or - * addAll operations. + * via the {@code Iterator.remove}, {@code Set.remove}, + * {@code removeAll}, {@code retainAll} and {@code clear} + * operations. It does not support the {@code add} or + * {@code addAll} operations. * - *

The view's iterator is a "weakly consistent" iterator + *

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. * - *

The Map.Entry elements returned by - * iterator.next() do not support the - * setValue operation. + *

The {@code Map.Entry} elements returned by + * {@code iterator.next()} do not support the + * {@code setValue} operation. * * @return a set view of the mappings contained in this map, * sorted in ascending key order @@ -1802,15 +1801,15 @@ public class ConcurrentSkipListMap extends AbstractMap /** * Compares the specified object with this map for equality. - * Returns true if the given object is also a map and the + * Returns {@code true} if the given object is also a map and the * two maps represent the same mappings. More formally, two maps - * m1 and m2 represent the same mappings if - * m1.entrySet().equals(m2.entrySet()). This + * {@code m1} and {@code m2} represent the same mappings if + * {@code m1.entrySet().equals(m2.entrySet())}. This * operation may return misleading results if either map is * concurrently modified during execution of this method. * * @param o object to be compared for equality with this map - * @return true if the specified object is equal to this map + * @return {@code true} if the specified object is equal to this map */ public boolean equals(Object o) { if (o == this) @@ -1842,7 +1841,7 @@ public class ConcurrentSkipListMap extends AbstractMap * {@inheritDoc} * * @return the previous value associated with the specified key, - * or null if there was no mapping for the key + * or {@code null} if there was no mapping for the key * @throws ClassCastException if the specified key cannot be compared * with the keys currently in the map * @throws NullPointerException if the specified key or value is null @@ -1897,7 +1896,7 @@ public class ConcurrentSkipListMap extends AbstractMap * {@inheritDoc} * * @return the previous value associated with the specified key, - * or null if there was no mapping for the key + * or {@code null} if there was no mapping for the key * @throws ClassCastException if the specified key cannot be compared * with the keys currently in the map * @throws NullPointerException if the specified key or value is null @@ -2014,9 +2013,9 @@ public class ConcurrentSkipListMap extends AbstractMap /** * Returns a key-value mapping associated with the greatest key - * strictly less than the given key, or null if there is + * strictly less than the given key, or {@code null} if there is * no such key. The returned entry does not support the - * Entry.setValue method. + * {@code Entry.setValue} method. * * @throws ClassCastException {@inheritDoc} * @throws NullPointerException if the specified key is null @@ -2036,9 +2035,9 @@ public class ConcurrentSkipListMap extends AbstractMap /** * Returns a key-value mapping associated with the greatest key - * less than or equal to the given key, or null if there + * less than or equal to the given key, or {@code null} if there * is no such key. The returned entry does not support - * the Entry.setValue method. + * the {@code Entry.setValue} method. * * @param key the key * @throws ClassCastException {@inheritDoc} @@ -2060,9 +2059,9 @@ public class ConcurrentSkipListMap extends AbstractMap /** * Returns a key-value mapping associated with the least key - * greater than or equal to the given key, or null if + * greater than or equal to the given key, or {@code null} if * there is no such entry. The returned entry does not - * support the Entry.setValue method. + * support the {@code Entry.setValue} method. * * @throws ClassCastException {@inheritDoc} * @throws NullPointerException if the specified key is null @@ -2082,9 +2081,9 @@ public class ConcurrentSkipListMap extends AbstractMap /** * Returns a key-value mapping associated with the least key - * strictly greater than the given key, or null if there + * strictly greater than the given key, or {@code null} if there * is no such key. The returned entry does not support - * the Entry.setValue method. + * the {@code Entry.setValue} method. * * @param key the key * @throws ClassCastException {@inheritDoc} @@ -2106,9 +2105,9 @@ public class ConcurrentSkipListMap extends AbstractMap /** * Returns a key-value mapping associated with the least - * key in this map, or null if the map is empty. + * key in this map, or {@code null} if the map is empty. * The returned entry does not support - * the Entry.setValue method. + * the {@code Entry.setValue} method. */ public Map.Entry firstEntry() { for (;;) { @@ -2123,9 +2122,9 @@ public class ConcurrentSkipListMap extends AbstractMap /** * Returns a key-value mapping associated with the greatest - * key in this map, or null if the map is empty. + * key in this map, or {@code null} if the map is empty. * The returned entry does not support - * the Entry.setValue method. + * the {@code Entry.setValue} method. */ public Map.Entry lastEntry() { for (;;) { @@ -2140,9 +2139,9 @@ public class ConcurrentSkipListMap extends AbstractMap /** * Removes and returns a key-value mapping associated with - * the least key in this map, or null if the map is empty. + * the least key in this map, or {@code null} if the map is empty. * The returned entry does not support - * the Entry.setValue method. + * the {@code Entry.setValue} method. */ public Map.Entry pollFirstEntry() { return doRemoveFirstEntry(); @@ -2150,9 +2149,9 @@ public class ConcurrentSkipListMap extends AbstractMap /** * Removes and returns a key-value mapping associated with - * the greatest key in this map, or null if the map is empty. + * the greatest key in this map, or {@code null} if the map is empty. * The returned entry does not support - * the Entry.setValue method. + * the {@code Entry.setValue} method. */ public Map.Entry pollLastEntry() { return doRemoveLastEntry(); @@ -2268,7 +2267,7 @@ public class ConcurrentSkipListMap extends AbstractMap static final List toList(Collection c) { // Using size() here would be a pessimization. - List list = new ArrayList(); + ArrayList list = new ArrayList(); for (E e : c) list.add(e); return list; @@ -2312,7 +2311,7 @@ public class ConcurrentSkipListMap extends AbstractMap Collection c = (Collection) o; try { return containsAll(c) && c.containsAll(this); - } catch (ClassCastException unused) { + } catch (ClassCastException unused) { return false; } catch (NullPointerException unused) { return false; @@ -2421,7 +2420,7 @@ public class ConcurrentSkipListMap extends AbstractMap Collection c = (Collection) o; try { return containsAll(c) && c.containsAll(this); - } catch (ClassCastException unused) { + } catch (ClassCastException unused) { return false; } catch (NullPointerException unused) { return false; @@ -2438,8 +2437,8 @@ public class ConcurrentSkipListMap extends AbstractMap * underlying maps, differing in that mappings outside their range are * ignored, and attempts to add mappings outside their ranges result * in {@link IllegalArgumentException}. Instances of this class are - * constructed only using the subMap, headMap, and - * tailMap methods of their underlying maps. + * constructed only using the {@code subMap}, {@code headMap}, and + * {@code tailMap} methods of their underlying maps. * * @serial include */ @@ -2467,7 +2466,7 @@ public class ConcurrentSkipListMap extends AbstractMap private transient Collection valuesView; /** - * Creates a new submap, initializing all fields + * Creates a new submap, initializing all fields. */ SubMap(ConcurrentSkipListMap map, K fromKey, boolean fromInclusive, @@ -2516,7 +2515,7 @@ public class ConcurrentSkipListMap extends AbstractMap } /** - * Returns true if node key is less than upper bound of range + * Returns true if node key is less than upper bound of range. */ private boolean isBeforeEnd(ConcurrentSkipListMap.Node n) { if (n == null) @@ -2534,7 +2533,7 @@ public class ConcurrentSkipListMap extends AbstractMap /** * Returns lowest node. This node might not be in range, so - * most usages need to check bounds + * most usages need to check bounds. */ private ConcurrentSkipListMap.Node loNode() { if (lo == null) @@ -2547,7 +2546,7 @@ public class ConcurrentSkipListMap extends AbstractMap /** * Returns highest node. This node might not be in range, so - * most usages need to check bounds + * most usages need to check bounds. */ private ConcurrentSkipListMap.Node hiNode() { if (hi == null) @@ -2559,7 +2558,7 @@ public class ConcurrentSkipListMap extends AbstractMap } /** - * Returns lowest absolute key (ignoring directonality) + * Returns lowest absolute key (ignoring directonality). */ private K lowestKey() { ConcurrentSkipListMap.Node n = loNode(); @@ -2570,7 +2569,7 @@ public class ConcurrentSkipListMap extends AbstractMap } /** - * Returns highest absolute key (ignoring directonality) + * Returns highest absolute key (ignoring directonality). */ private K highestKey() { ConcurrentSkipListMap.Node n = hiNode(); diff --git a/luni/src/main/java/java/util/concurrent/ConcurrentSkipListSet.java b/luni/src/main/java/java/util/concurrent/ConcurrentSkipListSet.java index 71431a9..f1402b6 100644 --- a/luni/src/main/java/java/util/concurrent/ConcurrentSkipListSet.java +++ b/luni/src/main/java/java/util/concurrent/ConcurrentSkipListSet.java @@ -19,7 +19,7 @@ import java.util.*; * on which constructor is used. * *

This implementation provides expected average log(n) time - * cost for the contains, add, and remove + * cost for the {@code contains}, {@code add}, and {@code remove} * operations and their variants. Insertion, removal, and access * operations safely execute concurrently by multiple threads. * Iterators are weakly consistent, returning elements @@ -29,23 +29,23 @@ import java.util.*; * other operations. Ascending ordered views and their iterators are * faster than descending ones. * - *

Beware that, unlike in most collections, the size + *

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

This class and its iterators implement all of the * optional methods of the {@link Set} and {@link Iterator} * interfaces. Like most other concurrent collection implementations, - * this class does not permit the use of null elements, - * because null arguments and return values cannot be reliably + * this class does not permit the use of {@code null} elements, + * because {@code null} arguments and return values cannot be reliably * distinguished from the absence of elements. * * @author Doug Lea @@ -61,7 +61,7 @@ public class ConcurrentSkipListSet /** * 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() + * safety, which entails some ugliness in clone(). */ private final ConcurrentNavigableMap m; @@ -78,7 +78,7 @@ public class ConcurrentSkipListSet * the specified comparator. * * @param comparator the comparator that will be used to order this set. - * If null, the {@linkplain Comparable natural + * If {@code null}, the {@linkplain Comparable natural * ordering} of the elements will be used. */ public ConcurrentSkipListSet(Comparator comparator) { @@ -91,7 +91,7 @@ public class ConcurrentSkipListSet * {@linkplain Comparable natural ordering}. * * @param c The elements that will comprise the new set - * @throws ClassCastException if the elements in c are + * @throws ClassCastException if the elements in {@code c} are * not {@link Comparable}, or are not mutually comparable * @throws NullPointerException if the specified collection or any * of its elements are null @@ -122,7 +122,7 @@ public class ConcurrentSkipListSet } /** - * Returns a shallow copy of this ConcurrentSkipListSet + * Returns a shallow copy of this {@code ConcurrentSkipListSet} * instance. (The elements themselves are not cloned.) * * @return a shallow copy of this set @@ -143,8 +143,8 @@ public class ConcurrentSkipListSet /** * Returns the number of elements in this set. If this set - * contains more than Integer.MAX_VALUE elements, it - * returns Integer.MAX_VALUE. + * contains more than {@code Integer.MAX_VALUE} elements, it + * returns {@code Integer.MAX_VALUE}. * *

Beware that, unlike in most collections, this method is * NOT a constant-time operation. Because of the @@ -162,20 +162,20 @@ public class ConcurrentSkipListSet } /** - * Returns true if this set contains no elements. - * @return true if this set contains no elements + * Returns {@code true} if this set contains no elements. + * @return {@code true} if this set contains no elements */ public boolean isEmpty() { return m.isEmpty(); } /** - * Returns true if this set contains the specified element. - * More formally, returns true if and only if this set - * contains an element e such that o.equals(e). + * Returns {@code true} if this set contains the specified element. + * More formally, returns {@code true} if and only if this set + * contains an element {@code e} such that {@code o.equals(e)}. * * @param o object to be checked for containment in this set - * @return true if this set contains the specified element + * @return {@code true} if this set contains the specified element * @throws ClassCastException if the specified element cannot be * compared with the elements currently in this set * @throws NullPointerException if the specified element is null @@ -186,15 +186,15 @@ public class ConcurrentSkipListSet /** * Adds the specified element to this set if it is not already present. - * More formally, adds the specified element e to this set if - * the set contains no element e2 such that e.equals(e2). + * More formally, adds the specified element {@code e} to this set if + * the set contains no element {@code e2} such that {@code e.equals(e2)}. * If this set already contains the element, the call leaves the set - * unchanged and returns false. + * unchanged and returns {@code false}. * * @param e element to be added to this set - * @return true if this set did not already contain the + * @return {@code true} if this set did not already contain the * specified element - * @throws ClassCastException if e cannot be compared + * @throws ClassCastException if {@code e} cannot be compared * with the elements currently in this set * @throws NullPointerException if the specified element is null */ @@ -204,15 +204,15 @@ public class ConcurrentSkipListSet /** * Removes the specified element from this set if it is present. - * More formally, removes an element e such that - * o.equals(e), if this set contains such an element. - * Returns true if this set contained the element (or + * More formally, removes an element {@code e} such that + * {@code o.equals(e)}, if this set contains such an element. + * Returns {@code true} if this set contained the element (or * equivalently, if this set changed as a result of the call). * (This set will not contain the element once the call returns.) * * @param o object to be removed from this set, if present - * @return true if this set contained the specified element - * @throws ClassCastException if o cannot be compared + * @return {@code true} if this set contained the specified element + * @throws ClassCastException if {@code o} cannot be compared * with the elements currently in this set * @throws NullPointerException if the specified element is null */ @@ -250,7 +250,7 @@ public class ConcurrentSkipListSet /** * Compares the specified object with this set for equality. Returns - * true if the specified object is also a set, the two sets + * {@code true} if the specified object is also a set, the two sets * have the same size, and every member of the specified set is * contained in this set (or equivalently, every member of this set is * contained in the specified set). This definition ensures that the @@ -258,7 +258,7 @@ public class ConcurrentSkipListSet * set interface. * * @param o the object to be compared for equality with this set - * @return true if the specified object is equal to this set + * @return {@code true} if the specified object is equal to this set */ public boolean equals(Object o) { // Override AbstractSet version to avoid calling size() @@ -269,7 +269,7 @@ public class ConcurrentSkipListSet Collection c = (Collection) o; try { return containsAll(c) && c.containsAll(this); - } catch (ClassCastException unused) { + } catch (ClassCastException unused) { return false; } catch (NullPointerException unused) { return false; @@ -283,7 +283,7 @@ public class ConcurrentSkipListSet * value is the asymmetric set difference of the two sets. * * @param c collection containing elements to be removed from this set - * @return true if this set changed as a result of the call + * @return {@code true} if this set changed as a result of the call * @throws ClassCastException if the types of one or more elements in this * set are incompatible with the specified collection * @throws NullPointerException if the specified collection or any @@ -431,7 +431,7 @@ public class ConcurrentSkipListSet * reflected in the descending set, and vice-versa. * *

The returned set has an ordering equivalent to - * {@link Collections#reverseOrder(Comparator) Collections.reverseOrder}(comparator()). + * {@link Collections#reverseOrder(Comparator) Collections.reverseOrder}{@code (comparator())}. * The expression {@code s.descendingSet().descendingSet()} returns a * view of {@code s} essentially equivalent to {@code s}. * diff --git a/luni/src/main/java/java/util/concurrent/CopyOnWriteArraySet.java b/luni/src/main/java/java/util/concurrent/CopyOnWriteArraySet.java index 1f37bc9..6fa8feb 100644 --- a/luni/src/main/java/java/util/concurrent/CopyOnWriteArraySet.java +++ b/luni/src/main/java/java/util/concurrent/CopyOnWriteArraySet.java @@ -20,17 +20,17 @@ import java.util.*; * vastly outnumber mutative operations, and you need * to prevent interference among threads during traversal. *

  • It is thread-safe. - *
  • Mutative operations (add, set, remove, etc.) + *
  • Mutative operations ({@code add}, {@code set}, {@code remove}, etc.) * are expensive since they usually entail copying the entire underlying * array. - *
  • Iterators do not support the mutative remove operation. + *
  • Iterators do not support the mutative {@code remove} operation. *
  • Traversal via iterators is fast and cannot encounter * interference from other threads. Iterators rely on * unchanging snapshots of the array at the time the iterators were * constructed. * * - *

    Sample Usage. The following code sketch uses a + *

    Sample Usage. The following code sketch uses a * copy-on-write set to maintain a set of Handler objects that * perform some action upon state updates. * @@ -48,7 +48,7 @@ import java.util.*; * public void update() { * changeState(); * for (Handler handler : handlers) - * handler.handle(); + * handler.handle(); * } * }}

  • * @@ -92,22 +92,22 @@ public class CopyOnWriteArraySet extends AbstractSet } /** - * Returns true if this set contains no elements. + * Returns {@code true} if this set contains no elements. * - * @return true if this set contains no elements + * @return {@code true} if this set contains no elements */ public boolean isEmpty() { return al.isEmpty(); } /** - * Returns true if this set contains the specified element. - * More formally, returns true if and only if this set - * contains an element e such that + * Returns {@code true} if this set contains the specified element. + * More formally, returns {@code true} if and only if this set + * contains an element {@code e} such that * (o==null ? e==null : o.equals(e)). * * @param o element whose presence in this set is to be tested - * @return true if this set contains the specified element + * @return {@code true} if this set contains the specified element */ public boolean contains(Object o) { return al.contains(o); @@ -143,7 +143,7 @@ public class CopyOnWriteArraySet extends AbstractSet *

    If this set fits in the specified array with room to spare * (i.e., the array has more elements than this set), the element in * the array immediately following the end of the set is set to - * null. (This is useful in determining the length of this + * {@code null}. (This is useful in determining the length of this * set only if the caller knows that this set does not contain * any null elements.) * @@ -156,14 +156,14 @@ public class CopyOnWriteArraySet extends AbstractSet * precise control over the runtime type of the output array, and may, * under certain circumstances, be used to save allocation costs. * - *

    Suppose x is a set known to contain only strings. + *

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

     {@code String[] y = x.toArray(new String[0]);}
    * - * Note that toArray(new Object[0]) is identical in function to - * toArray(). + * Note that {@code toArray(new Object[0])} is identical in function to + * {@code toArray()}. * * @param a the array into which the elements of this set are to be * stored, if it is big enough; otherwise, a new array of the same @@ -188,15 +188,15 @@ public class CopyOnWriteArraySet extends AbstractSet /** * Removes the specified element from this set if it is present. - * More formally, removes an element e such that + * More formally, removes an element {@code e} such that * (o==null ? e==null : o.equals(e)), - * if this set contains such an element. Returns true if + * if this set contains such an element. Returns {@code true} if * this set contained the element (or equivalently, if this set * changed as a result of the call). (This set will not contain the * element once the call returns.) * * @param o object to be removed from this set, if present - * @return true if this set contained the specified element + * @return {@code true} if this set contained the specified element */ public boolean remove(Object o) { return al.remove(o); @@ -204,14 +204,14 @@ public class CopyOnWriteArraySet extends AbstractSet /** * Adds the specified element to this set if it is not already present. - * More formally, adds the specified element e to this set if - * the set contains no element e2 such that + * More formally, adds the specified element {@code e} to this set if + * the set contains no element {@code e2} such that * (e==null ? e2==null : e.equals(e2)). * If this set already contains the element, the call leaves the set - * unchanged and returns false. + * unchanged and returns {@code false}. * * @param e element to be added to this set - * @return true if this set did not already contain the specified + * @return {@code true} if this set did not already contain the specified * element */ public boolean add(E e) { @@ -219,12 +219,12 @@ public class CopyOnWriteArraySet extends AbstractSet } /** - * Returns true if this set contains all of the elements of the + * Returns {@code true} if this set contains all of the elements of the * specified collection. If the specified collection is also a set, this - * method returns true if it is a subset of this set. + * method returns {@code true} if it is a subset of this set. * * @param c collection to be checked for containment in this set - * @return true if this set contains all of the elements of the + * @return {@code true} if this set contains all of the elements of the * specified collection * @throws NullPointerException if the specified collection is null * @see #contains(Object) @@ -236,13 +236,13 @@ public class CopyOnWriteArraySet extends AbstractSet /** * Adds all of the elements in the specified collection to this set if * they're not already present. If the specified collection is also a - * set, the addAll operation effectively modifies this set so + * set, the {@code addAll} operation effectively modifies this set so * that its value is the union of the two sets. The behavior of * this operation is undefined if the specified collection is modified * while the operation is in progress. * * @param c collection containing elements to be added to this set - * @return true if this set changed as a result of the call + * @return {@code true} if this set changed as a result of the call * @throws NullPointerException if the specified collection is null * @see #add(Object) */ @@ -257,7 +257,7 @@ public class CopyOnWriteArraySet extends AbstractSet * asymmetric set difference of the two sets. * * @param c collection containing elements to be removed from this set - * @return true if this set changed as a result of the call + * @return {@code true} if this set changed as a result of the call * @throws ClassCastException if the class of an element of this set * is incompatible with the specified collection (optional) * @throws NullPointerException if this set contains a null element and the @@ -278,7 +278,7 @@ public class CopyOnWriteArraySet extends AbstractSet * two sets. * * @param c collection containing elements to be retained in this set - * @return true if this set changed as a result of the call + * @return {@code true} if this set changed as a result of the call * @throws ClassCastException if the class of an element of this set * is incompatible with the specified collection (optional) * @throws NullPointerException if this set contains a null element and the @@ -297,7 +297,7 @@ public class CopyOnWriteArraySet extends AbstractSet *

    The returned iterator provides a snapshot of the state of the set * when the iterator was constructed. No synchronization is needed while * traversing the iterator. The iterator does NOT support the - * remove method. + * {@code remove} method. * * @return an iterator over the elements in this set */ @@ -354,7 +354,7 @@ public class CopyOnWriteArraySet extends AbstractSet } /** - * Test for equality, coping with nulls. + * Tests for equality, coping with nulls. */ private static boolean eq(Object o1, Object o2) { return (o1 == null) ? o2 == null : o1.equals(o2); diff --git a/luni/src/main/java/java/util/concurrent/CountDownLatch.java b/luni/src/main/java/java/util/concurrent/CountDownLatch.java index e90badf..fe0fa65 100644 --- a/luni/src/main/java/java/util/concurrent/CountDownLatch.java +++ b/luni/src/main/java/java/util/concurrent/CountDownLatch.java @@ -5,7 +5,7 @@ */ package java.util.concurrent; -import java.util.concurrent.locks.*; +import java.util.concurrent.locks.AbstractQueuedSynchronizer; /** * A synchronization aid that allows one or more threads to wait until @@ -63,15 +63,15 @@ import java.util.concurrent.locks.*; * private final CountDownLatch startSignal; * private final CountDownLatch doneSignal; * Worker(CountDownLatch startSignal, CountDownLatch doneSignal) { - * this.startSignal = startSignal; - * this.doneSignal = doneSignal; + * this.startSignal = startSignal; + * this.doneSignal = doneSignal; * } * public void run() { - * try { - * startSignal.await(); - * doWork(); - * doneSignal.countDown(); - * } catch (InterruptedException ex) {} // return; + * try { + * startSignal.await(); + * doWork(); + * doneSignal.countDown(); + * } catch (InterruptedException ex) {} // return; * } * * void doWork() { ... } @@ -101,14 +101,14 @@ import java.util.concurrent.locks.*; * private final CountDownLatch doneSignal; * private final int i; * WorkerRunnable(CountDownLatch doneSignal, int i) { - * this.doneSignal = doneSignal; - * this.i = i; + * this.doneSignal = doneSignal; + * this.i = i; * } * public void run() { - * try { - * doWork(i); - * doneSignal.countDown(); - * } catch (InterruptedException ex) {} // return; + * try { + * doWork(i); + * doneSignal.countDown(); + * } catch (InterruptedException ex) {} // return; * } * * void doWork() { ... } diff --git a/luni/src/main/java/java/util/concurrent/CountedCompleter.java b/luni/src/main/java/java/util/concurrent/CountedCompleter.java new file mode 100644 index 0000000..ffe7582 --- /dev/null +++ b/luni/src/main/java/java/util/concurrent/CountedCompleter.java @@ -0,0 +1,715 @@ +/* + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +package java.util.concurrent; + +/** + * A {@link ForkJoinTask} with a completion action performed when + * triggered and there are no remaining pending + * actions. CountedCompleters are in general more robust in the + * presence of subtask stalls and blockage than are other forms of + * ForkJoinTasks, but are less intuitive to program. Uses of + * CountedCompleter are similar to those of other completion based + * components (such as {@link java.nio.channels.CompletionHandler}) + * except that multiple pending completions may be necessary + * to trigger the completion action {@link #onCompletion}, not just one. + * Unless initialized otherwise, the {@linkplain #getPendingCount pending + * count} starts at zero, but may be (atomically) changed using + * methods {@link #setPendingCount}, {@link #addToPendingCount}, and + * {@link #compareAndSetPendingCount}. Upon invocation of {@link + * #tryComplete}, if the pending action count is nonzero, it is + * decremented; otherwise, the completion action is performed, and if + * this completer itself has a completer, the process is continued + * with its completer. As is the case with related synchronization + * components such as {@link java.util.concurrent.Phaser Phaser} and + * {@link java.util.concurrent.Semaphore Semaphore}, these methods + * affect only internal counts; they do not establish any further + * internal bookkeeping. In particular, the identities of pending + * tasks are not maintained. As illustrated below, you can create + * subclasses that do record some or all pending tasks or their + * results when needed. As illustrated below, utility methods + * supporting customization of completion traversals are also + * provided. However, because CountedCompleters provide only basic + * synchronization mechanisms, it may be useful to create further + * abstract subclasses that maintain linkages, fields, and additional + * support methods appropriate for a set of related usages. + * + *

    A concrete CountedCompleter class must define method {@link + * #compute}, that should in most cases (as illustrated below), invoke + * {@code tryComplete()} once before returning. The class may also + * optionally override method {@link #onCompletion} to perform an + * action upon normal completion, and method {@link + * #onExceptionalCompletion} to perform an action upon any exception. + * + *

    CountedCompleters most often do not bear results, in which case + * they are normally declared as {@code CountedCompleter}, and + * will always return {@code null} as a result value. In other cases, + * you should override method {@link #getRawResult} to provide a + * result from {@code join(), invoke()}, and related methods. In + * general, this method should return the value of a field (or a + * function of one or more fields) of the CountedCompleter object that + * holds the result upon completion. Method {@link #setRawResult} by + * default plays no role in CountedCompleters. It is possible, but + * rarely applicable, to override this method to maintain other + * objects or fields holding result data. + * + *

    A CountedCompleter that does not itself have a completer (i.e., + * one for which {@link #getCompleter} returns {@code null}) can be + * used as a regular ForkJoinTask with this added functionality. + * However, any completer that in turn has another completer serves + * only as an internal helper for other computations, so its own task + * status (as reported in methods such as {@link ForkJoinTask#isDone}) + * is arbitrary; this status changes only upon explicit invocations of + * {@link #complete}, {@link ForkJoinTask#cancel}, {@link + * ForkJoinTask#completeExceptionally} or upon exceptional completion + * of method {@code compute}. Upon any exceptional completion, the + * exception may be relayed to a task's completer (and its completer, + * and so on), if one exists and it has not otherwise already + * completed. Similarly, cancelling an internal CountedCompleter has + * only a local effect on that completer, so is not often useful. + * + *

    Sample Usages. + * + *

    Parallel recursive decomposition. CountedCompleters may + * be arranged in trees similar to those often used with {@link + * RecursiveAction}s, although the constructions involved in setting + * them up typically vary. Here, the completer of each task is its + * parent in the computation tree. Even though they entail a bit more + * bookkeeping, CountedCompleters may be better choices when applying + * a possibly time-consuming operation (that cannot be further + * subdivided) to each element of an array or collection; especially + * when the operation takes a significantly different amount of time + * to complete for some elements than others, either because of + * intrinsic variation (for example I/O) or auxiliary effects such as + * garbage collection. Because CountedCompleters provide their own + * continuations, other threads need not block waiting to perform + * them. + * + *

    For example, here is an initial version of a class that uses + * divide-by-two recursive decomposition to divide work into single + * pieces (leaf tasks). Even when work is split into individual calls, + * tree-based techniques are usually preferable to directly forking + * leaf tasks, because they reduce inter-thread communication and + * improve load balancing. In the recursive case, the second of each + * pair of subtasks to finish triggers completion of its parent + * (because no result combination is performed, the default no-op + * implementation of method {@code onCompletion} is not overridden). A + * static utility method sets up the base task and invokes it + * (here, implicitly using the {@link ForkJoinPool#commonPool()}). + * + *

     {@code
    + * class MyOperation { void apply(E e) { ... }  }
    + *
    + * class ForEach extends CountedCompleter {
    + *
    + *   public static  void forEach(E[] array, MyOperation op) {
    + *     new ForEach(null, array, op, 0, array.length).invoke();
    + *   }
    + *
    + *   final E[] array; final MyOperation op; final int lo, hi;
    + *   ForEach(CountedCompleter p, E[] array, MyOperation op, int lo, int hi) {
    + *     super(p);
    + *     this.array = array; this.op = op; this.lo = lo; this.hi = hi;
    + *   }
    + *
    + *   public void compute() { // version 1
    + *     if (hi - lo >= 2) {
    + *       int mid = (lo + hi) >>> 1;
    + *       setPendingCount(2); // must set pending count before fork
    + *       new ForEach(this, array, op, mid, hi).fork(); // right child
    + *       new ForEach(this, array, op, lo, mid).fork(); // left child
    + *     }
    + *     else if (hi > lo)
    + *       op.apply(array[lo]);
    + *     tryComplete();
    + *   }
    + * }}
    + * + * This design can be improved by noticing that in the recursive case, + * the task has nothing to do after forking its right task, so can + * directly invoke its left task before returning. (This is an analog + * of tail recursion removal.) Also, because the task returns upon + * executing its left task (rather than falling through to invoke + * {@code tryComplete}) the pending count is set to one: + * + *
     {@code
    + * class ForEach ...
    + *   public void compute() { // version 2
    + *     if (hi - lo >= 2) {
    + *       int mid = (lo + hi) >>> 1;
    + *       setPendingCount(1); // only one pending
    + *       new ForEach(this, array, op, mid, hi).fork(); // right child
    + *       new ForEach(this, array, op, lo, mid).compute(); // direct invoke
    + *     }
    + *     else {
    + *       if (hi > lo)
    + *         op.apply(array[lo]);
    + *       tryComplete();
    + *     }
    + *   }
    + * }
    + * + * As a further improvement, notice that the left task need not even + * exist. Instead of creating a new one, we can iterate using the + * original task, and add a pending count for each fork. Additionally, + * because no task in this tree implements an {@link #onCompletion} + * method, {@code tryComplete()} can be replaced with {@link + * #propagateCompletion}. + * + *
     {@code
    + * class ForEach ...
    + *   public void compute() { // version 3
    + *     int l = lo,  h = hi;
    + *     while (h - l >= 2) {
    + *       int mid = (l + h) >>> 1;
    + *       addToPendingCount(1);
    + *       new ForEach(this, array, op, mid, h).fork(); // right child
    + *       h = mid;
    + *     }
    + *     if (h > l)
    + *       op.apply(array[l]);
    + *     propagateCompletion();
    + *   }
    + * }
    + * + * Additional improvements of such classes might entail precomputing + * pending counts so that they can be established in constructors, + * specializing classes for leaf steps, subdividing by say, four, + * instead of two per iteration, and using an adaptive threshold + * instead of always subdividing down to single elements. + * + *

    Searching. A tree of CountedCompleters can search for a + * value or property in different parts of a data structure, and + * report a result in an {@link + * java.util.concurrent.atomic.AtomicReference AtomicReference} as + * soon as one is found. The others can poll the result to avoid + * unnecessary work. (You could additionally {@linkplain #cancel + * cancel} other tasks, but it is usually simpler and more efficient + * to just let them notice that the result is set and if so skip + * further processing.) Illustrating again with an array using full + * partitioning (again, in practice, leaf tasks will almost always + * process more than one element): + * + *

     {@code
    + * class Searcher extends CountedCompleter {
    + *   final E[] array; final AtomicReference result; final int lo, hi;
    + *   Searcher(CountedCompleter p, E[] array, AtomicReference result, int lo, int hi) {
    + *     super(p);
    + *     this.array = array; this.result = result; this.lo = lo; this.hi = hi;
    + *   }
    + *   public E getRawResult() { return result.get(); }
    + *   public void compute() { // similar to ForEach version 3
    + *     int l = lo,  h = hi;
    + *     while (result.get() == null && h >= l) {
    + *       if (h - l >= 2) {
    + *         int mid = (l + h) >>> 1;
    + *         addToPendingCount(1);
    + *         new Searcher(this, array, result, mid, h).fork();
    + *         h = mid;
    + *       }
    + *       else {
    + *         E x = array[l];
    + *         if (matches(x) && result.compareAndSet(null, x))
    + *           quietlyCompleteRoot(); // root task is now joinable
    + *         break;
    + *       }
    + *     }
    + *     tryComplete(); // normally complete whether or not found
    + *   }
    + *   boolean matches(E e) { ... } // return true if found
    + *
    + *   public static  E search(E[] array) {
    + *       return new Searcher(null, array, new AtomicReference(), 0, array.length).invoke();
    + *   }
    + * }}
    + * + * In this example, as well as others in which tasks have no other + * effects except to compareAndSet a common result, the trailing + * unconditional invocation of {@code tryComplete} could be made + * conditional ({@code if (result.get() == null) tryComplete();}) + * because no further bookkeeping is required to manage completions + * once the root task completes. + * + *

    Recording subtasks. CountedCompleter tasks that combine + * results of multiple subtasks usually need to access these results + * in method {@link #onCompletion}. As illustrated in the following + * class (that performs a simplified form of map-reduce where mappings + * and reductions are all of type {@code E}), one way to do this in + * divide and conquer designs is to have each subtask record its + * sibling, so that it can be accessed in method {@code onCompletion}. + * This technique applies to reductions in which the order of + * combining left and right results does not matter; ordered + * reductions require explicit left/right designations. Variants of + * other streamlinings seen in the above examples may also apply. + * + *

     {@code
    + * class MyMapper { E apply(E v) {  ...  } }
    + * class MyReducer { E apply(E x, E y) {  ...  } }
    + * class MapReducer extends CountedCompleter {
    + *   final E[] array; final MyMapper mapper;
    + *   final MyReducer reducer; final int lo, hi;
    + *   MapReducer sibling;
    + *   E result;
    + *   MapReducer(CountedCompleter p, E[] array, MyMapper mapper,
    + *              MyReducer reducer, int lo, int hi) {
    + *     super(p);
    + *     this.array = array; this.mapper = mapper;
    + *     this.reducer = reducer; this.lo = lo; this.hi = hi;
    + *   }
    + *   public void compute() {
    + *     if (hi - lo >= 2) {
    + *       int mid = (lo + hi) >>> 1;
    + *       MapReducer left = new MapReducer(this, array, mapper, reducer, lo, mid);
    + *       MapReducer right = new MapReducer(this, array, mapper, reducer, mid, hi);
    + *       left.sibling = right;
    + *       right.sibling = left;
    + *       setPendingCount(1); // only right is pending
    + *       right.fork();
    + *       left.compute();     // directly execute left
    + *     }
    + *     else {
    + *       if (hi > lo)
    + *           result = mapper.apply(array[lo]);
    + *       tryComplete();
    + *     }
    + *   }
    + *   public void onCompletion(CountedCompleter caller) {
    + *     if (caller != this) {
    + *       MapReducer child = (MapReducer)caller;
    + *       MapReducer sib = child.sibling;
    + *       if (sib == null || sib.result == null)
    + *         result = child.result;
    + *       else
    + *         result = reducer.apply(child.result, sib.result);
    + *     }
    + *   }
    + *   public E getRawResult() { return result; }
    + *
    + *   public static  E mapReduce(E[] array, MyMapper mapper, MyReducer reducer) {
    + *     return new MapReducer(null, array, mapper, reducer,
    + *                              0, array.length).invoke();
    + *   }
    + * }}
    + * + * Here, method {@code onCompletion} takes a form common to many + * completion designs that combine results. This callback-style method + * is triggered once per task, in either of the two different contexts + * in which the pending count is, or becomes, zero: (1) by a task + * itself, if its pending count is zero upon invocation of {@code + * tryComplete}, or (2) by any of its subtasks when they complete and + * decrement the pending count to zero. The {@code caller} argument + * distinguishes cases. Most often, when the caller is {@code this}, + * no action is necessary. Otherwise the caller argument can be used + * (usually via a cast) to supply a value (and/or links to other + * values) to be combined. Assuming proper use of pending counts, the + * actions inside {@code onCompletion} occur (once) upon completion of + * a task and its subtasks. No additional synchronization is required + * within this method to ensure thread safety of accesses to fields of + * this task or other completed tasks. + * + *

    Completion Traversals. If using {@code onCompletion} to + * process completions is inapplicable or inconvenient, you can use + * methods {@link #firstComplete} and {@link #nextComplete} to create + * custom traversals. For example, to define a MapReducer that only + * splits out right-hand tasks in the form of the third ForEach + * example, the completions must cooperatively reduce along + * unexhausted subtask links, which can be done as follows: + * + *

     {@code
    + * class MapReducer extends CountedCompleter { // version 2
    + *   final E[] array; final MyMapper mapper;
    + *   final MyReducer reducer; final int lo, hi;
    + *   MapReducer forks, next; // record subtask forks in list
    + *   E result;
    + *   MapReducer(CountedCompleter p, E[] array, MyMapper mapper,
    + *              MyReducer reducer, int lo, int hi, MapReducer next) {
    + *     super(p);
    + *     this.array = array; this.mapper = mapper;
    + *     this.reducer = reducer; this.lo = lo; this.hi = hi;
    + *     this.next = next;
    + *   }
    + *   public void compute() {
    + *     int l = lo,  h = hi;
    + *     while (h - l >= 2) {
    + *       int mid = (l + h) >>> 1;
    + *       addToPendingCount(1);
    + *       (forks = new MapReducer(this, array, mapper, reducer, mid, h, forks)).fork();
    + *       h = mid;
    + *     }
    + *     if (h > l)
    + *       result = mapper.apply(array[l]);
    + *     // process completions by reducing along and advancing subtask links
    + *     for (CountedCompleter c = firstComplete(); c != null; c = c.nextComplete()) {
    + *       for (MapReducer t = (MapReducer)c, s = t.forks;  s != null; s = t.forks = s.next)
    + *         t.result = reducer.apply(t.result, s.result);
    + *     }
    + *   }
    + *   public E getRawResult() { return result; }
    + *
    + *   public static  E mapReduce(E[] array, MyMapper mapper, MyReducer reducer) {
    + *     return new MapReducer(null, array, mapper, reducer,
    + *                              0, array.length, null).invoke();
    + *   }
    + * }}
    + * + *

    Triggers. Some CountedCompleters are themselves never + * forked, but instead serve as bits of plumbing in other designs; + * including those in which the completion of one of more async tasks + * triggers another async task. For example: + * + *

     {@code
    + * class HeaderBuilder extends CountedCompleter<...> { ... }
    + * class BodyBuilder extends CountedCompleter<...> { ... }
    + * class PacketSender extends CountedCompleter<...> {
    + *   PacketSender(...) { super(null, 1); ... } // trigger on second completion
    + *   public void compute() { } // never called
    + *   public void onCompletion(CountedCompleter caller) { sendPacket(); }
    + * }
    + * // sample use:
    + * PacketSender p = new PacketSender();
    + * new HeaderBuilder(p, ...).fork();
    + * new BodyBuilder(p, ...).fork();
    + * }
    + * + * @since 1.8 + * @hide + * @author Doug Lea + */ +public abstract class CountedCompleter extends ForkJoinTask { + private static final long serialVersionUID = 5232453752276485070L; + + /** This task's completer, or null if none */ + final CountedCompleter completer; + /** The number of pending tasks until completion */ + volatile int pending; + + /** + * Creates a new CountedCompleter with the given completer + * and initial pending count. + * + * @param completer this task's completer, or {@code null} if none + * @param initialPendingCount the initial pending count + */ + protected CountedCompleter(CountedCompleter completer, + int initialPendingCount) { + this.completer = completer; + this.pending = initialPendingCount; + } + + /** + * Creates a new CountedCompleter with the given completer + * and an initial pending count of zero. + * + * @param completer this task's completer, or {@code null} if none + */ + protected CountedCompleter(CountedCompleter completer) { + this.completer = completer; + } + + /** + * Creates a new CountedCompleter with no completer + * and an initial pending count of zero. + */ + protected CountedCompleter() { + this.completer = null; + } + + /** + * The main computation performed by this task. + */ + public abstract void compute(); + + /** + * Performs an action when method {@link #tryComplete} is invoked + * and the pending count is zero, or when the unconditional + * method {@link #complete} is invoked. By default, this method + * does nothing. You can distinguish cases by checking the + * identity of the given caller argument. If not equal to {@code + * this}, then it is typically a subtask that may contain results + * (and/or links to other results) to combine. + * + * @param caller the task invoking this method (which may + * be this task itself) + */ + public void onCompletion(CountedCompleter caller) { + } + + /** + * Performs an action when method {@link #completeExceptionally} + * is invoked or method {@link #compute} throws an exception, and + * this task has not otherwise already completed normally. On + * entry to this method, this task {@link + * ForkJoinTask#isCompletedAbnormally}. The return value of this + * method controls further propagation: If {@code true} and this + * task has a completer, then this completer is also completed + * exceptionally. The default implementation of this method does + * nothing except return {@code true}. + * + * @param ex the exception + * @param caller the task invoking this method (which may + * be this task itself) + * @return true if this exception should be propagated to this + * task's completer, if one exists + */ + public boolean onExceptionalCompletion(Throwable ex, CountedCompleter caller) { + return true; + } + + /** + * Returns the completer established in this task's constructor, + * or {@code null} if none. + * + * @return the completer + */ + public final CountedCompleter getCompleter() { + return completer; + } + + /** + * Returns the current pending count. + * + * @return the current pending count + */ + public final int getPendingCount() { + return pending; + } + + /** + * Sets the pending count to the given value. + * + * @param count the count + */ + public final void setPendingCount(int count) { + pending = count; + } + + /** + * Adds (atomically) the given value to the pending count. + * + * @param delta the value to add + */ + public final void addToPendingCount(int delta) { + int c; // note: can replace with intrinsic in jdk8 + do {} while (!U.compareAndSwapInt(this, PENDING, c = pending, c+delta)); + } + + /** + * Sets (atomically) the pending count to the given count only if + * it currently holds the given expected value. + * + * @param expected the expected value + * @param count the new value + * @return true if successful + */ + public final boolean compareAndSetPendingCount(int expected, int count) { + return U.compareAndSwapInt(this, PENDING, expected, count); + } + + /** + * If the pending count is nonzero, (atomically) decrements it. + * + * @return the initial (undecremented) pending count holding on entry + * to this method + */ + public final int decrementPendingCountUnlessZero() { + int c; + do {} while ((c = pending) != 0 && + !U.compareAndSwapInt(this, PENDING, c, c - 1)); + return c; + } + + /** + * Returns the root of the current computation; i.e., this + * task if it has no completer, else its completer's root. + * + * @return the root of the current computation + */ + public final CountedCompleter getRoot() { + CountedCompleter a = this, p; + while ((p = a.completer) != null) + a = p; + return a; + } + + /** + * If the pending count is nonzero, decrements the count; + * otherwise invokes {@link #onCompletion} and then similarly + * tries to complete this task's completer, if one exists, + * else marks this task as complete. + */ + public final void tryComplete() { + CountedCompleter a = this, s = a; + for (int c;;) { + if ((c = a.pending) == 0) { + a.onCompletion(s); + if ((a = (s = a).completer) == null) { + s.quietlyComplete(); + return; + } + } + else if (U.compareAndSwapInt(a, PENDING, c, c - 1)) + return; + } + } + + /** + * Equivalent to {@link #tryComplete} but does not invoke {@link + * #onCompletion} along the completion path: If the pending count + * is nonzero, decrements the count; otherwise, similarly tries to + * complete this task's completer, if one exists, else marks this + * task as complete. This method may be useful in cases where + * {@code onCompletion} should not, or need not, be invoked for + * each completer in a computation. + */ + public final void propagateCompletion() { + CountedCompleter a = this, s = a; + for (int c;;) { + if ((c = a.pending) == 0) { + if ((a = (s = a).completer) == null) { + s.quietlyComplete(); + return; + } + } + else if (U.compareAndSwapInt(a, PENDING, c, c - 1)) + return; + } + } + + /** + * Regardless of pending count, invokes {@link #onCompletion}, + * marks this task as complete and further triggers {@link + * #tryComplete} on this task's completer, if one exists. The + * given rawResult is used as an argument to {@link #setRawResult} + * before invoking {@link #onCompletion} or marking this task as + * complete; its value is meaningful only for classes overriding + * {@code setRawResult}. + * + *

    This method may be useful when forcing completion as soon as + * any one (versus all) of several subtask results are obtained. + * However, in the common (and recommended) case in which {@code + * setRawResult} is not overridden, this effect can be obtained + * more simply using {@code quietlyCompleteRoot();}. + * + * @param rawResult the raw result + */ + public void complete(T rawResult) { + CountedCompleter p; + setRawResult(rawResult); + onCompletion(this); + quietlyComplete(); + if ((p = completer) != null) + p.tryComplete(); + } + + + /** + * If this task's pending count is zero, returns this task; + * otherwise decrements its pending count and returns {@code + * null}. This method is designed to be used with {@link + * #nextComplete} in completion traversal loops. + * + * @return this task, if pending count was zero, else {@code null} + */ + public final CountedCompleter firstComplete() { + for (int c;;) { + if ((c = pending) == 0) + return this; + else if (U.compareAndSwapInt(this, PENDING, c, c - 1)) + return null; + } + } + + /** + * If this task does not have a completer, invokes {@link + * ForkJoinTask#quietlyComplete} and returns {@code null}. Or, if + * the completer's pending count is non-zero, decrements that + * pending count and returns {@code null}. Otherwise, returns the + * completer. This method can be used as part of a completion + * traversal loop for homogeneous task hierarchies: + * + *

     {@code
    +     * for (CountedCompleter c = firstComplete();
    +     *      c != null;
    +     *      c = c.nextComplete()) {
    +     *   // ... process c ...
    +     * }}
    + * + * @return the completer, or {@code null} if none + */ + public final CountedCompleter nextComplete() { + CountedCompleter p; + if ((p = completer) != null) + return p.firstComplete(); + else { + quietlyComplete(); + return null; + } + } + + /** + * Equivalent to {@code getRoot().quietlyComplete()}. + */ + public final void quietlyCompleteRoot() { + for (CountedCompleter a = this, p;;) { + if ((p = a.completer) == null) { + a.quietlyComplete(); + return; + } + a = p; + } + } + + /** + * Supports ForkJoinTask exception propagation. + */ + void internalPropagateException(Throwable ex) { + CountedCompleter a = this, s = a; + while (a.onExceptionalCompletion(ex, s) && + (a = (s = a).completer) != null && a.status >= 0) + a.recordExceptionalCompletion(ex); + } + + /** + * Implements execution conventions for CountedCompleters. + */ + protected final boolean exec() { + compute(); + return false; + } + + /** + * Returns the result of the computation. By default + * returns {@code null}, which is appropriate for {@code Void} + * actions, but in other cases should be overridden, almost + * always to return a field or function of a field that + * holds the result upon completion. + * + * @return the result of the computation + */ + public T getRawResult() { return null; } + + /** + * A method that result-bearing CountedCompleters may optionally + * use to help maintain result data. By default, does nothing. + * Overrides are not recommended. However, if this method is + * overridden to update existing objects or fields, then it must + * in general be defined to be thread-safe. + */ + protected void setRawResult(T t) { } + + // Unsafe mechanics + private static final sun.misc.Unsafe U; + private static final long PENDING; + static { + try { + U = sun.misc.Unsafe.getUnsafe(); + PENDING = U.objectFieldOffset + (CountedCompleter.class.getDeclaredField("pending")); + } catch (Exception e) { + throw new Error(e); + } + } +} diff --git a/luni/src/main/java/java/util/concurrent/CyclicBarrier.java b/luni/src/main/java/java/util/concurrent/CyclicBarrier.java index cf0b46e..e1a7bee 100644 --- a/luni/src/main/java/java/util/concurrent/CyclicBarrier.java +++ b/luni/src/main/java/java/util/concurrent/CyclicBarrier.java @@ -5,7 +5,8 @@ */ package java.util.concurrent; -import java.util.concurrent.locks.*; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.ReentrantLock; /** * A synchronization aid that allows a set of threads to all wait for @@ -15,7 +16,7 @@ import java.util.concurrent.locks.*; * cyclic because it can be re-used after the waiting threads * are released. * - *

    A CyclicBarrier supports an optional {@link Runnable} command + *

    A {@code CyclicBarrier} supports an optional {@link Runnable} command * that is run once per barrier point, after the last thread in the party * arrives, but before any threads are released. * This barrier action is useful @@ -68,8 +69,8 @@ import java.util.concurrent.locks.*; * barrier until all rows have been processed. When all rows are processed * the supplied {@link Runnable} barrier action is executed and merges the * rows. If the merger - * determines that a solution has been found then done() will return - * true and each worker will terminate. + * determines that a solution has been found then {@code done()} will return + * {@code true} and each worker will terminate. * *

    If the barrier action does not rely on the parties being suspended when * it is executed, then any of the threads in the party could execute that @@ -82,7 +83,7 @@ import java.util.concurrent.locks.*; * // log the completion of this iteration * }}

    * - *

    The CyclicBarrier uses an all-or-none breakage model + *

    The {@code CyclicBarrier} uses an all-or-none breakage model * for failed synchronization attempts: If a thread leaves a barrier * point prematurely because of interruption, failure, or timeout, all * other threads waiting at that barrier point will also leave @@ -109,7 +110,7 @@ public class CyclicBarrier { * is reset. There can be many generations associated with threads * using the barrier - due to the non-deterministic way the lock * may be allocated to waiting threads - but only one of these - * can be active at a time (the one to which count applies) + * can be active at a time (the one to which {@code count} applies) * and all the rest are either broken or tripped. * There need not be an active generation if there has been a break * but no subsequent reset. @@ -229,7 +230,7 @@ public class CyclicBarrier { } /** - * Creates a new CyclicBarrier that will trip when the + * Creates a new {@code CyclicBarrier} that will trip when the * given number of parties (threads) are waiting upon it, and which * will execute the given barrier action when the barrier is tripped, * performed by the last thread entering the barrier. @@ -248,7 +249,7 @@ public class CyclicBarrier { } /** - * Creates a new CyclicBarrier that will trip when the + * Creates a new {@code CyclicBarrier} that will trip when the * given number of parties (threads) are waiting upon it, and * does not perform a predefined action when the barrier is tripped. * @@ -271,7 +272,7 @@ public class CyclicBarrier { /** * Waits until all {@linkplain #getParties parties} have invoked - * await on this barrier. + * {@code await} on this barrier. * *

    If the current thread is not the last to arrive then it is * disabled for thread scheduling purposes and lies dormant until @@ -296,7 +297,7 @@ public class CyclicBarrier { * *

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

    If any thread is {@linkplain Thread#interrupt interrupted} while waiting, @@ -313,7 +314,7 @@ public class CyclicBarrier { * the broken state. * * @return the arrival index of the current thread, where index - * {@link #getParties()} - 1 indicates the first + * {@code getParties() - 1} indicates the first * to arrive and zero indicates the last to arrive * @throws InterruptedException if the current thread was interrupted * while waiting @@ -321,7 +322,7 @@ public class CyclicBarrier { * interrupted or timed out while the current thread was * waiting, or the barrier was reset, or the barrier was * broken when {@code await} was called, or the barrier - * action (if present) failed due an exception. + * action (if present) failed due to an exception */ public int await() throws InterruptedException, BrokenBarrierException { try { @@ -333,7 +334,7 @@ public class CyclicBarrier { /** * Waits until all {@linkplain #getParties parties} have invoked - * await on this barrier, or the specified waiting time elapses. + * {@code await} on this barrier, or the specified waiting time elapses. * *

    If the current thread is not the last to arrive then it is * disabled for thread scheduling purposes and lies dormant until @@ -363,7 +364,7 @@ public class CyclicBarrier { * *

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

    If any thread is {@linkplain Thread#interrupt interrupted} while @@ -382,7 +383,7 @@ public class CyclicBarrier { * @param timeout the time to wait for the barrier * @param unit the time unit of the timeout parameter * @return the arrival index of the current thread, where index - * {@link #getParties()} - 1 indicates the first + * {@code getParties() - 1} indicates the first * to arrive and zero indicates the last to arrive * @throws InterruptedException if the current thread was interrupted * while waiting @@ -391,7 +392,7 @@ public class CyclicBarrier { * interrupted or timed out while the current thread was * waiting, or the barrier was reset, or the barrier was broken * when {@code await} was called, or the barrier action (if - * present) failed due an exception + * present) failed due to an exception */ public int await(long timeout, TimeUnit unit) throws InterruptedException, diff --git a/luni/src/main/java/java/util/concurrent/DelayQueue.java b/luni/src/main/java/java/util/concurrent/DelayQueue.java index 52028cb..945249e 100644 --- a/luni/src/main/java/java/util/concurrent/DelayQueue.java +++ b/luni/src/main/java/java/util/concurrent/DelayQueue.java @@ -4,7 +4,6 @@ * http://creativecommons.org/publicdomain/zero/1.0/ */ - package java.util.concurrent; import static java.util.concurrent.TimeUnit.NANOSECONDS; import java.util.concurrent.locks.Condition; @@ -17,15 +16,15 @@ import java.util.*; /** * An unbounded {@linkplain BlockingQueue blocking queue} of - * Delayed elements, in which an element can only be taken + * {@code Delayed} elements, in which an element can only be taken * when its delay has expired. The head of the queue is that - * Delayed element whose delay expired furthest in the - * past. If no delay has expired there is no head and poll - * will return null. Expiration occurs when an element's - * getDelay(TimeUnit.NANOSECONDS) method returns a value less + * {@code Delayed} element whose delay expired furthest in the + * past. If no delay has expired there is no head and {@code poll} + * will return {@code null}. Expiration occurs when an element's + * {@code getDelay(TimeUnit.NANOSECONDS)} method returns a value less * than or equal to zero. Even though unexpired elements cannot be - * removed using take or poll, they are otherwise - * treated as normal elements. For example, the size method + * removed using {@code take} or {@code poll}, they are otherwise + * treated as normal elements. For example, the {@code size} method * returns the count of both expired and unexpired elements. * This queue does not permit null elements. * @@ -39,11 +38,10 @@ import java.util.*; * @author Doug Lea * @param the type of elements held in this collection */ - public class DelayQueue extends AbstractQueue implements BlockingQueue { - private transient final ReentrantLock lock = new ReentrantLock(); + private final transient ReentrantLock lock = new ReentrantLock(); private final PriorityQueue q = new PriorityQueue(); /** @@ -72,12 +70,12 @@ public class DelayQueue extends AbstractQueue private final Condition available = lock.newCondition(); /** - * Creates a new DelayQueue that is initially empty. + * Creates a new {@code DelayQueue} that is initially empty. */ public DelayQueue() {} /** - * Creates a DelayQueue initially containing the elements of the + * Creates a {@code DelayQueue} initially containing the elements of the * given collection of {@link Delayed} instances. * * @param c the collection of elements to initially contain @@ -92,7 +90,7 @@ public class DelayQueue extends AbstractQueue * Inserts the specified element into this delay queue. * * @param e the element to add - * @return true (as specified by {@link Collection#add}) + * @return {@code true} (as specified by {@link Collection#add}) * @throws NullPointerException if the specified element is null */ public boolean add(E e) { @@ -103,7 +101,7 @@ public class DelayQueue extends AbstractQueue * Inserts the specified element into this delay queue. * * @param e the element to add - * @return true + * @return {@code true} * @throws NullPointerException if the specified element is null */ public boolean offer(E e) { @@ -139,7 +137,7 @@ public class DelayQueue extends AbstractQueue * @param e the element to add * @param timeout This parameter is ignored as the method never blocks * @param unit This parameter is ignored as the method never blocks - * @return true + * @return {@code true} * @throws NullPointerException {@inheritDoc} */ public boolean offer(E e, long timeout, TimeUnit unit) { @@ -147,10 +145,10 @@ public class DelayQueue extends AbstractQueue } /** - * Retrieves and removes the head of this queue, or returns null + * Retrieves and removes the head of this queue, or returns {@code null} * if this queue has no elements with an expired delay. * - * @return the head of this queue, or null if this + * @return the head of this queue, or {@code null} if this * queue has no elements with an expired delay */ public E poll() { @@ -186,7 +184,8 @@ public class DelayQueue extends AbstractQueue long delay = first.getDelay(NANOSECONDS); if (delay <= 0) return q.poll(); - else if (leader != null) + first = null; // don't retain ref while waiting + if (leader != null) available.await(); else { Thread thisThread = Thread.currentThread(); @@ -212,7 +211,7 @@ public class DelayQueue extends AbstractQueue * until an element with an expired delay is available on this queue, * or the specified wait time expires. * - * @return the head of this queue, or null if the + * @return the head of this queue, or {@code null} if the * specified waiting time elapses before an element with * an expired delay becomes available * @throws InterruptedException {@inheritDoc} @@ -235,6 +234,7 @@ public class DelayQueue extends AbstractQueue return q.poll(); if (nanos <= 0) return null; + first = null; // don't retain ref while waiting if (nanos < delay || leader != null) nanos = available.awaitNanos(nanos); else { @@ -259,13 +259,13 @@ public class DelayQueue extends AbstractQueue /** * Retrieves, but does not remove, the head of this queue, or - * returns null if this queue is empty. Unlike - * poll, if no expired elements are available in the queue, + * returns {@code null} if this queue is empty. Unlike + * {@code poll}, if no expired elements are available in the queue, * this method returns the element that will expire next, * if one exists. * - * @return the head of this queue, or null if this - * queue is empty. + * @return the head of this queue, or {@code null} if this + * queue is empty */ public E peek() { final ReentrantLock lock = this.lock; @@ -288,7 +288,7 @@ public class DelayQueue extends AbstractQueue } /** - * Return first element only if it is expired. + * Returns first element only if it is expired. * Used only by drainTo. Call only when holding lock. */ private E peekExpired() { @@ -369,10 +369,10 @@ public class DelayQueue extends AbstractQueue } /** - * Always returns Integer.MAX_VALUE because - * a DelayQueue is not capacity constrained. + * Always returns {@code Integer.MAX_VALUE} because + * a {@code DelayQueue} is not capacity constrained. * - * @return Integer.MAX_VALUE + * @return {@code Integer.MAX_VALUE} */ public int remainingCapacity() { return Integer.MAX_VALUE; @@ -412,7 +412,7 @@ public class DelayQueue extends AbstractQueue *

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

    Like the {@link #toArray()} method, this method acts as bridge between * array-based and collection-based APIs. Further, this method allows @@ -420,12 +420,12 @@ public class DelayQueue extends AbstractQueue * under certain circumstances, be used to save allocation costs. * *

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

     {@code Delayed[] a = q.toArray(new Delayed[0]);}
    * - * Note that toArray(new Object[0]) is identical in function to - * toArray(). + * 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 diff --git a/luni/src/main/java/java/util/concurrent/Delayed.java b/luni/src/main/java/java/util/concurrent/Delayed.java index 39d927c..6a9527d 100644 --- a/luni/src/main/java/java/util/concurrent/Delayed.java +++ b/luni/src/main/java/java/util/concurrent/Delayed.java @@ -11,8 +11,8 @@ package java.util.concurrent; * acted upon after a given delay. * *

    An implementation of this interface must define a - * compareTo method that provides an ordering consistent with - * its getDelay method. + * {@code compareTo} method that provides an ordering consistent with + * its {@code getDelay} method. * * @since 1.5 * @author Doug Lea diff --git a/luni/src/main/java/java/util/concurrent/Exchanger.java b/luni/src/main/java/java/util/concurrent/Exchanger.java index 6069dce..01d5960 100644 --- a/luni/src/main/java/java/util/concurrent/Exchanger.java +++ b/luni/src/main/java/java/util/concurrent/Exchanger.java @@ -6,7 +6,8 @@ */ package java.util.concurrent; -import java.util.concurrent.atomic.*; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.locks.LockSupport; /** @@ -73,486 +74,427 @@ import java.util.concurrent.locks.LockSupport; * @param The type of objects that may be exchanged */ public class Exchanger { + /* - * Algorithm Description: + * Overview: The core algorithm is, for an exchange "slot", + * and a participant (caller) with an item: + * + * for (;;) { + * if (slot is empty) { // offer + * place item in a Node; + * if (can CAS slot from empty to node) { + * wait for release; + * return matching item in node; + * } + * } + * else if (can CAS slot from node to empty) { // release + * get the item in node; + * set matching item in node; + * release waiting thread; + * } + * // else retry on CAS failure + * } + * + * This is among the simplest forms of a "dual data structure" -- + * see Scott and Scherer's DISC 04 paper and + * http://www.cs.rochester.edu/research/synchronization/pseudocode/duals.html * - * The basic idea is to maintain a "slot", which is a reference to - * a Node containing both an Item to offer and a "hole" waiting to - * get filled in. If an incoming "occupying" thread sees that the - * slot is null, it CAS'es (compareAndSets) a Node there and waits - * for another to invoke exchange. That second "fulfilling" thread - * sees that the slot is non-null, and so CASes it back to null, - * also exchanging items by CASing the hole, plus waking up the - * occupying thread if it is blocked. In each case CAS'es may - * fail because a slot at first appears non-null but is null upon - * CAS, or vice-versa. So threads may need to retry these - * actions. + * This works great in principle. But in practice, like many + * algorithms centered on atomic updates to a single location, it + * scales horribly when there are more than a few participants + * using the same Exchanger. So the implementation instead uses a + * form of elimination arena, that spreads out this contention by + * arranging that some threads typically use different slots, + * while still ensuring that eventually, any two parties will be + * able to exchange items. That is, we cannot completely partition + * across threads, but instead give threads arena indices that + * will on average grow under contention and shrink under lack of + * contention. We approach this by defining the Nodes that we need + * anyway as ThreadLocals, and include in them per-thread index + * and related bookkeeping state. (We can safely reuse per-thread + * nodes rather than creating them fresh each time because slots + * alternate between pointing to a node vs null, so cannot + * encounter ABA problems. However, we do need some care in + * resetting them between uses.) * - * This simple approach works great when there are only a few - * threads using an Exchanger, but performance rapidly - * deteriorates due to CAS contention on the single slot when - * there are lots of threads using an exchanger. So instead we use - * an "arena"; basically a kind of hash table with a dynamically - * varying number of slots, any one of which can be used by - * threads performing an exchange. Incoming threads pick slots - * based on a hash of their Thread ids. If an incoming thread - * fails to CAS in its chosen slot, it picks an alternative slot - * instead. And similarly from there. If a thread successfully - * CASes into a slot but no other thread arrives, it tries - * another, heading toward the zero slot, which always exists even - * if the table shrinks. The particular mechanics controlling this - * are as follows: + * Implementing an effective arena requires allocating a bunch of + * space, so we only do so upon detecting contention (except on + * uniprocessors, where they wouldn't help, so aren't used). + * Otherwise, exchanges use the single-slot slotExchange method. + * On contention, not only must the slots be in different + * locations, but the locations must not encounter memory + * contention due to being on the same cache line (or more + * generally, the same coherence unit). Because, as of this + * writing, there is no way to determine cacheline size, we define + * a value that is enough for common platforms. Additionally, + * extra care elsewhere is taken to avoid other false/unintended + * sharing and to enhance locality, including adding padding to + * Nodes, embedding "bound" as an Exchanger field, and reworking + * some park/unpark mechanics compared to LockSupport versions. * - * Waiting: Slot zero is special in that it is the only slot that - * exists when there is no contention. A thread occupying slot - * zero will block if no thread fulfills it after a short spin. - * In other cases, occupying threads eventually give up and try - * another slot. Waiting threads spin for a while (a period that - * should be a little less than a typical context-switch time) - * before either blocking (if slot zero) or giving up (if other - * slots) and restarting. There is no reason for threads to block - * unless there are unlikely to be any other threads present. - * Occupants are mainly avoiding memory contention so sit there - * quietly polling for a shorter period than it would take to - * block and then unblock them. Non-slot-zero waits that elapse - * because of lack of other threads waste around one extra - * context-switch time per try, which is still on average much - * faster than alternative approaches. + * The arena starts out with only one used slot. We expand the + * effective arena size by tracking collisions; i.e., failed CASes + * while trying to exchange. By nature of the above algorithm, the + * only kinds of collision that reliably indicate contention are + * when two attempted releases collide -- one of two attempted + * offers can legitimately fail to CAS without indicating + * contention by more than one other thread. (Note: it is possible + * but not worthwhile to more precisely detect contention by + * reading slot values after CAS failures.) When a thread has + * collided at each slot within the current arena bound, it tries + * to expand the arena size by one. We track collisions within + * bounds by using a version (sequence) number on the "bound" + * field, and conservatively reset collision counts when a + * participant notices that bound has been updated (in either + * direction). * - * Sizing: Usually, using only a few slots suffices to reduce - * contention. Especially with small numbers of threads, using - * too many slots can lead to just as poor performance as using - * too few of them, and there's not much room for error. The - * variable "max" maintains the number of slots actually in - * use. It is increased when a thread sees too many CAS - * failures. (This is analogous to resizing a regular hash table - * based on a target load factor, except here, growth steps are - * just one-by-one rather than proportional.) Growth requires - * contention failures in each of three tried slots. Requiring - * multiple failures for expansion copes with the fact that some - * failed CASes are not due to contention but instead to simple - * races between two threads or thread pre-emptions occurring - * between reading and CASing. Also, very transient peak - * contention can be much higher than the average sustainable - * levels. An attempt to decrease the max limit is usually made - * when a non-slot-zero wait elapses without being fulfilled. - * Threads experiencing elapsed waits move closer to zero, so - * eventually find existing (or future) threads even if the table - * has been shrunk due to inactivity. The chosen mechanics and - * thresholds for growing and shrinking are intrinsically - * entangled with indexing and hashing inside the exchange code, - * and can't be nicely abstracted out. + * The effective arena size is reduced (when there is more than + * one slot) by giving up on waiting after a while and trying to + * decrement the arena size on expiration. The value of "a while" + * is an empirical matter. We implement by piggybacking on the + * use of spin->yield->block that is essential for reasonable + * waiting performance anyway -- in a busy exchanger, offers are + * usually almost immediately released, in which case context + * switching on multiprocessors is extremely slow/wasteful. Arena + * waits just omit the blocking part, and instead cancel. The spin + * count is empirically chosen to be a value that avoids blocking + * 99% of the time under maximum sustained exchange rates on a + * range of test machines. Spins and yields entail some limited + * randomness (using a cheap xorshift) to avoid regular patterns + * that can induce unproductive grow/shrink cycles. (Using a + * pseudorandom also helps regularize spin cycle duration by + * making branches unpredictable.) Also, during an offer, a + * waiter can "know" that it will be released when its slot has + * changed, but cannot yet proceed until match is set. In the + * mean time it cannot cancel the offer, so instead spins/yields. + * Note: It is possible to avoid this secondary check by changing + * the linearization point to be a CAS of the match field (as done + * in one case in the Scott & Scherer DISC paper), which also + * increases asynchrony a bit, at the expense of poorer collision + * detection and inability to always reuse per-thread nodes. So + * the current scheme is typically a better tradeoff. * - * Hashing: Each thread picks its initial slot to use in accord - * with a simple hashcode. The sequence is the same on each - * encounter by any given thread, but effectively random across - * threads. Using arenas encounters the classic cost vs quality - * tradeoffs of all hash tables. Here, we use a one-step FNV-1a - * hash code based on the current thread's Thread.getId(), along - * with a cheap approximation to a mod operation to select an - * index. The downside of optimizing index selection in this way - * is that the code is hardwired to use a maximum table size of - * 32. But this value more than suffices for known platforms and - * applications. + * On collisions, indices traverse the arena cyclically in reverse + * order, restarting at the maximum index (which will tend to be + * sparsest) when bounds change. (On expirations, indices instead + * are halved until reaching 0.) It is possible (and has been + * tried) to use randomized, prime-value-stepped, or double-hash + * style traversal instead of simple cyclic traversal to reduce + * bunching. But empirically, whatever benefits these may have + * don't overcome their added overhead: We are managing operations + * that occur very quickly unless there is sustained contention, + * so simpler/faster control policies work better than more + * accurate but slower ones. * - * Probing: On sensed contention of a selected slot, we probe - * sequentially through the table, analogously to linear probing - * after collision in a hash table. (We move circularly, in - * reverse order, to mesh best with table growth and shrinkage - * rules.) Except that to minimize the effects of false-alarms - * and cache thrashing, we try the first selected slot twice - * before moving. + * Because we use expiration for arena size control, we cannot + * throw TimeoutExceptions in the timed version of the public + * exchange method until the arena size has shrunken to zero (or + * the arena isn't enabled). This may delay response to timeout + * but is still within spec. * - * Padding: Even with contention management, slots are heavily - * contended, so use cache-padding to avoid poor memory - * performance. Because of this, slots are lazily constructed - * only when used, to avoid wasting this space unnecessarily. - * While isolation of locations is not much of an issue at first - * in an application, as time goes on and garbage-collectors - * perform compaction, slots are very likely to be moved adjacent - * to each other, which can cause much thrashing of cache lines on - * MPs unless padding is employed. + * Essentially all of the implementation is in methods + * slotExchange and arenaExchange. These have similar overall + * structure, but differ in too many details to combine. The + * slotExchange method uses the single Exchanger field "slot" + * rather than arena array elements. However, it still needs + * minimal collision detection to trigger arena construction. + * (The messiest part is making sure interrupt status and + * InterruptedExceptions come out right during transitions when + * both methods may be called. This is done by using null return + * as a sentinel to recheck interrupt status.) * - * This is an improvement of the algorithm described in the paper - * "A Scalable Elimination-based Exchange Channel" by William - * Scherer, Doug Lea, and Michael Scott in Proceedings of SCOOL05 - * workshop. Available at: http://hdl.handle.net/1802/2104 + * As is too common in this sort of code, methods are monolithic + * because most of the logic relies on reads of fields that are + * maintained as local variables so can't be nicely factored -- + * mainly, here, bulky spin->yield->block/cancel code), and + * heavily dependent on intrinsics (Unsafe) to use inlined + * embedded CAS and related memory access operations (that tend + * not to be as readily inlined by dynamic compilers when they are + * hidden behind other methods that would more nicely name and + * encapsulate the intended effects). This includes the use of + * putOrderedX to clear fields of the per-thread Nodes between + * uses. Note that field Node.item is not declared as volatile + * even though it is read by releasing threads, because they only + * do so after CAS operations that must precede access, and all + * uses by the owning thread are otherwise acceptably ordered by + * other operations. (Because the actual points of atomicity are + * slot CASes, it would also be legal for the write to Node.match + * in a release to be weaker than a full volatile write. However, + * this is not done because it could allow further postponement of + * the write, delaying progress.) */ - /** The number of CPUs, for sizing and spin control */ - private static final int NCPU = Runtime.getRuntime().availableProcessors(); - /** - * The capacity of the arena. Set to a value that provides more - * than enough space to handle contention. On small machines - * most slots won't be used, but it is still not wasted because - * the extra space provides some machine-level address padding - * to minimize interference with heavily CAS'ed Slot locations. - * And on very large machines, performance eventually becomes - * bounded by memory bandwidth, not numbers of threads/CPUs. - * This constant cannot be changed without also modifying - * indexing and hashing algorithms. + * The byte distance (as a shift value) between any two used slots + * in the arena. 1 << ASHIFT should be at least cacheline size. */ - private static final int CAPACITY = 32; + private static final int ASHIFT = 7; /** - * The value of "max" that will hold all threads without - * contention. When this value is less than CAPACITY, some - * otherwise wasted expansion can be avoided. + * The maximum supported arena index. The maximum allocatable + * arena size is MMASK + 1. Must be a power of two minus one, less + * than (1<<(31-ASHIFT)). The cap of 255 (0xff) more than suffices + * for the expected scaling limits of the main algorithms. */ - private static final int FULL = - Math.max(0, Math.min(CAPACITY, NCPU / 2) - 1); + private static final int MMASK = 0xff; /** - * The number of times to spin (doing nothing except polling a - * memory location) before blocking or giving up while waiting to - * be fulfilled. Should be zero on uniprocessors. On - * multiprocessors, this value should be large enough so that two - * threads exchanging items as fast as possible block only when - * one of them is stalled (due to GC or preemption), but not much - * longer, to avoid wasting CPU resources. Seen differently, this - * value is a little over half the number of cycles of an average - * context switch time on most systems. The value here is - * approximately the average of those across a range of tested - * systems. + * Unit for sequence/version bits of bound field. Each successful + * change to the bound also adds SEQ. */ - private static final int SPINS = (NCPU == 1) ? 0 : 2000; + private static final int SEQ = MMASK + 1; + + /** The number of CPUs, for sizing and spin control */ + private static final int NCPU = Runtime.getRuntime().availableProcessors(); /** - * The number of times to spin before blocking in timed waits. - * Timed waits spin more slowly because checking the time takes - * time. The best value relies mainly on the relative rate of - * System.nanoTime vs memory accesses. The value is empirically - * derived to work well across a variety of systems. + * The maximum slot index of the arena: The number of slots that + * can in principle hold all threads without contention, or at + * most the maximum indexable value. */ - private static final int TIMED_SPINS = SPINS / 20; + static final int FULL = (NCPU >= (MMASK << 1)) ? MMASK : NCPU >>> 1; /** - * Sentinel item representing cancellation of a wait due to - * interruption, timeout, or elapsed spin-waits. This value is - * placed in holes on cancellation, and used as a return value - * from waiting methods to indicate failure to set or get hole. + * The bound for spins while waiting for a match. The actual + * number of iterations will on average be about twice this value + * due to randomization. Note: Spinning is disabled when NCPU==1. */ - private static final Object CANCEL = new Object(); + private static final int SPINS = 1 << 10; /** * Value representing null arguments/returns from public - * methods. This disambiguates from internal requirement that - * holes start out as null to mean they are not yet set. + * methods. Needed because the API originally didn't disallow null + * arguments, which it should have. */ private static final Object NULL_ITEM = new Object(); /** - * Nodes hold partially exchanged data. This class - * opportunistically subclasses AtomicReference to represent the - * hole. So get() returns hole, and compareAndSet CAS'es value - * into hole. This class cannot be parameterized as "V" because - * of the use of non-V CANCEL sentinels. + * Sentinel value returned by internal exchange methods upon + * timeout, to avoid need for separate timed versions of these + * methods. */ - private static final class Node extends AtomicReference { - /** The element offered by the Thread creating this node. */ - public final Object item; - - /** The Thread waiting to be signalled; null until waiting. */ - public volatile Thread waiter; - - /** - * Creates node with given item and empty hole. - * @param item the item - */ - public Node(Object item) { - this.item = item; - } - } - - /** - * A Slot is an AtomicReference with heuristic padding to lessen - * cache effects of this heavily CAS'ed location. While the - * padding adds noticeable space, all slots are created only on - * demand, and there will be more than one of them only when it - * would improve throughput more than enough to outweigh using - * extra space. - */ - private static final class Slot extends AtomicReference { - // Improve likelihood of isolation on <= 128 byte cache lines. - // We used to target 64 byte cache lines, but some x86s (including - // i7 under some BIOSes) actually use 128 byte cache lines. - long q0, q1, q2, q3, q4, q5, q6, q7, q8, q9, qa, qb, qc, qd, qe; - } + private static final Object TIMED_OUT = new Object(); /** - * Slot array. Elements are lazily initialized when needed. - * Declared volatile to enable double-checked lazy construction. + * Nodes hold partially exchanged data, plus other per-thread + * bookkeeping. */ - private volatile Slot[] arena = new Slot[CAPACITY]; + static final class Node { + int index; // Arena index + int bound; // Last recorded value of Exchanger.bound + int collides; // Number of CAS failures at current bound + int hash; // Pseudo-random for spins + Object item; // This thread's current item + volatile Object match; // Item provided by releasing thread + volatile Thread parked; // Set to this thread when parked, else null - /** - * The maximum slot index being used. The value sometimes - * increases when a thread experiences too many CAS contentions, - * and sometimes decreases when a spin-wait elapses. Changes - * are performed only via compareAndSet, to avoid stale values - * when a thread happens to stall right before setting. - */ - private final AtomicInteger max = new AtomicInteger(); - - /** - * Main exchange function, handling the different policy variants. - * Uses Object, not "V" as argument and return value to simplify - * handling of sentinel values. Callers from public methods decode - * and cast accordingly. - * - * @param item the (non-null) item to exchange - * @param timed true if the wait is timed - * @param nanos if timed, the maximum wait time - * @return the other thread's item, or CANCEL if interrupted or timed out - */ - private Object doExchange(Object item, boolean timed, long nanos) { - Node me = new Node(item); // Create in case occupying - int index = hashIndex(); // Index of current slot - int fails = 0; // Number of CAS failures - - for (;;) { - Object y; // Contents of current slot - Slot slot = arena[index]; - if (slot == null) // Lazily initialize slots - createSlot(index); // Continue loop to reread - else if ((y = slot.get()) != null && // Try to fulfill - slot.compareAndSet(y, null)) { - Node you = (Node)y; // Transfer item - if (you.compareAndSet(null, item)) { - LockSupport.unpark(you.waiter); - return you.item; - } // Else cancelled; continue - } - else if (y == null && // Try to occupy - slot.compareAndSet(null, me)) { - if (index == 0) // Blocking wait for slot 0 - return timed ? - awaitNanos(me, slot, nanos) : - await(me, slot); - Object v = spinWait(me, slot); // Spin wait for non-0 - if (v != CANCEL) - return v; - me = new Node(item); // Throw away cancelled node - int m = max.get(); - if (m > (index >>>= 1)) // Decrease index - max.compareAndSet(m, m - 1); // Maybe shrink table - } - else if (++fails > 1) { // Allow 2 fails on 1st slot - int m = max.get(); - if (fails > 3 && m < FULL && max.compareAndSet(m, m + 1)) - index = m + 1; // Grow on 3rd failed slot - else if (--index < 0) - index = m; // Circularly traverse - } - } + // Padding to ameliorate unfortunate memory placements + Object p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pa, pb, pc, pd, pe, pf; + Object q0, q1, q2, q3, q4, q5, q6, q7, q8, q9, qa, qb, qc, qd, qe, qf; } - /** - * Returns a hash index for the current thread. Uses a one-step - * FNV-1a hash code (http://www.isthe.com/chongo/tech/comp/fnv/) - * based on the current thread's Thread.getId(). These hash codes - * have more uniform distribution properties with respect to small - * moduli (here 1-31) than do other simple hashing functions. - * - *

    To return an index between 0 and max, we use a cheap - * approximation to a mod operation, that also corrects for bias - * due to non-power-of-2 remaindering (see {@link - * java.util.Random#nextInt}). Bits of the hashcode are masked - * with "nbits", the ceiling power of two of table size (looked up - * in a table packed into three ints). If too large, this is - * retried after rotating the hash by nbits bits, while forcing new - * top bit to 0, which guarantees eventual termination (although - * with a non-random-bias). This requires an average of less than - * 2 tries for all table sizes, and has a maximum 2% difference - * from perfectly uniform slot probabilities when applied to all - * possible hash codes for sizes less than 32. - * - * @return a per-thread-random index, 0 <= index < max - */ - private final int hashIndex() { - long id = Thread.currentThread().getId(); - int hash = (((int)(id ^ (id >>> 32))) ^ 0x811c9dc5) * 0x01000193; - - int m = max.get(); - int nbits = (((0xfffffc00 >> m) & 4) | // Compute ceil(log2(m+1)) - ((0x000001f8 >>> m) & 2) | // The constants hold - ((0xffff00f2 >>> m) & 1)); // a lookup table - int index; - while ((index = hash & ((1 << nbits) - 1)) > m) // May retry on - hash = (hash >>> nbits) | (hash << (33 - nbits)); // non-power-2 m - return index; + /** The corresponding thread local class */ + static final class Participant extends ThreadLocal { + public Node initialValue() { return new Node(); } } /** - * Creates a new slot at given index. Called only when the slot - * appears to be null. Relies on double-check using builtin - * locks, since they rarely contend. This in turn relies on the - * arena array being declared volatile. - * - * @param index the index to add slot at + * Per-thread state */ - private void createSlot(int index) { - // Create slot outside of lock to narrow sync region - Slot newSlot = new Slot(); - Slot[] a = arena; - synchronized (a) { - if (a[index] == null) - a[index] = newSlot; - } - } + private final Participant participant; /** - * Tries to cancel a wait for the given node waiting in the given - * slot, if so, helping clear the node from its slot to avoid - * garbage retention. - * - * @param node the waiting node - * @param slot the slot it is waiting in - * @return true if successfully cancelled + * Elimination array; null until enabled (within slotExchange). + * Element accesses use emulation of volatile gets and CAS. */ - private static boolean tryCancel(Node node, Slot slot) { - if (!node.compareAndSet(null, CANCEL)) - return false; - if (slot.get() == node) // pre-check to minimize contention - slot.compareAndSet(node, null); - return true; - } - - // Three forms of waiting. Each just different enough not to merge - // code with others. + private volatile Node[] arena; /** - * Spin-waits for hole for a non-0 slot. Fails if spin elapses - * before hole filled. Does not check interrupt, relying on check - * in public exchange method to abort if interrupted on entry. - * - * @param node the waiting node - * @return on success, the hole; on failure, CANCEL + * Slot used until contention detected. */ - private static Object spinWait(Node node, Slot slot) { - int spins = SPINS; - for (;;) { - Object v = node.get(); - if (v != null) - return v; - else if (spins > 0) - --spins; - else - tryCancel(node, slot); - } - } + private volatile Node slot; /** - * Waits for (by spinning and/or blocking) and gets the hole - * filled in by another thread. Fails if interrupted before - * hole filled. - * - * When a node/thread is about to block, it sets its waiter field - * and then rechecks state at least one more time before actually - * parking, thus covering race vs fulfiller noticing that waiter - * is non-null so should be woken. - * - * Thread interruption status is checked only surrounding calls to - * park. The caller is assumed to have checked interrupt status - * on entry. - * - * @param node the waiting node - * @return on success, the hole; on failure, CANCEL + * The index of the largest valid arena position, OR'ed with SEQ + * number in high bits, incremented on each update. The initial + * update from 0 to SEQ is used to ensure that the arena array is + * constructed only once. */ - private static Object await(Node node, Slot slot) { - Thread w = Thread.currentThread(); - int spins = SPINS; - for (;;) { - Object v = node.get(); - if (v != null) - return v; - else if (spins > 0) // Spin-wait phase - --spins; - else if (node.waiter == null) // Set up to block next - node.waiter = w; - else if (w.isInterrupted()) // Abort on interrupt - tryCancel(node, slot); - else // Block - LockSupport.park(node); - } - } + private volatile int bound; /** - * Waits for (at index 0) and gets the hole filled in by another - * thread. Fails if timed out or interrupted before hole filled. - * Same basic logic as untimed version, but a bit messier. + * Exchange function when arenas enabled. See above for explanation. * - * @param node the waiting node - * @param nanos the wait time - * @return on success, the hole; on failure, CANCEL + * @param item the (non-null) item to exchange + * @param timed true if the wait is timed + * @param ns if timed, the maximum wait time, else 0L + * @return the other thread's item; or null if interrupted; or + * TIMED_OUT if timed and timed out */ - private Object awaitNanos(Node node, Slot slot, long nanos) { - int spins = TIMED_SPINS; - long lastTime = 0; - Thread w = null; - for (;;) { - Object v = node.get(); - if (v != null) + private final Object arenaExchange(Object item, boolean timed, long ns) { + Node[] a = arena; + Node p = participant.get(); + for (int i = p.index;;) { // access slot at i + int b, m, c; long j; // j is raw array offset + Node q = (Node)U.getObjectVolatile(a, j = (i << ASHIFT) + ABASE); + if (q != null && U.compareAndSwapObject(a, j, q, null)) { + Object v = q.item; // release + q.match = item; + Thread w = q.parked; + if (w != null) + U.unpark(w); return v; - long now = System.nanoTime(); - if (w == null) - w = Thread.currentThread(); - else - nanos -= now - lastTime; - lastTime = now; - if (nanos > 0) { - if (spins > 0) - --spins; - else if (node.waiter == null) - node.waiter = w; - else if (w.isInterrupted()) - tryCancel(node, slot); + } + else if (i <= (m = (b = bound) & MMASK) && q == null) { + p.item = item; // offer + if (U.compareAndSwapObject(a, j, null, p)) { + long end = (timed && m == 0) ? System.nanoTime() + ns : 0L; + Thread t = Thread.currentThread(); // wait + for (int h = p.hash, spins = SPINS;;) { + Object v = p.match; + if (v != null) { + U.putOrderedObject(p, MATCH, null); + p.item = null; // clear for next use + p.hash = h; + return v; + } + else if (spins > 0) { + h ^= h << 1; h ^= h >>> 3; h ^= h << 10; // xorshift + if (h == 0) // initialize hash + h = SPINS | (int)t.getId(); + else if (h < 0 && // approx 50% true + (--spins & ((SPINS >>> 1) - 1)) == 0) + Thread.yield(); // two yields per wait + } + else if (U.getObjectVolatile(a, j) != p) + spins = SPINS; // releaser hasn't set match yet + else if (!t.isInterrupted() && m == 0 && + (!timed || + (ns = end - System.nanoTime()) > 0L)) { + U.putObject(t, BLOCKER, this); // emulate LockSupport + p.parked = t; // minimize window + if (U.getObjectVolatile(a, j) == p) + U.park(false, ns); + p.parked = null; + U.putObject(t, BLOCKER, null); + } + else if (U.getObjectVolatile(a, j) == p && + U.compareAndSwapObject(a, j, p, null)) { + if (m != 0) // try to shrink + U.compareAndSwapInt(this, BOUND, b, b + SEQ - 1); + p.item = null; + p.hash = h; + i = p.index >>>= 1; // descend + if (Thread.interrupted()) + return null; + if (timed && m == 0 && ns <= 0L) + return TIMED_OUT; + break; // expired; restart + } + } + } else - LockSupport.parkNanos(node, nanos); + p.item = null; // clear offer + } + else { + if (p.bound != b) { // stale; reset + p.bound = b; + p.collides = 0; + i = (i != m || m == 0) ? m : m - 1; + } + else if ((c = p.collides) < m || m == FULL || + !U.compareAndSwapInt(this, BOUND, b, b + SEQ + 1)) { + p.collides = c + 1; + i = (i == 0) ? m : i - 1; // cyclically traverse + } + else + i = m + 1; // grow + p.index = i; } - else if (tryCancel(node, slot) && !w.isInterrupted()) - return scanOnTimeout(node); } } /** - * Sweeps through arena checking for any waiting threads. Called - * only upon return from timeout while waiting in slot 0. When a - * thread gives up on a timed wait, it is possible that a - * previously-entered thread is still waiting in some other - * slot. So we scan to check for any. This is almost always - * overkill, but decreases the likelihood of timeouts when there - * are other threads present to far less than that in lock-based - * exchangers in which earlier-arriving threads may still be - * waiting on entry locks. + * Exchange function used until arenas enabled. See above for explanation. * - * @param node the waiting node - * @return another thread's item, or CANCEL + * @param item the item to exchange + * @param timed true if the wait is timed + * @param ns if timed, the maximum wait time, else 0L + * @return the other thread's item; or null if either the arena + * was enabled or the thread was interrupted before completion; or + * TIMED_OUT if timed and timed out */ - private Object scanOnTimeout(Node node) { - Object y; - for (int j = arena.length - 1; j >= 0; --j) { - Slot slot = arena[j]; - if (slot != null) { - while ((y = slot.get()) != null) { - if (slot.compareAndSet(y, null)) { - Node you = (Node)y; - if (you.compareAndSet(null, node.item)) { - LockSupport.unpark(you.waiter); - return you.item; - } - } + private final Object slotExchange(Object item, boolean timed, long ns) { + Node p = participant.get(); + Thread t = Thread.currentThread(); + if (t.isInterrupted()) // preserve interrupt status so caller can recheck + return null; + + for (Node q;;) { + if ((q = slot) != null) { + if (U.compareAndSwapObject(this, SLOT, q, null)) { + Object v = q.item; + q.match = item; + Thread w = q.parked; + if (w != null) + U.unpark(w); + return v; } + // create arena on contention, but continue until slot null + if (NCPU > 1 && bound == 0 && + U.compareAndSwapInt(this, BOUND, 0, SEQ)) + arena = new Node[(FULL + 2) << ASHIFT]; + } + else if (arena != null) + return null; // caller must reroute to arenaExchange + else { + p.item = item; + if (U.compareAndSwapObject(this, SLOT, null, p)) + break; + p.item = null; } } - return CANCEL; + + // await release + int h = p.hash; + long end = timed ? System.nanoTime() + ns : 0L; + int spins = (NCPU > 1) ? SPINS : 1; + Object v; + while ((v = p.match) == null) { + if (spins > 0) { + h ^= h << 1; h ^= h >>> 3; h ^= h << 10; + if (h == 0) + h = SPINS | (int)t.getId(); + else if (h < 0 && (--spins & ((SPINS >>> 1) - 1)) == 0) + Thread.yield(); + } + else if (slot != p) + spins = SPINS; + else if (!t.isInterrupted() && arena == null && + (!timed || (ns = end - System.nanoTime()) > 0L)) { + U.putObject(t, BLOCKER, this); + p.parked = t; + if (slot == p) + U.park(false, ns); + p.parked = null; + U.putObject(t, BLOCKER, null); + } + else if (U.compareAndSwapObject(this, SLOT, p, null)) { + v = timed && ns <= 0L && !t.isInterrupted() ? TIMED_OUT : null; + break; + } + } + U.putOrderedObject(p, MATCH, null); + p.item = null; + p.hash = h; + return v; } /** * Creates a new Exchanger. */ public Exchanger() { + participant = new Participant(); } /** @@ -588,16 +530,16 @@ public class Exchanger { * @throws InterruptedException if the current thread was * interrupted while waiting */ + @SuppressWarnings("unchecked") public V exchange(V x) throws InterruptedException { - if (!Thread.interrupted()) { - Object v = doExchange((x == null) ? NULL_ITEM : x, false, 0); - if (v == NULL_ITEM) - return null; - if (v != CANCEL) - return (V)v; - Thread.interrupted(); // Clear interrupt status on IE throw - } - throw new InterruptedException(); + Object v; + Object item = (x == null) ? NULL_ITEM : x; // translate null args + if ((arena != null || + (v = slotExchange(item, false, 0L)) == null) && + ((Thread.interrupted() || // disambiguates null return + (v = arenaExchange(item, false, 0L)) == null))) + throw new InterruptedException(); + return (v == NULL_ITEM) ? null : (V)v; } /** @@ -635,25 +577,61 @@ public class Exchanger { * * @param x the object to exchange * @param timeout the maximum time to wait - * @param unit the time unit of the timeout argument + * @param unit the time unit of the {@code timeout} argument * @return the object provided by the other thread * @throws InterruptedException if the current thread was * interrupted while waiting * @throws TimeoutException if the specified waiting time elapses * before another thread enters the exchange */ + @SuppressWarnings("unchecked") public V exchange(V x, long timeout, TimeUnit unit) throws InterruptedException, TimeoutException { - if (!Thread.interrupted()) { - Object v = doExchange((x == null) ? NULL_ITEM : x, - true, unit.toNanos(timeout)); - if (v == NULL_ITEM) - return null; - if (v != CANCEL) - return (V)v; - if (!Thread.interrupted()) - throw new TimeoutException(); + Object v; + Object item = (x == null) ? NULL_ITEM : x; + long ns = unit.toNanos(timeout); + if ((arena != null || + (v = slotExchange(item, true, ns)) == null) && + ((Thread.interrupted() || + (v = arenaExchange(item, true, ns)) == null))) + throw new InterruptedException(); + if (v == TIMED_OUT) + throw new TimeoutException(); + return (v == NULL_ITEM) ? null : (V)v; + } + + // Unsafe mechanics + private static final sun.misc.Unsafe U; + private static final long BOUND; + private static final long SLOT; + private static final long MATCH; + private static final long BLOCKER; + private static final int ABASE; + static { + int s; + try { + U = sun.misc.Unsafe.getUnsafe(); + Class ek = Exchanger.class; + Class nk = Node.class; + Class ak = Node[].class; + Class tk = Thread.class; + BOUND = U.objectFieldOffset + (ek.getDeclaredField("bound")); + SLOT = U.objectFieldOffset + (ek.getDeclaredField("slot")); + MATCH = U.objectFieldOffset + (nk.getDeclaredField("match")); + BLOCKER = U.objectFieldOffset + (tk.getDeclaredField("parkBlocker")); + s = U.arrayIndexScale(ak); + // ABASE absorbs padding in front of element 0 + ABASE = U.arrayBaseOffset(ak) + (1 << ASHIFT); + + } catch (Exception e) { + throw new Error(e); } - throw new InterruptedException(); + if ((s & (s-1)) != 0 || s > (1 << ASHIFT)) + throw new Error("Unsupported array scale"); } + } diff --git a/luni/src/main/java/java/util/concurrent/ExecutionException.java b/luni/src/main/java/java/util/concurrent/ExecutionException.java index 9bb8dee..dbfbe65 100644 --- a/luni/src/main/java/java/util/concurrent/ExecutionException.java +++ b/luni/src/main/java/java/util/concurrent/ExecutionException.java @@ -19,14 +19,14 @@ public class ExecutionException extends Exception { private static final long serialVersionUID = 7830266012832686185L; /** - * Constructs an ExecutionException with no detail message. + * Constructs an {@code ExecutionException} with no detail message. * The cause is not initialized, and may subsequently be * initialized by a call to {@link #initCause(Throwable) initCause}. */ protected ExecutionException() { } /** - * Constructs an ExecutionException with the specified detail + * Constructs an {@code ExecutionException} with the specified detail * message. The cause is not initialized, and may subsequently be * initialized by a call to {@link #initCause(Throwable) initCause}. * @@ -37,7 +37,7 @@ public class ExecutionException extends Exception { } /** - * Constructs an ExecutionException with the specified detail + * Constructs an {@code ExecutionException} with the specified detail * message and cause. * * @param message the detail message @@ -49,10 +49,10 @@ public class ExecutionException extends Exception { } /** - * Constructs an ExecutionException with the specified cause. + * Constructs an {@code ExecutionException} with the specified cause. * The detail message is set to {@code (cause == null ? null : * cause.toString())} (which typically contains the class and - * detail message of cause). + * detail message of {@code cause}). * * @param cause the cause (which is saved for later retrieval by the * {@link #getCause()} method) diff --git a/luni/src/main/java/java/util/concurrent/Executor.java b/luni/src/main/java/java/util/concurrent/Executor.java index 831bf46..f55209a 100644 --- a/luni/src/main/java/java/util/concurrent/Executor.java +++ b/luni/src/main/java/java/util/concurrent/Executor.java @@ -10,9 +10,9 @@ package java.util.concurrent; * An object that executes submitted {@link Runnable} tasks. This * interface provides a way of decoupling task submission from the * mechanics of how each task will be run, including details of thread - * use, scheduling, etc. An Executor is normally used + * use, scheduling, etc. An {@code Executor} is normally used * instead of explicitly creating threads. For example, rather than - * invoking new Thread(new(RunnableTask())).start() for each + * invoking {@code new Thread(new(RunnableTask())).start()} for each * of a set of tasks, you might use: * *

    @@ -22,7 +22,7 @@ package java.util.concurrent;
      * ...
      * 
    * - * However, the Executor interface does not strictly + * However, the {@code Executor} interface does not strictly * require that execution be asynchronous. In the simplest case, an * executor can run the submitted task immediately in the caller's * thread: @@ -45,7 +45,7 @@ package java.util.concurrent; * } * }} * - * Many Executor implementations impose some sort of + * Many {@code Executor} implementations impose some sort of * limitation on how and when tasks are scheduled. The executor below * serializes the submission of tasks to a second executor, * illustrating a composite executor. @@ -82,7 +82,7 @@ package java.util.concurrent; * } * }} * - * The Executor implementations provided in this package + * The {@code Executor} implementations provided in this package * implement {@link ExecutorService}, which is a more extensive * interface. The {@link ThreadPoolExecutor} class provides an * extensible thread pool implementation. The {@link Executors} class @@ -101,11 +101,11 @@ public interface Executor { /** * Executes the given command at some time in the future. The command * may execute in a new thread, in a pooled thread, or in the calling - * thread, at the discretion of the Executor implementation. + * thread, at the discretion of the {@code Executor} implementation. * * @param command the runnable task * @throws RejectedExecutionException if this task cannot be - * accepted for execution. + * accepted for execution * @throws NullPointerException if command is null */ void execute(Runnable command); diff --git a/luni/src/main/java/java/util/concurrent/ExecutorService.java b/luni/src/main/java/java/util/concurrent/ExecutorService.java index a33ceec..4599f59 100644 --- a/luni/src/main/java/java/util/concurrent/ExecutorService.java +++ b/luni/src/main/java/java/util/concurrent/ExecutorService.java @@ -17,21 +17,21 @@ import java.util.Collection; * methods that can produce a {@link Future} for tracking progress of * one or more asynchronous tasks. * - *

    An ExecutorService can be shut down, which will cause + *

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

    Method submit extends base method {@link + *

    Method {@code submit} extends base method {@link * Executor#execute} by creating and returning a {@link Future} that * can be used to cancel execution and/or wait for completion. - * Methods invokeAny and invokeAll perform the most + * Methods {@code invokeAny} and {@code invokeAll} perform the most * commonly useful forms of bulk execution, executing a collection of * tasks and then waiting for at least one, or all, to * complete. (Class {@link ExecutorCompletionService} can be used to @@ -76,9 +76,9 @@ import java.util.Collection; * } * }} * - * The following method shuts down an ExecutorService in two phases, - * first by calling shutdown to reject incoming tasks, and then - * calling shutdownNow, if necessary, to cancel any lingering tasks: + * The following method shuts down an {@code ExecutorService} in two phases, + * first by calling {@code shutdown} to reject incoming tasks, and then + * calling {@code shutdownNow}, if necessary, to cancel any lingering tasks: * *

     {@code
      * void shutdownAndAwaitTermination(ExecutorService pool) {
    @@ -141,18 +141,18 @@ public interface ExecutorService extends Executor {
         List shutdownNow();
     
         /**
    -     * Returns true if this executor has been shut down.
    +     * Returns {@code true} if this executor has been shut down.
          *
    -     * @return true if this executor has been shut down
    +     * @return {@code true} if this executor has been shut down
          */
         boolean isShutdown();
     
         /**
    -     * Returns true if all tasks have completed following shut down.
    -     * Note that isTerminated is never true unless
    -     * either shutdown or shutdownNow was called first.
    +     * Returns {@code true} if all tasks have completed following shut down.
    +     * Note that {@code isTerminated} is never {@code true} unless
    +     * either {@code shutdown} or {@code shutdownNow} was called first.
          *
    -     * @return true if all tasks have completed following shut down
    +     * @return {@code true} if all tasks have completed following shut down
          */
         boolean isTerminated();
     
    @@ -163,26 +163,25 @@ public interface ExecutorService extends Executor {
          *
          * @param timeout the maximum time to wait
          * @param unit the time unit of the timeout argument
    -     * @return true if this executor terminated and
    -     *         false if the timeout elapsed before termination
    +     * @return {@code true} if this executor terminated and
    +     *         {@code false} if the timeout elapsed before termination
          * @throws InterruptedException if interrupted while waiting
          */
         boolean awaitTermination(long timeout, TimeUnit unit)
             throws InterruptedException;
     
    -
         /**
          * Submits a value-returning task for execution and returns a
          * Future representing the pending results of the task. The
    -     * Future's get method will return the task's result upon
    +     * Future's {@code get} method will return the task's result upon
          * successful completion.
          *
          * 

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

    Note: The {@link Executors} class includes a set of methods + *

    Note: The {@link Executors} class includes a set of methods * that can convert some other common closure-like objects, * for example, {@link java.security.PrivilegedAction} to * {@link Callable} form so they can be submitted. @@ -197,7 +196,7 @@ public interface ExecutorService extends Executor { /** * Submits a Runnable task for execution and returns a Future - * representing that task. The Future's get method will + * representing that task. The Future's {@code get} method will * return the given result upon successful completion. * * @param task the task to submit @@ -211,8 +210,8 @@ public interface ExecutorService extends Executor { /** * Submits a Runnable task for execution and returns a Future - * representing that task. The Future's get method will - * return null upon successful completion. + * representing that task. The Future's {@code get} method will + * return {@code null} upon successful completion. * * @param task the task to submit * @return a Future representing pending completion of the task @@ -225,7 +224,7 @@ public interface ExecutorService extends Executor { /** * Executes the given tasks, returning a list of Futures holding * their status and results when all complete. - * {@link Future#isDone} is true for each + * {@link Future#isDone} is {@code true} for each * element of the returned list. * Note that a completed task could have * terminated either normally or by throwing an exception. @@ -233,16 +232,15 @@ public interface ExecutorService extends Executor { * collection is modified while this operation is in progress. * * @param tasks the collection of tasks - * @return A list of Futures representing the tasks, in the same + * @return a list of Futures representing the tasks, in the same * sequential order as produced by the iterator for the - * given task list, each of which has completed. + * given task list, each of which has completed * @throws InterruptedException if interrupted while waiting, in - * which case unfinished tasks are cancelled. - * @throws NullPointerException if tasks or any of its elements are null + * which case unfinished tasks are cancelled + * @throws NullPointerException if tasks or any of its elements are {@code null} * @throws RejectedExecutionException if any task cannot be * scheduled for execution */ - List> invokeAll(Collection> tasks) throws InterruptedException; @@ -250,7 +248,7 @@ public interface ExecutorService extends Executor { * Executes the given tasks, returning a list of Futures holding * their status and results * when all complete or the timeout expires, whichever happens first. - * {@link Future#isDone} is true for each + * {@link Future#isDone} is {@code true} for each * element of the returned list. * Upon return, tasks that have not completed are cancelled. * Note that a completed task could have @@ -269,7 +267,7 @@ public interface ExecutorService extends Executor { * @throws InterruptedException if interrupted while waiting, in * which case unfinished tasks are cancelled * @throws NullPointerException if tasks, any of its elements, or - * unit are null + * unit are {@code null} * @throws RejectedExecutionException if any task cannot be scheduled * for execution */ @@ -289,7 +287,7 @@ public interface ExecutorService extends Executor { * @return the result returned by one of the tasks * @throws InterruptedException if interrupted while waiting * @throws NullPointerException if tasks or any element task - * subject to execution is null + * subject to execution is {@code null} * @throws IllegalArgumentException if tasks is empty * @throws ExecutionException if no task successfully completes * @throws RejectedExecutionException if tasks cannot be scheduled @@ -310,10 +308,10 @@ public interface ExecutorService extends Executor { * @param tasks the collection of tasks * @param timeout the maximum time to wait * @param unit the time unit of the timeout argument - * @return the result returned by one of the tasks. + * @return the result returned by one of the tasks * @throws InterruptedException if interrupted while waiting * @throws NullPointerException if tasks, or unit, or any element - * task subject to execution is null + * task subject to execution is {@code null} * @throws TimeoutException if the given timeout elapses before * any task successfully completes * @throws ExecutionException if no task successfully completes diff --git a/luni/src/main/java/java/util/concurrent/Executors.java b/luni/src/main/java/java/util/concurrent/Executors.java index b4f03ba..53c68fc 100644 --- a/luni/src/main/java/java/util/concurrent/Executors.java +++ b/luni/src/main/java/java/util/concurrent/Executors.java @@ -34,7 +34,7 @@ import java.security.PrivilegedActionException; * that sets newly created threads to a known state. *

  • Methods that create and return a {@link Callable} * out of other closure-like forms, so they can be used - * in execution methods requiring Callable. + * in execution methods requiring {@code Callable}. * * * @since 1.5 @@ -45,7 +45,7 @@ public class Executors { /** * Creates a thread pool that reuses a fixed number of threads * operating off a shared unbounded queue. At any point, at most - * nThreads threads will be active processing tasks. + * {@code nThreads} threads will be active processing tasks. * If additional tasks are submitted when all threads are active, * they will wait in the queue until a thread is available. * If any thread terminates due to a failure during execution @@ -64,10 +64,48 @@ public class Executors { } /** + * Creates a thread pool that maintains enough threads to support + * the given parallelism level, and may use multiple queues to + * reduce contention. The parallelism level corresponds to the + * maximum number of threads actively engaged in, or available to + * engage in, task processing. The actual number of threads may + * grow and shrink dynamically. A work-stealing pool makes no + * guarantees about the order in which submitted tasks are + * executed. + * + * @param parallelism the targeted parallelism level + * @return the newly created thread pool + * @throws IllegalArgumentException if {@code parallelism <= 0} + * @since 1.8 + * @hide + */ + public static ExecutorService newWorkStealingPool(int parallelism) { + return new ForkJoinPool + (parallelism, + ForkJoinPool.defaultForkJoinWorkerThreadFactory, + null, true); + } + + /** + * Creates a work-stealing thread pool using all + * {@link Runtime#availableProcessors available processors} + * as its target parallelism level. + * @return the newly created thread pool + * @since 1.8 + * @hide + */ + public static ExecutorService newWorkStealingPool() { + return new ForkJoinPool + (Runtime.getRuntime().availableProcessors(), + ForkJoinPool.defaultForkJoinWorkerThreadFactory, + null, true); + } + + /** * Creates a thread pool that reuses a fixed number of threads * operating off a shared unbounded queue, using the provided * ThreadFactory to create new threads when needed. At any point, - * at most nThreads threads will be active processing + * at most {@code nThreads} threads will be active processing * tasks. If additional tasks are submitted when all threads are * active, they will wait in the queue until a thread is * available. If any thread terminates due to a failure during @@ -97,7 +135,7 @@ public class Executors { * subsequent tasks.) Tasks are guaranteed to execute * sequentially, and no more than one task will be active at any * given time. Unlike the otherwise equivalent - * newFixedThreadPool(1) the returned executor is + * {@code newFixedThreadPool(1)} the returned executor is * guaranteed not to be reconfigurable to use additional threads. * * @return the newly created single-threaded Executor @@ -113,7 +151,7 @@ public class Executors { * Creates an Executor that uses a single worker thread operating * off an unbounded queue, and uses the provided ThreadFactory to * create a new thread when needed. Unlike the otherwise - * equivalent newFixedThreadPool(1, threadFactory) the + * equivalent {@code newFixedThreadPool(1, threadFactory)} the * returned executor is guaranteed not to be reconfigurable to use * additional threads. * @@ -136,7 +174,7 @@ public class Executors { * will reuse previously constructed threads when they are * available. These pools will typically improve the performance * of programs that execute many short-lived asynchronous tasks. - * Calls to execute will reuse previously constructed + * Calls to {@code execute} will reuse previously constructed * threads if available. If no existing thread is available, a new * thread will be created and added to the pool. Threads that have * not been used for sixty seconds are terminated and removed from @@ -178,7 +216,7 @@ public class Executors { * subsequent tasks.) Tasks are guaranteed to execute * sequentially, and no more than one task will be active at any * given time. Unlike the otherwise equivalent - * newScheduledThreadPool(1) the returned executor is + * {@code newScheduledThreadPool(1)} the returned executor is * guaranteed not to be reconfigurable to use additional threads. * @return the newly created scheduled executor */ @@ -195,7 +233,7 @@ public class Executors { * place if needed to execute subsequent tasks.) Tasks are * guaranteed to execute sequentially, and no more than one task * will be active at any given time. Unlike the otherwise - * equivalent newScheduledThreadPool(1, threadFactory) + * equivalent {@code newScheduledThreadPool(1, threadFactory)} * the returned executor is guaranteed not to be reconfigurable to * use additional threads. * @param threadFactory the factory to use when creating new @@ -212,7 +250,7 @@ public class Executors { * Creates a thread pool that can schedule commands to run after a * given delay, or to execute periodically. * @param corePoolSize the number of threads to keep in the pool, - * even if they are idle. + * even if they are idle * @return a newly created scheduled thread pool * @throws IllegalArgumentException if {@code corePoolSize < 0} */ @@ -224,9 +262,9 @@ public class Executors { * Creates a thread pool that can schedule commands to run after a * given delay, or to execute periodically. * @param corePoolSize the number of threads to keep in the pool, - * even if they are idle. + * even if they are idle * @param threadFactory the factory to use when the executor - * creates a new thread. + * creates a new thread * @return a newly created scheduled thread pool * @throws IllegalArgumentException if {@code corePoolSize < 0} * @throws NullPointerException if threadFactory is null @@ -236,7 +274,6 @@ public class Executors { return new ScheduledThreadPoolExecutor(corePoolSize, threadFactory); } - /** * Returns an object that delegates all defined {@link * ExecutorService} methods to the given executor, but not any @@ -244,7 +281,7 @@ public class Executors { * casts. This provides a way to safely "freeze" configuration and * disallow tuning of a given concrete implementation. * @param executor the underlying implementation - * @return an ExecutorService instance + * @return an {@code ExecutorService} instance * @throws NullPointerException if executor null */ public static ExecutorService unconfigurableExecutorService(ExecutorService executor) { @@ -260,7 +297,7 @@ public class Executors { * casts. This provides a way to safely "freeze" configuration and * disallow tuning of a given concrete implementation. * @param executor the underlying implementation - * @return a ScheduledExecutorService instance + * @return a {@code ScheduledExecutorService} instance * @throws NullPointerException if executor null */ public static ScheduledExecutorService unconfigurableScheduledExecutorService(ScheduledExecutorService executor) { @@ -274,7 +311,7 @@ public class Executors { * This factory creates all new threads used by an Executor in the * same {@link ThreadGroup}. Each new * thread is created as a non-daemon thread with priority set to - * the smaller of Thread.NORM_PRIORITY and the maximum + * the smaller of {@code Thread.NORM_PRIORITY} and the maximum * priority permitted in the thread group. New threads have names * accessible via {@link Thread#getName} of * pool-N-thread-M, where N is the sequence @@ -297,7 +334,7 @@ public class Executors { * Returns a {@link Callable} object that, when * called, runs the given task and returns the given result. This * can be useful when applying methods requiring a - * Callable to an otherwise resultless action. + * {@code Callable} to an otherwise resultless action. * @param task the task to run * @param result the result to return * @return a callable object @@ -311,7 +348,7 @@ public class Executors { /** * Returns a {@link Callable} object that, when - * called, runs the given task and returns null. + * called, runs the given task and returns {@code null}. * @param task the task to run * @return a callable object * @throws NullPointerException if task null @@ -361,12 +398,7 @@ public class Executors { } /** - * Returns a {@link Callable} object that will, when - * called, execute the given callable under the current - * with the current context class loader as the context class loader. - * - * @return a callable object - * @throws NullPointerException if callable null + * Legacy security code; do not use. */ public static Callable privilegedCallableUsingCurrentClassLoader(Callable callable) { if (callable == null) @@ -451,18 +483,17 @@ public class Executors { return AccessController.doPrivileged( new PrivilegedExceptionAction() { public T run() throws Exception { - ClassLoader savedcl = null; Thread t = Thread.currentThread(); - try { - ClassLoader cl = t.getContextClassLoader(); - if (ccl != cl) { - t.setContextClassLoader(ccl); - savedcl = cl; - } + ClassLoader cl = t.getContextClassLoader(); + if (ccl == cl) { return task.call(); - } finally { - if (savedcl != null) - t.setContextClassLoader(savedcl); + } else { + t.setContextClassLoader(ccl); + try { + return task.call(); + } finally { + t.setContextClassLoader(cl); + } } } }, acc); @@ -609,21 +640,20 @@ public class Executors { super(executor); e = executor; } - public ScheduledFuture schedule(Runnable command, long delay, TimeUnit unit) { + public ScheduledFuture schedule(Runnable command, long delay, TimeUnit unit) { return e.schedule(command, delay, unit); } public ScheduledFuture schedule(Callable callable, long delay, TimeUnit unit) { return e.schedule(callable, delay, unit); } - public ScheduledFuture scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) { + public ScheduledFuture scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) { return e.scheduleAtFixedRate(command, initialDelay, period, unit); } - public ScheduledFuture scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit) { + public ScheduledFuture scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit) { return e.scheduleWithFixedDelay(command, initialDelay, delay, unit); } } - /** Cannot instantiate. */ private Executors() {} } diff --git a/luni/src/main/java/java/util/concurrent/ForkJoinPool.java b/luni/src/main/java/java/util/concurrent/ForkJoinPool.java index ee15ac8..87ffff3 100644 --- a/luni/src/main/java/java/util/concurrent/ForkJoinPool.java +++ b/luni/src/main/java/java/util/concurrent/ForkJoinPool.java @@ -11,7 +11,6 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; -import java.util.Random; import java.util.concurrent.AbstractExecutorService; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; @@ -19,15 +18,6 @@ import java.util.concurrent.Future; import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.RunnableFuture; import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.locks.LockSupport; -import java.util.concurrent.locks.ReentrantLock; -import java.util.concurrent.locks.Condition; -import libcore.util.SneakyThrow; - -// BEGIN android-note -// removed security manager docs -// END android-note /** * An {@link ExecutorService} for running {@link ForkJoinTask}s. @@ -38,21 +28,31 @@ import libcore.util.SneakyThrow; *

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

    A static {@link #commonPool()} is available and appropriate for + * most applications. The common pool is used by any ForkJoinTask that + * is not explicitly submitted to a specified pool. Using the common + * pool normally reduces resource usage (its threads are slowly + * reclaimed during periods of non-use, and reinstated upon subsequent + * use). * - *

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

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

    In addition to execution and lifecycle control methods, this @@ -62,16 +62,17 @@ import libcore.util.SneakyThrow; * {@link #toString} returns indications of pool state in a * convenient form for informal monitoring. * - *

    As is the case with other ExecutorServices, there are three - * main task execution methods summarized in the following - * table. These are designed to be used by clients not already engaged - * in fork/join computations in the current pool. The main forms of - * these methods accept instances of {@code ForkJoinTask}, but - * overloaded forms also allow mixed execution of plain {@code + *

    As is the case with other ExecutorServices, there are three + * main task execution methods summarized in the following table. + * These are designed to be used primarily by clients not already + * engaged in fork/join computations in the current pool. The main + * forms of these methods accept instances of {@code ForkJoinTask}, + * but overloaded forms also allow mixed execution of plain {@code * Runnable}- or {@code Callable}- based activities as well. However, - * tasks that are already executing in a pool should normally - * NOT use these pool execution methods, but instead use the - * within-computation forms listed in the table. + * tasks that are already executing in a pool should normally instead + * use the within-computation forms listed in the table unless using + * async event-style tasks that are not usually joined, in which case + * there is little difference among choice of methods. * * * @@ -96,22 +97,16 @@ import libcore.util.SneakyThrow; * *
    * - *

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

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

    The common pool is by default constructed with default + * parameters, but these may be controlled by setting three {@link + * System#getProperty system properties} with prefix {@code + * java.util.concurrent.ForkJoinPool.common}: {@code parallelism} -- + * an integer greater than zero, {@code threadFactory} -- the class + * name of a {@link ForkJoinWorkerThreadFactory}, and {@code + * exceptionHandler} -- the class name of a {@link + * java.lang.Thread.UncaughtExceptionHandler + * Thread.UncaughtExceptionHandler}. Upon any error in establishing + * these settings, default parameters are used. * *

    Implementation notes: This implementation restricts the * maximum number of running threads to 32767. Attempts to create @@ -131,213 +126,387 @@ public class ForkJoinPool extends AbstractExecutorService { /* * Implementation Overview * - * This class provides the central bookkeeping and control for a - * set of worker threads: Submissions from non-FJ threads enter - * into a submission queue. Workers take these tasks and typically - * split them into subtasks that may be stolen by other workers. - * Preference rules give first priority to processing tasks from - * their own queues (LIFO or FIFO, depending on mode), then to - * randomized FIFO steals of tasks in other worker queues, and - * lastly to new submissions. + * This class and its nested classes provide the main + * functionality and control for a set of worker threads: + * Submissions from non-FJ threads enter into submission queues. + * Workers take these tasks and typically split them into subtasks + * that may be stolen by other workers. Preference rules give + * first priority to processing tasks from their own queues (LIFO + * or FIFO, depending on mode), then to randomized FIFO steals of + * tasks in other queues. + * + * WorkQueues + * ========== + * + * Most operations occur within work-stealing queues (in nested + * class WorkQueue). These are special forms of Deques that + * support only three of the four possible end-operations -- push, + * pop, and poll (aka steal), under the further constraints that + * push and pop are called only from the owning thread (or, as + * extended here, under a lock), while poll may be called from + * other threads. (If you are unfamiliar with them, you probably + * want to read Herlihy and Shavit's book "The Art of + * Multiprocessor programming", chapter 16 describing these in + * more detail before proceeding.) The main work-stealing queue + * design is roughly similar to those in the papers "Dynamic + * Circular Work-Stealing Deque" by Chase and Lev, SPAA 2005 + * (http://research.sun.com/scalable/pubs/index.html) and + * "Idempotent work stealing" by Michael, Saraswat, and Vechev, + * PPoPP 2009 (http://portal.acm.org/citation.cfm?id=1504186). + * The main differences ultimately stem from GC requirements that + * we null out taken slots as soon as we can, to maintain as small + * a footprint as possible even in programs generating huge + * numbers of tasks. To accomplish this, we shift the CAS + * arbitrating pop vs poll (steal) from being on the indices + * ("base" and "top") to the slots themselves. So, both a + * successful pop and poll mainly entail a CAS of a slot from + * non-null to null. Because we rely on CASes of references, we + * do not need tag bits on base or top. They are simple ints as + * used in any circular array-based queue (see for example + * ArrayDeque). Updates to the indices must still be ordered in a + * way that guarantees that top == base means the queue is empty, + * but otherwise may err on the side of possibly making the queue + * appear nonempty when a push, pop, or poll have not fully + * committed. Note that this means that the poll operation, + * considered individually, is not wait-free. One thief cannot + * successfully continue until another in-progress one (or, if + * previously empty, a push) completes. However, in the + * aggregate, we ensure at least probabilistic non-blockingness. + * If an attempted steal fails, a thief always chooses a different + * random victim target to try next. So, in order for one thief to + * progress, it suffices for any in-progress poll or new push on + * any empty queue to complete. (This is why we normally use + * method pollAt and its variants that try once at the apparent + * base index, else consider alternative actions, rather than + * method poll.) + * + * This approach also enables support of a user mode in which local + * task processing is in FIFO, not LIFO order, simply by using + * poll rather than pop. This can be useful in message-passing + * frameworks in which tasks are never joined. However neither + * mode considers affinities, loads, cache localities, etc, so + * rarely provide the best possible performance on a given + * machine, but portably provide good throughput by averaging over + * these factors. (Further, even if we did try to use such + * information, we do not usually have a basis for exploiting it. + * For example, some sets of tasks profit from cache affinities, + * but others are harmed by cache pollution effects.) + * + * WorkQueues are also used in a similar way for tasks submitted + * to the pool. We cannot mix these tasks in the same queues used + * for work-stealing (this would contaminate lifo/fifo + * processing). Instead, we randomly associate submission queues + * with submitting threads, using a form of hashing. The + * ThreadLocal Submitter class contains a value initially used as + * a hash code for choosing existing queues, but may be randomly + * repositioned upon contention with other submitters. In + * essence, submitters act like workers except that they are + * restricted to executing local tasks that they submitted (or in + * the case of CountedCompleters, others with the same root task). + * However, because most shared/external queue operations are more + * expensive than internal, and because, at steady state, external + * submitters will compete for CPU with workers, ForkJoinTask.join + * and related methods disable them from repeatedly helping to + * process tasks if all workers are active. Insertion of tasks in + * shared mode requires a lock (mainly to protect in the case of + * resizing) but we use only a simple spinlock (using bits in + * field qlock), because submitters encountering a busy queue move + * on to try or create other queues -- they block only when + * creating and registering new queues. + * + * Management + * ========== * * The main throughput advantages of work-stealing stem from * decentralized control -- workers mostly take tasks from * themselves or each other. We cannot negate this in the * implementation of other management responsibilities. The main * tactic for avoiding bottlenecks is packing nearly all - * essentially atomic control state into a single 64bit volatile - * variable ("ctl"). This variable is read on the order of 10-100 - * times as often as it is modified (always via CAS). (There is - * some additional control state, for example variable "shutdown" - * for which we can cope with uncoordinated updates.) This - * streamlines synchronization and control at the expense of messy - * constructions needed to repack status bits upon updates. - * Updates tend not to contend with each other except during - * bursts while submitted tasks begin or end. In some cases when - * they do contend, threads can instead do something else - * (usually, scan for tasks) until contention subsides. - * - * To enable packing, we restrict maximum parallelism to (1<<15)-1 - * (which is far in excess of normal operating range) to allow - * ids, counts, and their negations (used for thresholding) to fit - * into 16bit fields. - * - * Recording Workers. Workers are recorded in the "workers" array - * that is created upon pool construction and expanded if (rarely) - * necessary. This is an array as opposed to some other data - * structure to support index-based random steals by workers. - * Updates to the array recording new workers and unrecording - * terminated ones are protected from each other by a seqLock - * (scanGuard) but the array is otherwise concurrently readable, - * and accessed directly by workers. To simplify index-based - * operations, the array size is always a power of two, and all - * readers must tolerate null slots. To avoid flailing during - * start-up, the array is presized to hold twice #parallelism - * workers (which is unlikely to need further resizing during - * execution). But to avoid dealing with so many null slots, - * variable scanGuard includes a mask for the nearest power of two - * that contains all current workers. All worker thread creation - * is on-demand, triggered by task submissions, replacement of - * terminated workers, and/or compensation for blocked - * workers. However, all other support code is set up to work with - * other policies. To ensure that we do not hold on to worker - * references that would prevent GC, ALL accesses to workers are - * via indices into the workers array (which is one source of some - * of the messy code constructions here). In essence, the workers - * array serves as a weak reference mechanism. Thus for example - * the wait queue field of ctl stores worker indices, not worker - * references. Access to the workers in associated methods (for - * example signalWork) must both index-check and null-check the - * IDs. All such accesses ignore bad IDs by returning out early - * from what they are doing, since this can only be associated - * with termination, in which case it is OK to give up. - * - * All uses of the workers array, as well as queue arrays, check - * that the array is non-null (even if previously non-null). This - * allows nulling during termination, which is currently not - * necessary, but remains an option for resource-revocation-based - * shutdown schemes. - * - * Wait Queuing. Unlike HPC work-stealing frameworks, we cannot + * essentially atomic control state into two volatile variables + * that are by far most often read (not written) as status and + * consistency checks. + * + * Field "ctl" contains 64 bits holding all the information needed + * to atomically decide to add, inactivate, enqueue (on an event + * queue), dequeue, and/or re-activate workers. To enable this + * packing, we restrict maximum parallelism to (1<<15)-1 (which is + * far in excess of normal operating range) to allow ids, counts, + * and their negations (used for thresholding) to fit into 16bit + * fields. + * + * Field "plock" is a form of sequence lock with a saturating + * shutdown bit (similarly for per-queue "qlocks"), mainly + * protecting updates to the workQueues array, as well as to + * enable shutdown. When used as a lock, it is normally only very + * briefly held, so is nearly always available after at most a + * brief spin, but we use a monitor-based backup strategy to + * block when needed. + * + * Recording WorkQueues. WorkQueues are recorded in the + * "workQueues" array that is created upon first use and expanded + * if necessary. Updates to the array while recording new workers + * and unrecording terminated ones are protected from each other + * by a lock but the array is otherwise concurrently readable, and + * accessed directly. To simplify index-based operations, the + * array size is always a power of two, and all readers must + * tolerate null slots. Worker queues are at odd indices. Shared + * (submission) queues are at even indices, up to a maximum of 64 + * slots, to limit growth even if array needs to expand to add + * more workers. Grouping them together in this way simplifies and + * speeds up task scanning. + * + * All worker thread creation is on-demand, triggered by task + * submissions, replacement of terminated workers, and/or + * compensation for blocked workers. However, all other support + * code is set up to work with other policies. To ensure that we + * do not hold on to worker references that would prevent GC, ALL + * accesses to workQueues are via indices into the workQueues + * array (which is one source of some of the messy code + * constructions here). In essence, the workQueues array serves as + * a weak reference mechanism. Thus for example the wait queue + * field of ctl stores indices, not references. Access to the + * workQueues in associated methods (for example signalWork) must + * both index-check and null-check the IDs. All such accesses + * ignore bad IDs by returning out early from what they are doing, + * since this can only be associated with termination, in which + * case it is OK to give up. All uses of the workQueues array + * also check that it is non-null (even if previously + * non-null). This allows nulling during termination, which is + * currently not necessary, but remains an option for + * resource-revocation-based shutdown schemes. It also helps + * reduce JIT issuance of uncommon-trap code, which tends to + * unnecessarily complicate control flow in some methods. + * + * Event Queuing. Unlike HPC work-stealing frameworks, we cannot * let workers spin indefinitely scanning for tasks when none can * be found immediately, and we cannot start/resume workers unless * there appear to be tasks available. On the other hand, we must * quickly prod them into action when new tasks are submitted or - * generated. We park/unpark workers after placing in an event - * wait queue when they cannot find work. This "queue" is actually - * a simple Treiber stack, headed by the "id" field of ctl, plus a - * 15bit counter value to both wake up waiters (by advancing their - * count) and avoid ABA effects. Successors are held in worker - * field "nextWait". Queuing deals with several intrinsic races, - * mainly that a task-producing thread can miss seeing (and + * generated. In many usages, ramp-up time to activate workers is + * the main limiting factor in overall performance (this is + * compounded at program start-up by JIT compilation and + * allocation). So we try to streamline this as much as possible. + * We park/unpark workers after placing in an event wait queue + * when they cannot find work. This "queue" is actually a simple + * Treiber stack, headed by the "id" field of ctl, plus a 15bit + * counter value (that reflects the number of times a worker has + * been inactivated) to avoid ABA effects (we need only as many + * version numbers as worker threads). Successors are held in + * field WorkQueue.nextWait. Queuing deals with several intrinsic + * races, mainly that a task-producing thread can miss seeing (and * signalling) another thread that gave up looking for work but * has not yet entered the wait queue. We solve this by requiring - * a full sweep of all workers both before (in scan()) and after - * (in tryAwaitWork()) a newly waiting worker is added to the wait - * queue. During a rescan, the worker might release some other - * queued worker rather than itself, which has the same net - * effect. Because enqueued workers may actually be rescanning - * rather than waiting, we set and clear the "parked" field of - * ForkJoinWorkerThread to reduce unnecessary calls to unpark. - * (Use of the parked field requires a secondary recheck to avoid - * missed signals.) + * a full sweep of all workers (via repeated calls to method + * scan()) both before and after a newly waiting worker is added + * to the wait queue. During a rescan, the worker might release + * some other queued worker rather than itself, which has the same + * net effect. Because enqueued workers may actually be rescanning + * rather than waiting, we set and clear the "parker" field of + * WorkQueues to reduce unnecessary calls to unpark. (This + * requires a secondary recheck to avoid missed signals.) Note + * the unusual conventions about Thread.interrupts surrounding + * parking and other blocking: Because interrupts are used solely + * to alert threads to check termination, which is checked anyway + * upon blocking, we clear status (using Thread.interrupted) + * before any call to park, so that park does not immediately + * return due to status being set via some other unrelated call to + * interrupt in user code. * * Signalling. We create or wake up workers only when there * appears to be at least one task they might be able to find and - * execute. When a submission is added or another worker adds a - * task to a queue that previously had two or fewer tasks, they - * signal waiting workers (or trigger creation of new ones if - * fewer than the given parallelism level -- see signalWork). - * These primary signals are buttressed by signals during rescans - * as well as those performed when a worker steals a task and - * notices that there are more tasks too; together these cover the - * signals needed in cases when more than two tasks are pushed - * but untaken. + * execute. However, many other threads may notice the same task + * and each signal to wake up a thread that might take it. So in + * general, pools will be over-signalled. When a submission is + * added or another worker adds a task to a queue that has fewer + * than two tasks, they signal waiting workers (or trigger + * creation of new ones if fewer than the given parallelism level + * -- signalWork), and may leave a hint to the unparked worker to + * help signal others upon wakeup). These primary signals are + * buttressed by others (see method helpSignal) whenever other + * threads scan for work or do not have a task to process. On + * most platforms, signalling (unpark) overhead time is noticeably + * long, and the time between signalling a thread and it actually + * making progress can be very noticeably long, so it is worth + * offloading these delays from critical paths as much as + * possible. * * Trimming workers. To release resources after periods of lack of * use, a worker starting to wait when the pool is quiescent will - * time out and terminate if the pool has remained quiescent for - * SHRINK_RATE nanosecs. This will slowly propagate, eventually - * terminating all workers after long periods of non-use. - * - * Submissions. External submissions are maintained in an - * array-based queue that is structured identically to - * ForkJoinWorkerThread queues except for the use of - * submissionLock in method addSubmission. Unlike the case for - * worker queues, multiple external threads can add new - * submissions, so adding requires a lock. - * - * Compensation. Beyond work-stealing support and lifecycle - * control, the main responsibility of this framework is to take - * actions when one worker is waiting to join a task stolen (or - * always held by) another. Because we are multiplexing many - * tasks on to a pool of workers, we can't just let them block (as - * in Thread.join). We also cannot just reassign the joiner's - * run-time stack with another and replace it later, which would - * be a form of "continuation", that even if possible is not - * necessarily a good idea since we sometimes need both an - * unblocked task and its continuation to progress. Instead we - * combine two tactics: + * time out and terminate if the pool has remained quiescent for a + * given period -- a short period if there are more threads than + * parallelism, longer as the number of threads decreases. This + * will slowly propagate, eventually terminating all workers after + * periods of non-use. + * + * Shutdown and Termination. A call to shutdownNow atomically sets + * a plock bit and then (non-atomically) sets each worker's + * qlock status, cancels all unprocessed tasks, and wakes up + * all waiting workers. Detecting whether termination should + * commence after a non-abrupt shutdown() call requires more work + * and bookkeeping. We need consensus about quiescence (i.e., that + * there is no more work). The active count provides a primary + * indication but non-abrupt shutdown still requires a rechecking + * scan for any workers that are inactive but not queued. + * + * Joining Tasks + * ============= + * + * Any of several actions may be taken when one worker is waiting + * to join a task stolen (or always held) by another. Because we + * are multiplexing many tasks on to a pool of workers, we can't + * just let them block (as in Thread.join). We also cannot just + * reassign the joiner's run-time stack with another and replace + * it later, which would be a form of "continuation", that even if + * possible is not necessarily a good idea since we sometimes need + * both an unblocked task and its continuation to progress. + * Instead we combine two tactics: * * Helping: Arranging for the joiner to execute some task that it - * would be running if the steal had not occurred. Method - * ForkJoinWorkerThread.joinTask tracks joining->stealing - * links to try to find such a task. + * would be running if the steal had not occurred. * * Compensating: Unless there are already enough live threads, - * method tryPreBlock() may create or re-activate a spare - * thread to compensate for blocked joiners until they - * unblock. + * method tryCompensate() may create or re-activate a spare + * thread to compensate for blocked joiners until they unblock. + * + * A third form (implemented in tryRemoveAndExec) amounts to + * helping a hypothetical compensator: If we can readily tell that + * a possible action of a compensator is to steal and execute the + * task being joined, the joining thread can do so directly, + * without the need for a compensation thread (although at the + * expense of larger run-time stacks, but the tradeoff is + * typically worthwhile). * * The ManagedBlocker extension API can't use helping so relies * only on compensation in method awaitBlocker. * + * The algorithm in tryHelpStealer entails a form of "linear" + * helping: Each worker records (in field currentSteal) the most + * recent task it stole from some other worker. Plus, it records + * (in field currentJoin) the task it is currently actively + * joining. Method tryHelpStealer uses these markers to try to + * find a worker to help (i.e., steal back a task from and execute + * it) that could hasten completion of the actively joined task. + * In essence, the joiner executes a task that would be on its own + * local deque had the to-be-joined task not been stolen. This may + * be seen as a conservative variant of the approach in Wagner & + * Calder "Leapfrogging: a portable technique for implementing + * efficient futures" SIGPLAN Notices, 1993 + * (http://portal.acm.org/citation.cfm?id=155354). It differs in + * that: (1) We only maintain dependency links across workers upon + * steals, rather than use per-task bookkeeping. This sometimes + * requires a linear scan of workQueues array to locate stealers, + * but often doesn't because stealers leave hints (that may become + * stale/wrong) of where to locate them. It is only a hint + * because a worker might have had multiple steals and the hint + * records only one of them (usually the most current). Hinting + * isolates cost to when it is needed, rather than adding to + * per-task overhead. (2) It is "shallow", ignoring nesting and + * potentially cyclic mutual steals. (3) It is intentionally + * racy: field currentJoin is updated only while actively joining, + * which means that we miss links in the chain during long-lived + * tasks, GC stalls etc (which is OK since blocking in such cases + * is usually a good idea). (4) We bound the number of attempts + * to find work (see MAX_HELP) and fall back to suspending the + * worker and if necessary replacing it with another. + * + * Helping actions for CountedCompleters are much simpler: Method + * helpComplete can take and execute any task with the same root + * as the task being waited on. However, this still entails some + * traversal of completer chains, so is less efficient than using + * CountedCompleters without explicit joins. + * * It is impossible to keep exactly the target parallelism number * of threads running at any given time. Determining the * existence of conservatively safe helping targets, the * availability of already-created spares, and the apparent need - * to create new spares are all racy and require heuristic - * guidance, so we rely on multiple retries of each. Currently, - * in keeping with on-demand signalling policy, we compensate only - * if blocking would leave less than one active (non-waiting, - * non-blocked) worker. Additionally, to avoid some false alarms - * due to GC, lagging counters, system activity, etc, compensated - * blocking for joins is only attempted after rechecks stabilize - * (retries are interspersed with Thread.yield, for good - * citizenship). The variable blockedCount, incremented before - * blocking and decremented after, is sometimes needed to - * distinguish cases of waiting for work vs blocking on joins or - * other managed sync. Both cases are equivalent for most pool - * control, so we can update non-atomically. (Additionally, - * contention on blockedCount alleviates some contention on ctl). - * - * Shutdown and Termination. A call to shutdownNow atomically sets - * the ctl stop bit and then (non-atomically) sets each workers - * "terminate" status, cancels all unprocessed tasks, and wakes up - * all waiting workers. Detecting whether termination should - * commence after a non-abrupt shutdown() call requires more work - * and bookkeeping. We need consensus about quiescence (i.e., that - * there is no more work) which is reflected in active counts so - * long as there are no current blockers, as well as possible - * re-evaluations during independent changes in blocking or - * quiescing workers. - * - * Style notes: There is a lot of representation-level coupling - * among classes ForkJoinPool, ForkJoinWorkerThread, and - * ForkJoinTask. Most fields of ForkJoinWorkerThread maintain - * data structures managed by ForkJoinPool, so are directly - * accessed. Conversely we allow access to "workers" array by - * workers, and direct access to ForkJoinTask.status by both - * ForkJoinPool and ForkJoinWorkerThread. There is little point + * to create new spares are all racy, so we rely on multiple + * retries of each. Compensation in the apparent absence of + * helping opportunities is challenging to control on JVMs, where + * GC and other activities can stall progress of tasks that in + * turn stall out many other dependent tasks, without us being + * able to determine whether they will ever require compensation. + * Even though work-stealing otherwise encounters little + * degradation in the presence of more threads than cores, + * aggressively adding new threads in such cases entails risk of + * unwanted positive feedback control loops in which more threads + * cause more dependent stalls (as well as delayed progress of + * unblocked threads to the point that we know they are available) + * leading to more situations requiring more threads, and so + * on. This aspect of control can be seen as an (analytically + * intractable) game with an opponent that may choose the worst + * (for us) active thread to stall at any time. We take several + * precautions to bound losses (and thus bound gains), mainly in + * methods tryCompensate and awaitJoin. + * + * Common Pool + * =========== + * + * The static commonPool always exists after static + * initialization. Since it (or any other created pool) need + * never be used, we minimize initial construction overhead and + * footprint to the setup of about a dozen fields, with no nested + * allocation. Most bootstrapping occurs within method + * fullExternalPush during the first submission to the pool. + * + * When external threads submit to the common pool, they can + * perform some subtask processing (see externalHelpJoin and + * related methods). We do not need to record whether these + * submissions are to the common pool -- if not, externalHelpJoin + * returns quickly (at the most helping to signal some common pool + * workers). These submitters would otherwise be blocked waiting + * for completion, so the extra effort (with liberally sprinkled + * task status checks) in inapplicable cases amounts to an odd + * form of limited spin-wait before blocking in ForkJoinTask.join. + * + * Style notes + * =========== + * + * There is a lot of representation-level coupling among classes + * ForkJoinPool, ForkJoinWorkerThread, and ForkJoinTask. The + * fields of WorkQueue maintain data structures managed by + * ForkJoinPool, so are directly accessed. There is little point * trying to reduce this, since any associated future changes in * representations will need to be accompanied by algorithmic - * changes anyway. All together, these low-level implementation - * choices produce as much as a factor of 4 performance - * improvement compared to naive implementations, and enable the - * processing of billions of tasks per second, at the expense of - * some ugliness. - * - * Methods signalWork() and scan() are the main bottlenecks so are - * especially heavily micro-optimized/mangled. There are lots of - * inline assignments (of form "while ((local = field) != 0)") - * which are usually the simplest way to ensure the required read - * orderings (which are sometimes critical). This leads to a - * "C"-like style of listing declarations of these locals at the - * heads of methods or blocks. There are several occurrences of - * the unusual "do {} while (!cas...)" which is the simplest way - * to force an update of a CAS'ed variable. There are also other - * coding oddities that help some methods perform reasonably even - * when interpreted (not compiled). - * - * The order of declarations in this file is: (1) declarations of - * statics (2) fields (along with constants used when unpacking - * some of them), listed in an order that tends to reduce - * contention among them a bit under most JVMs. (3) internal - * control methods (4) callbacks and other support for - * ForkJoinTask and ForkJoinWorkerThread classes, (5) exported - * methods (plus a few little helpers). (6) static block - * initializing all statics in a minimally dependent order. + * changes anyway. Several methods intrinsically sprawl because + * they must accumulate sets of consistent reads of volatiles held + * in local variables. Methods signalWork() and scan() are the + * main bottlenecks, so are especially heavily + * micro-optimized/mangled. There are lots of inline assignments + * (of form "while ((local = field) != 0)") which are usually the + * simplest way to ensure the required read orderings (which are + * sometimes critical). This leads to a "C"-like style of listing + * declarations of these locals at the heads of methods or blocks. + * There are several occurrences of the unusual "do {} while + * (!cas...)" which is the simplest way to force an update of a + * CAS'ed variable. There are also other coding oddities (including + * several unnecessary-looking hoisted null checks) that help + * some methods perform reasonably even when interpreted (not + * compiled). + * + * The order of declarations in this file is: + * (1) Static utility functions + * (2) Nested (static) classes + * (3) Static fields + * (4) Fields, along with constants used when unpacking some of them + * (5) Internal control methods + * (6) Callbacks and other support for ForkJoinTask methods + * (7) Exported methods + * (8) Static block initializing statics in minimally dependent order + */ + + // Static utilities + + /** + * If there is a security manager, makes sure caller has + * permission to modify threads. */ + private static void checkPermission() { + SecurityManager security = System.getSecurityManager(); + if (security != null) + security.checkPermission(modifyThreadPermission); + } + + // Nested classes /** * Factory for creating new {@link ForkJoinWorkerThread}s. @@ -359,122 +528,619 @@ public class ForkJoinPool extends AbstractExecutorService { * Default ForkJoinWorkerThreadFactory implementation; creates a * new ForkJoinWorkerThread. */ - static class DefaultForkJoinWorkerThreadFactory + static final class DefaultForkJoinWorkerThreadFactory implements ForkJoinWorkerThreadFactory { - public ForkJoinWorkerThread newThread(ForkJoinPool pool) { + public final ForkJoinWorkerThread newThread(ForkJoinPool pool) { return new ForkJoinWorkerThread(pool); } } /** - * Creates a new ForkJoinWorkerThread. This factory is used unless - * overridden in ForkJoinPool constructors. - */ - public static final ForkJoinWorkerThreadFactory - defaultForkJoinWorkerThreadFactory; + * Per-thread records for threads that submit to pools. Currently + * holds only pseudo-random seed / index that is used to choose + * submission queues in method externalPush. In the future, this may + * also incorporate a means to implement different task rejection + * and resubmission policies. + * + * Seeds for submitters and workers/workQueues work in basically + * the same way but are initialized and updated using slightly + * different mechanics. Both are initialized using the same + * approach as in class ThreadLocal, where successive values are + * unlikely to collide with previous values. Seeds are then + * randomly modified upon collisions using xorshifts, which + * requires a non-zero seed. + */ + static final class Submitter { + int seed; + Submitter(int s) { seed = s; } + } + + /** + * Class for artificial tasks that are used to replace the target + * of local joins if they are removed from an interior queue slot + * in WorkQueue.tryRemoveAndExec. We don't need the proxy to + * actually do anything beyond having a unique identity. + */ + static final class EmptyTask extends ForkJoinTask { + private static final long serialVersionUID = -7721805057305804111L; + EmptyTask() { status = ForkJoinTask.NORMAL; } // force done + public final Void getRawResult() { return null; } + public final void setRawResult(Void x) {} + public final boolean exec() { return true; } + } + + /** + * Queues supporting work-stealing as well as external task + * submission. See above for main rationale and algorithms. + * Implementation relies heavily on "Unsafe" intrinsics + * and selective use of "volatile": + * + * Field "base" is the index (mod array.length) of the least valid + * queue slot, which is always the next position to steal (poll) + * from if nonempty. Reads and writes require volatile orderings + * but not CAS, because updates are only performed after slot + * CASes. + * + * Field "top" is the index (mod array.length) of the next queue + * slot to push to or pop from. It is written only by owner thread + * for push, or under lock for external/shared push, and accessed + * by other threads only after reading (volatile) base. Both top + * and base are allowed to wrap around on overflow, but (top - + * base) (or more commonly -(base - top) to force volatile read of + * base before top) still estimates size. The lock ("qlock") is + * forced to -1 on termination, causing all further lock attempts + * to fail. (Note: we don't need CAS for termination state because + * upon pool shutdown, all shared-queues will stop being used + * anyway.) Nearly all lock bodies are set up so that exceptions + * within lock bodies are "impossible" (modulo JVM errors that + * would cause failure anyway.) + * + * The array slots are read and written using the emulation of + * volatiles/atomics provided by Unsafe. Insertions must in + * general use putOrderedObject as a form of releasing store to + * ensure that all writes to the task object are ordered before + * its publication in the queue. All removals entail a CAS to + * null. The array is always a power of two. To ensure safety of + * Unsafe array operations, all accesses perform explicit null + * checks and implicit bounds checks via power-of-two masking. + * + * In addition to basic queuing support, this class contains + * fields described elsewhere to control execution. It turns out + * to work better memory-layout-wise to include them in this class + * rather than a separate class. + * + * Performance on most platforms is very sensitive to placement of + * instances of both WorkQueues and their arrays -- we absolutely + * do not want multiple WorkQueue instances or multiple queue + * arrays sharing cache lines. (It would be best for queue objects + * and their arrays to share, but there is nothing available to + * help arrange that). Unfortunately, because they are recorded + * in a common array, WorkQueue instances are often moved to be + * adjacent by garbage collectors. To reduce impact, we use field + * padding that works OK on common platforms; this effectively + * trades off slightly slower average field access for the sake of + * avoiding really bad worst-case access. (Until better JVM + * support is in place, this padding is dependent on transient + * properties of JVM field layout rules.) We also take care in + * allocating, sizing and resizing the array. Non-shared queue + * arrays are initialized by workers before use. Others are + * allocated on first use. + */ + static final class WorkQueue { + /** + * Capacity of work-stealing queue array upon initialization. + * Must be a power of two; at least 4, but should be larger to + * reduce or eliminate cacheline sharing among queues. + * Currently, it is much larger, as a partial workaround for + * the fact that JVMs often place arrays in locations that + * share GC bookkeeping (especially cardmarks) such that + * per-write accesses encounter serious memory contention. + */ + static final int INITIAL_QUEUE_CAPACITY = 1 << 13; - /** - * Permission required for callers of methods that may start or - * kill threads. - */ - private static final RuntimePermission modifyThreadPermission; + /** + * Maximum size for queue arrays. Must be a power of two less + * than or equal to 1 << (31 - width of array entry) to ensure + * lack of wraparound of index calculations, but defined to a + * value a bit less than this to help users trap runaway + * programs before saturating systems. + */ + static final int MAXIMUM_QUEUE_CAPACITY = 1 << 26; // 64M + + // Heuristic padding to ameliorate unfortunate memory placements + volatile long pad00, pad01, pad02, pad03, pad04, pad05, pad06; + + int seed; // for random scanning; initialize nonzero + volatile int eventCount; // encoded inactivation count; < 0 if inactive + int nextWait; // encoded record of next event waiter + int hint; // steal or signal hint (index) + int poolIndex; // index of this queue in pool (or 0) + final int mode; // 0: lifo, > 0: fifo, < 0: shared + int nsteals; // number of steals + volatile int qlock; // 1: locked, -1: terminate; else 0 + volatile int base; // index of next slot for poll + int top; // index of next slot for push + ForkJoinTask[] array; // the elements (initially unallocated) + final ForkJoinPool pool; // the containing pool (may be null) + final ForkJoinWorkerThread owner; // owning thread or null if shared + volatile Thread parker; // == owner during call to park; else null + volatile ForkJoinTask currentJoin; // task being joined in awaitJoin + ForkJoinTask currentSteal; // current non-local task being executed + + volatile Object pad10, pad11, pad12, pad13, pad14, pad15, pad16, pad17; + volatile Object pad18, pad19, pad1a, pad1b, pad1c, pad1d; + + WorkQueue(ForkJoinPool pool, ForkJoinWorkerThread owner, int mode, + int seed) { + this.pool = pool; + this.owner = owner; + this.mode = mode; + this.seed = seed; + // Place indices in the center of array (that is not yet allocated) + base = top = INITIAL_QUEUE_CAPACITY >>> 1; + } - /** - * If there is a security manager, makes sure caller has - * permission to modify threads. - */ - private static void checkPermission() { - SecurityManager security = System.getSecurityManager(); - if (security != null) - security.checkPermission(modifyThreadPermission); + /** + * Returns the approximate number of tasks in the queue. + */ + final int queueSize() { + int n = base - top; // non-owner callers must read base first + return (n >= 0) ? 0 : -n; // ignore transient negative + } + + /** + * Provides a more accurate estimate of whether this queue has + * any tasks than does queueSize, by checking whether a + * near-empty queue has at least one unclaimed task. + */ + final boolean isEmpty() { + ForkJoinTask[] a; int m, s; + int n = base - (s = top); + return (n >= 0 || + (n == -1 && + ((a = array) == null || + (m = a.length - 1) < 0 || + U.getObject + (a, (long)((m & (s - 1)) << ASHIFT) + ABASE) == null))); + } + + /** + * Pushes a task. Call only by owner in unshared queues. (The + * shared-queue version is embedded in method externalPush.) + * + * @param task the task. Caller must ensure non-null. + * @throws RejectedExecutionException if array cannot be resized + */ + final void push(ForkJoinTask task) { + ForkJoinTask[] a; ForkJoinPool p; + int s = top, m, n; + if ((a = array) != null) { // ignore if queue removed + int j = (((m = a.length - 1) & s) << ASHIFT) + ABASE; + U.putOrderedObject(a, j, task); + if ((n = (top = s + 1) - base) <= 2) { + if ((p = pool) != null) + p.signalWork(this); + } + else if (n >= m) + growArray(); + } + } + + /** + * Initializes or doubles the capacity of array. Call either + * by owner or with lock held -- it is OK for base, but not + * top, to move while resizings are in progress. + */ + final ForkJoinTask[] growArray() { + ForkJoinTask[] oldA = array; + int size = oldA != null ? oldA.length << 1 : INITIAL_QUEUE_CAPACITY; + if (size > MAXIMUM_QUEUE_CAPACITY) + throw new RejectedExecutionException("Queue capacity exceeded"); + int oldMask, t, b; + ForkJoinTask[] a = array = new ForkJoinTask[size]; + if (oldA != null && (oldMask = oldA.length - 1) >= 0 && + (t = top) - (b = base) > 0) { + int mask = size - 1; + do { + ForkJoinTask x; + int oldj = ((b & oldMask) << ASHIFT) + ABASE; + int j = ((b & mask) << ASHIFT) + ABASE; + x = (ForkJoinTask)U.getObjectVolatile(oldA, oldj); + if (x != null && + U.compareAndSwapObject(oldA, oldj, x, null)) + U.putObjectVolatile(a, j, x); + } while (++b != t); + } + return a; + } + + /** + * Takes next task, if one exists, in LIFO order. Call only + * by owner in unshared queues. + */ + final ForkJoinTask pop() { + ForkJoinTask[] a; ForkJoinTask t; int m; + if ((a = array) != null && (m = a.length - 1) >= 0) { + for (int s; (s = top - 1) - base >= 0;) { + long j = ((m & s) << ASHIFT) + ABASE; + if ((t = (ForkJoinTask)U.getObject(a, j)) == null) + break; + if (U.compareAndSwapObject(a, j, t, null)) { + top = s; + return t; + } + } + } + return null; + } + + /** + * Takes a task in FIFO order if b is base of queue and a task + * can be claimed without contention. Specialized versions + * appear in ForkJoinPool methods scan and tryHelpStealer. + */ + final ForkJoinTask pollAt(int b) { + ForkJoinTask t; ForkJoinTask[] a; + if ((a = array) != null) { + int j = (((a.length - 1) & b) << ASHIFT) + ABASE; + if ((t = (ForkJoinTask)U.getObjectVolatile(a, j)) != null && + base == b && + U.compareAndSwapObject(a, j, t, null)) { + base = b + 1; + return t; + } + } + return null; + } + + /** + * Takes next task, if one exists, in FIFO order. + */ + final ForkJoinTask poll() { + ForkJoinTask[] a; int b; ForkJoinTask t; + while ((b = base) - top < 0 && (a = array) != null) { + int j = (((a.length - 1) & b) << ASHIFT) + ABASE; + t = (ForkJoinTask)U.getObjectVolatile(a, j); + if (t != null) { + if (base == b && + U.compareAndSwapObject(a, j, t, null)) { + base = b + 1; + return t; + } + } + else if (base == b) { + if (b + 1 == top) + break; + Thread.yield(); // wait for lagging update (very rare) + } + } + return null; + } + + /** + * Takes next task, if one exists, in order specified by mode. + */ + final ForkJoinTask nextLocalTask() { + return mode == 0 ? pop() : poll(); + } + + /** + * Returns next task, if one exists, in order specified by mode. + */ + final ForkJoinTask peek() { + ForkJoinTask[] a = array; int m; + if (a == null || (m = a.length - 1) < 0) + return null; + int i = mode == 0 ? top - 1 : base; + int j = ((i & m) << ASHIFT) + ABASE; + return (ForkJoinTask)U.getObjectVolatile(a, j); + } + + /** + * Pops the given task only if it is at the current top. + * (A shared version is available only via FJP.tryExternalUnpush) + */ + final boolean tryUnpush(ForkJoinTask t) { + ForkJoinTask[] a; int s; + if ((a = array) != null && (s = top) != base && + U.compareAndSwapObject + (a, (((a.length - 1) & --s) << ASHIFT) + ABASE, t, null)) { + top = s; + return true; + } + return false; + } + + /** + * Removes and cancels all known tasks, ignoring any exceptions. + */ + final void cancelAll() { + ForkJoinTask.cancelIgnoringExceptions(currentJoin); + ForkJoinTask.cancelIgnoringExceptions(currentSteal); + for (ForkJoinTask t; (t = poll()) != null; ) + ForkJoinTask.cancelIgnoringExceptions(t); + } + + /** + * Computes next value for random probes. Scans don't require + * a very high quality generator, but also not a crummy one. + * Marsaglia xor-shift is cheap and works well enough. Note: + * This is manually inlined in its usages in ForkJoinPool to + * avoid writes inside busy scan loops. + */ + final int nextSeed() { + int r = seed; + r ^= r << 13; + r ^= r >>> 17; + return seed = r ^= r << 5; + } + + // Specialized execution methods + + /** + * Pops and runs tasks until empty. + */ + private void popAndExecAll() { + // A bit faster than repeated pop calls + ForkJoinTask[] a; int m, s; long j; ForkJoinTask t; + while ((a = array) != null && (m = a.length - 1) >= 0 && + (s = top - 1) - base >= 0 && + (t = ((ForkJoinTask) + U.getObject(a, j = ((m & s) << ASHIFT) + ABASE))) + != null) { + if (U.compareAndSwapObject(a, j, t, null)) { + top = s; + t.doExec(); + } + } + } + + /** + * Polls and runs tasks until empty. + */ + private void pollAndExecAll() { + for (ForkJoinTask t; (t = poll()) != null;) + t.doExec(); + } + + /** + * If present, removes from queue and executes the given task, + * or any other cancelled task. Returns (true) on any CAS + * or consistency check failure so caller can retry. + * + * @return false if no progress can be made, else true + */ + final boolean tryRemoveAndExec(ForkJoinTask task) { + boolean stat = true, removed = false, empty = true; + ForkJoinTask[] a; int m, s, b, n; + if ((a = array) != null && (m = a.length - 1) >= 0 && + (n = (s = top) - (b = base)) > 0) { + for (ForkJoinTask t;;) { // traverse from s to b + int j = ((--s & m) << ASHIFT) + ABASE; + t = (ForkJoinTask)U.getObjectVolatile(a, j); + if (t == null) // inconsistent length + break; + else if (t == task) { + if (s + 1 == top) { // pop + if (!U.compareAndSwapObject(a, j, task, null)) + break; + top = s; + removed = true; + } + else if (base == b) // replace with proxy + removed = U.compareAndSwapObject(a, j, task, + new EmptyTask()); + break; + } + else if (t.status >= 0) + empty = false; + else if (s + 1 == top) { // pop and throw away + if (U.compareAndSwapObject(a, j, t, null)) + top = s; + break; + } + if (--n == 0) { + if (!empty && base == b) + stat = false; + break; + } + } + } + if (removed) + task.doExec(); + return stat; + } + + /** + * Polls for and executes the given task or any other task in + * its CountedCompleter computation. + */ + final boolean pollAndExecCC(ForkJoinTask root) { + ForkJoinTask[] a; int b; Object o; + outer: while ((b = base) - top < 0 && (a = array) != null) { + long j = (((a.length - 1) & b) << ASHIFT) + ABASE; + if ((o = U.getObject(a, j)) == null || + !(o instanceof CountedCompleter)) + break; + for (CountedCompleter t = (CountedCompleter)o, r = t;;) { + if (r == root) { + if (base == b && + U.compareAndSwapObject(a, j, t, null)) { + base = b + 1; + t.doExec(); + return true; + } + else + break; // restart + } + if ((r = r.completer) == null) + break outer; // not part of root computation + } + } + return false; + } + + /** + * Executes a top-level task and any local tasks remaining + * after execution. + */ + final void runTask(ForkJoinTask t) { + if (t != null) { + (currentSteal = t).doExec(); + currentSteal = null; + ++nsteals; + if (base - top < 0) { // process remaining local tasks + if (mode == 0) + popAndExecAll(); + else + pollAndExecAll(); + } + } + } + + /** + * Executes a non-top-level (stolen) task. + */ + final void runSubtask(ForkJoinTask t) { + if (t != null) { + ForkJoinTask ps = currentSteal; + (currentSteal = t).doExec(); + currentSteal = ps; + } + } + + /** + * Returns true if owned and not known to be blocked. + */ + final boolean isApparentlyUnblocked() { + Thread wt; Thread.State s; + return (eventCount >= 0 && + (wt = owner) != null && + (s = wt.getState()) != Thread.State.BLOCKED && + s != Thread.State.WAITING && + s != Thread.State.TIMED_WAITING); + } + + // Unsafe mechanics + private static final sun.misc.Unsafe U; + private static final long QLOCK; + private static final int ABASE; + private static final int ASHIFT; + static { + try { + U = sun.misc.Unsafe.getUnsafe(); + Class k = WorkQueue.class; + Class ak = ForkJoinTask[].class; + QLOCK = U.objectFieldOffset + (k.getDeclaredField("qlock")); + ABASE = U.arrayBaseOffset(ak); + int scale = U.arrayIndexScale(ak); + if ((scale & (scale - 1)) != 0) + throw new Error("data type scale not a power of two"); + ASHIFT = 31 - Integer.numberOfLeadingZeros(scale); + } catch (Exception e) { + throw new Error(e); + } + } } + // static fields (initialized in static initializer below) + /** - * Generator for assigning sequence numbers as pool names. + * Creates a new ForkJoinWorkerThread. This factory is used unless + * overridden in ForkJoinPool constructors. */ - private static final AtomicInteger poolNumberGenerator; + public static final ForkJoinWorkerThreadFactory + defaultForkJoinWorkerThreadFactory; /** - * Generator for initial random seeds for worker victim - * selection. This is used only to create initial seeds. Random - * steals use a cheaper xorshift generator per steal attempt. We - * don't expect much contention on seedGenerator, so just use a - * plain Random. + * Per-thread submission bookkeeping. Shared across all pools + * to reduce ThreadLocal pollution and because random motion + * to avoid contention in one pool is likely to hold for others. + * Lazily initialized on first submission (but null-checked + * in other contexts to avoid unnecessary initialization). */ - static final Random workerSeedGenerator; + static final ThreadLocal submitters; /** - * Array holding all worker threads in the pool. Initialized upon - * construction. Array size must be a power of two. Updates and - * replacements are protected by scanGuard, but the array is - * always kept in a consistent enough state to be randomly - * accessed without locking by workers performing work-stealing, - * as well as other traversal-based methods in this class, so long - * as reads memory-acquire by first reading ctl. All readers must - * tolerate that some array slots may be null. + * Permission required for callers of methods that may start or + * kill threads. */ - ForkJoinWorkerThread[] workers; + private static final RuntimePermission modifyThreadPermission; /** - * Initial size for submission queue array. Must be a power of - * two. In many applications, these always stay small so we use a - * small initial cap. + * Common (static) pool. Non-null for public use unless a static + * construction exception, but internal usages null-check on use + * to paranoically avoid potential initialization circularities + * as well as to simplify generated code. */ - private static final int INITIAL_QUEUE_CAPACITY = 8; + static final ForkJoinPool commonPool; /** - * Maximum size for submission queue array. Must be a power of two - * less than or equal to 1 << (31 - width of array entry) to - * ensure lack of index wraparound, but is capped at a lower - * value to help users trap runaway computations. + * Common pool parallelism. Must equal commonPool.parallelism. */ - private static final int MAXIMUM_QUEUE_CAPACITY = 1 << 24; // 16M + static final int commonPoolParallelism; /** - * Array serving as submission queue. Initialized upon construction. + * Sequence number for creating workerNamePrefix. */ - private ForkJoinTask[] submissionQueue; + private static int poolNumberSequence; /** - * Lock protecting submissions array for addSubmission + * Returns the next sequence number. We don't expect this to + * ever contend, so use simple builtin sync. */ - private final ReentrantLock submissionLock; + private static final synchronized int nextPoolId() { + return ++poolNumberSequence; + } + + // static constants /** - * Condition for awaitTermination, using submissionLock for - * convenience. + * Initial timeout value (in nanoseconds) for the thread + * triggering quiescence to park waiting for new work. On timeout, + * the thread will instead try to shrink the number of + * workers. The value should be large enough to avoid overly + * aggressive shrinkage during most transient stalls (long GCs + * etc). */ - private final Condition termination; + private static final long IDLE_TIMEOUT = 2000L * 1000L * 1000L; // 2sec /** - * Creation factory for worker threads. + * Timeout value when there are more threads than parallelism level */ - private final ForkJoinWorkerThreadFactory factory; + private static final long FAST_IDLE_TIMEOUT = 200L * 1000L * 1000L; /** - * The uncaught exception handler used when any worker abruptly - * terminates. + * Tolerance for idle timeouts, to cope with timer undershoots */ - final Thread.UncaughtExceptionHandler ueh; + private static final long TIMEOUT_SLOP = 2000000L; // 20ms /** - * Prefix for assigning names to worker threads + * The maximum stolen->joining link depth allowed in method + * tryHelpStealer. Must be a power of two. Depths for legitimate + * chains are unbounded, but we use a fixed constant to avoid + * (otherwise unchecked) cycles and to bound staleness of + * traversal parameters at the expense of sometimes blocking when + * we could be helping. */ - private final String workerNamePrefix; + private static final int MAX_HELP = 64; /** - * Sum of per-thread steal counts, updated only when threads are - * idle or terminating. + * Increment for seed generators. See class ThreadLocal for + * explanation. */ - private volatile long stealCount; + private static final int SEED_INCREMENT = 0x61c88647; - /** - * Main pool control -- a long packed with: + /* + * Bits and masks for control variables + * + * Field ctl is a long packed with: * AC: Number of active running workers minus target parallelism (16 bits) * TC: Number of total workers minus target parallelism (16 bits) * ST: true if pool is terminating (1 bit) * EC: the wait count of top waiting thread (15 bits) - * ID: ~poolIndex of top of Treiber stack of waiting threads (16 bits) + * ID: poolIndex of top of Treiber stack of waiters (16 bits) * * When convenient, we can extract the upper 32 bits of counts and * the lower 32 bits of queue state, u = (int)(ctl >>> 32) and e = @@ -483,13 +1149,26 @@ public class ForkJoinPool extends AbstractExecutorService { * parallelism and the positionings of fields makes it possible to * perform the most common checks via sign tests of fields: When * ac is negative, there are not enough active workers, when tc is - * negative, there are not enough total workers, when id is - * negative, there is at least one waiting worker, and when e is + * negative, there are not enough total workers, and when e is * negative, the pool is terminating. To deal with these possibly * negative fields, we use casts in and out of "short" and/or * signed shifts to maintain signedness. + * + * When a thread is queued (inactivated), its eventCount field is + * set negative, which is the only way to tell if a worker is + * prevented from executing tasks, even though it must continue to + * scan for them to avoid queuing races. Note however that + * eventCount updates lag releases so usage requires care. + * + * Field plock is an int packed with: + * SHUTDOWN: true if shutdown is enabled (1 bit) + * SEQ: a sequence lock, with PL_LOCK bit set if locked (30 bits) + * SIGNAL: set when threads may be waiting on the lock (1 bit) + * + * The sequence number enables simple consistency checks: + * Staleness of read-only operations on the workQueues array can + * be checked by comparing plock before vs after the reads. */ - volatile long ctl; // bit positions/shifts for fields private static final int AC_SHIFT = 48; @@ -498,8 +1177,10 @@ public class ForkJoinPool extends AbstractExecutorService { private static final int EC_SHIFT = 16; // bounds - private static final int MAX_ID = 0x7fff; // max poolIndex - private static final int SMASK = 0xffff; // mask short bits + private static final int SMASK = 0xffff; // short bits + private static final int MAX_CAP = 0x7fff; // max #workers - 1 + private static final int EVENMASK = 0xfffe; // even short bits + private static final int SQMASK = 0x007e; // max 64 (even) slots private static final int SHORT_SIGN = 1 << 15; private static final int INT_SIGN = 1 << 31; @@ -521,851 +1202,1280 @@ public class ForkJoinPool extends AbstractExecutorService { private static final int UTC_UNIT = 1 << UTC_SHIFT; // masks and units for dealing with e = (int)ctl - private static final int E_MASK = 0x7fffffff; // no STOP_BIT - private static final int EC_UNIT = 1 << EC_SHIFT; - - /** - * The target parallelism level. - */ - final int parallelism; - - /** - * Index (mod submission queue length) of next element to take - * from submission queue. Usage is identical to that for - * per-worker queues -- see ForkJoinWorkerThread internal - * documentation. - */ - volatile int queueBase; - - /** - * Index (mod submission queue length) of next element to add - * in submission queue. Usage is identical to that for - * per-worker queues -- see ForkJoinWorkerThread internal - * documentation. - */ - int queueTop; - - /** - * True when shutdown() has been called. - */ - volatile boolean shutdown; - - /** - * True if use local fifo, not default lifo, for local polling. - * Read by, and replicated by ForkJoinWorkerThreads. - */ - final boolean locallyFifo; + private static final int E_MASK = 0x7fffffff; // no STOP_BIT + private static final int E_SEQ = 1 << EC_SHIFT; - /** - * The number of threads in ForkJoinWorkerThreads.helpQuiescePool. - * When non-zero, suppresses automatic shutdown when active - * counts become zero. - */ - volatile int quiescerCount; + // plock bits + private static final int SHUTDOWN = 1 << 31; + private static final int PL_LOCK = 2; + private static final int PL_SIGNAL = 1; + private static final int PL_SPINS = 1 << 8; - /** - * The number of threads blocked in join. - */ - volatile int blockedCount; + // access mode for WorkQueue + static final int LIFO_QUEUE = 0; + static final int FIFO_QUEUE = 1; + static final int SHARED_QUEUE = -1; - /** - * Counter for worker Thread names (unrelated to their poolIndex) - */ - private volatile int nextWorkerNumber; - - /** - * The index for the next created worker. Accessed under scanGuard. - */ - private int nextWorkerIndex; + // bounds for #steps in scan loop -- must be power 2 minus 1 + private static final int MIN_SCAN = 0x1ff; // cover estimation slop + private static final int MAX_SCAN = 0x1ffff; // 4 * max workers - /** - * SeqLock and index masking for updates to workers array. Locked - * when SG_UNIT is set. Unlocking clears bit by adding - * SG_UNIT. Staleness of read-only operations can be checked by - * comparing scanGuard to value before the reads. The low 16 bits - * (i.e, anding with SMASK) hold (the smallest power of two - * covering all worker indices, minus one, and is used to avoid - * dealing with large numbers of null slots when the workers array - * is overallocated. - */ - volatile int scanGuard; + // Instance fields - private static final int SG_UNIT = 1 << 16; + /* + * Field layout of this class tends to matter more than one would + * like. Runtime layout order is only loosely related to + * declaration order and may differ across JVMs, but the following + * empirically works OK on current JVMs. + */ + + // Heuristic padding to ameliorate unfortunate memory placements + volatile long pad00, pad01, pad02, pad03, pad04, pad05, pad06; + + volatile long stealCount; // collects worker counts + volatile long ctl; // main pool control + volatile int plock; // shutdown status and seqLock + volatile int indexSeed; // worker/submitter index seed + final int config; // mode and parallelism level + WorkQueue[] workQueues; // main registry + final ForkJoinWorkerThreadFactory factory; + final Thread.UncaughtExceptionHandler ueh; // per-worker UEH + final String workerNamePrefix; // to create worker name string + + volatile Object pad10, pad11, pad12, pad13, pad14, pad15, pad16, pad17; + volatile Object pad18, pad19, pad1a, pad1b; + + /** + * Acquires the plock lock to protect worker array and related + * updates. This method is called only if an initial CAS on plock + * fails. This acts as a spinlock for normal cases, but falls back + * to builtin monitor to block when (rarely) needed. This would be + * a terrible idea for a highly contended lock, but works fine as + * a more conservative alternative to a pure spinlock. + */ + private int acquirePlock() { + int spins = PL_SPINS, r = 0, ps, nps; + for (;;) { + if (((ps = plock) & PL_LOCK) == 0 && + U.compareAndSwapInt(this, PLOCK, ps, nps = ps + PL_LOCK)) + return nps; + else if (r == 0) { // randomize spins if possible + Thread t = Thread.currentThread(); WorkQueue w; Submitter z; + if ((t instanceof ForkJoinWorkerThread) && + (w = ((ForkJoinWorkerThread)t).workQueue) != null) + r = w.seed; + else if ((z = submitters.get()) != null) + r = z.seed; + else + r = 1; + } + else if (spins >= 0) { + r ^= r << 1; r ^= r >>> 3; r ^= r << 10; // xorshift + if (r >= 0) + --spins; + } + else if (U.compareAndSwapInt(this, PLOCK, ps, ps | PL_SIGNAL)) { + synchronized (this) { + if ((plock & PL_SIGNAL) != 0) { + try { + wait(); + } catch (InterruptedException ie) { + try { + Thread.currentThread().interrupt(); + } catch (SecurityException ignore) { + } + } + } + else + notifyAll(); + } + } + } + } /** - * The wakeup interval (in nanoseconds) for a worker waiting for a - * task when the pool is quiescent to instead try to shrink the - * number of workers. The exact value does not matter too - * much. It must be short enough to release resources during - * sustained periods of idleness, but not so short that threads - * are continually re-created. + * Unlocks and signals any thread waiting for plock. Called only + * when CAS of seq value for unlock fails. */ - private static final long SHRINK_RATE = - 4L * 1000L * 1000L * 1000L; // 4 seconds + private void releasePlock(int ps) { + plock = ps; + synchronized (this) { notifyAll(); } + } /** - * Top-level loop for worker threads: On each step: if the - * previous step swept through all queues and found no tasks, or - * there are excess threads, then possibly blocks. Otherwise, - * scans for and, if found, executes a task. Returns when pool - * and/or worker terminate. + * Performs secondary initialization, called when plock is zero. + * Creates workQueue array and sets plock to a valid value. The + * lock body must be exception-free (so no try/finally) so we + * optimistically allocate new array outside the lock and throw + * away if (very rarely) not needed. (A similar tactic is used in + * fullExternalPush.) Because the plock seq value can eventually + * wrap around zero, this method harmlessly fails to reinitialize + * if workQueues exists, while still advancing plock. * - * @param w the worker + * Additionally tries to create the first worker. */ - final void work(ForkJoinWorkerThread w) { - boolean swept = false; // true on empty scans - long c; - while (!w.terminate && (int)(c = ctl) >= 0) { - int a; // active count - if (!swept && (a = (int)(c >> AC_SHIFT)) <= 0) - swept = scan(w, a); - else if (tryAwaitWork(w, c)) - swept = false; + private void initWorkers() { + WorkQueue[] ws, nws; int ps; + int p = config & SMASK; // find power of two table size + int n = (p > 1) ? p - 1 : 1; // ensure at least 2 slots + n |= n >>> 1; n |= n >>> 2; n |= n >>> 4; n |= n >>> 8; n |= n >>> 16; + n = (n + 1) << 1; + if ((ws = workQueues) == null || ws.length == 0) + nws = new WorkQueue[n]; + else + nws = null; + if (((ps = plock) & PL_LOCK) != 0 || + !U.compareAndSwapInt(this, PLOCK, ps, ps += PL_LOCK)) + ps = acquirePlock(); + if (((ws = workQueues) == null || ws.length == 0) && nws != null) + workQueues = nws; + int nps = (ps & SHUTDOWN) | ((ps + PL_LOCK) & ~SHUTDOWN); + if (!U.compareAndSwapInt(this, PLOCK, ps, nps)) + releasePlock(nps); + tryAddWorker(); + } + + /** + * Tries to create and start one worker if fewer than target + * parallelism level exist. Adjusts counts etc on failure. + */ + private void tryAddWorker() { + long c; int u; + while ((u = (int)((c = ctl) >>> 32)) < 0 && + (u & SHORT_SIGN) != 0 && (int)c == 0) { + long nc = (long)(((u + UTC_UNIT) & UTC_MASK) | + ((u + UAC_UNIT) & UAC_MASK)) << 32; + if (U.compareAndSwapLong(this, CTL, c, nc)) { + ForkJoinWorkerThreadFactory fac; + Throwable ex = null; + ForkJoinWorkerThread wt = null; + try { + if ((fac = factory) != null && + (wt = fac.newThread(this)) != null) { + wt.start(); + break; + } + } catch (Throwable e) { + ex = e; + } + deregisterWorker(wt, ex); + break; + } } } - // Signalling + // Registering and deregistering workers /** - * Wakes up or creates a worker. + * Callback from ForkJoinWorkerThread to establish and record its + * WorkQueue. To avoid scanning bias due to packing entries in + * front of the workQueues array, we treat the array as a simple + * power-of-two hash table using per-thread seed as hash, + * expanding as needed. + * + * @param wt the worker thread + * @return the worker's queue */ - final void signalWork() { - /* - * The while condition is true if: (there is are too few total - * workers OR there is at least one waiter) AND (there are too - * few active workers OR the pool is terminating). The value - * of e distinguishes the remaining cases: zero (no waiters) - * for create, negative if terminating (in which case do - * nothing), else release a waiter. The secondary checks for - * release (non-null array etc) can fail if the pool begins - * terminating after the test, and don't impose any added cost - * because JVMs must perform null and bounds checks anyway. - */ - long c; int e, u; - while ((((e = (int)(c = ctl)) | (u = (int)(c >>> 32))) & - (INT_SIGN|SHORT_SIGN)) == (INT_SIGN|SHORT_SIGN) && e >= 0) { - if (e > 0) { // release a waiting worker - int i; ForkJoinWorkerThread w; ForkJoinWorkerThread[] ws; - if ((ws = workers) == null || - (i = ~e & SMASK) >= ws.length || - (w = ws[i]) == null) - break; - long nc = (((long)(w.nextWait & E_MASK)) | - ((long)(u + UAC_UNIT) << 32)); - if (w.eventCount == e && - UNSAFE.compareAndSwapLong(this, ctlOffset, c, nc)) { - w.eventCount = (e + EC_UNIT) & E_MASK; - if (w.parked) - UNSAFE.unpark(w); - break; + final WorkQueue registerWorker(ForkJoinWorkerThread wt) { + Thread.UncaughtExceptionHandler handler; WorkQueue[] ws; int s, ps; + wt.setDaemon(true); + if ((handler = ueh) != null) + wt.setUncaughtExceptionHandler(handler); + do {} while (!U.compareAndSwapInt(this, INDEXSEED, s = indexSeed, + s += SEED_INCREMENT) || + s == 0); // skip 0 + WorkQueue w = new WorkQueue(this, wt, config >>> 16, s); + if (((ps = plock) & PL_LOCK) != 0 || + !U.compareAndSwapInt(this, PLOCK, ps, ps += PL_LOCK)) + ps = acquirePlock(); + int nps = (ps & SHUTDOWN) | ((ps + PL_LOCK) & ~SHUTDOWN); + try { + if ((ws = workQueues) != null) { // skip if shutting down + int n = ws.length, m = n - 1; + int r = (s << 1) | 1; // use odd-numbered indices + if (ws[r &= m] != null) { // collision + int probes = 0; // step by approx half size + int step = (n <= 4) ? 2 : ((n >>> 1) & EVENMASK) + 2; + while (ws[r = (r + step) & m] != null) { + if (++probes >= n) { + workQueues = ws = Arrays.copyOf(ws, n <<= 1); + m = n - 1; + probes = 0; + } + } } + w.eventCount = w.poolIndex = r; // volatile write orders + ws[r] = w; } - else if (UNSAFE.compareAndSwapLong - (this, ctlOffset, c, - (long)(((u + UTC_UNIT) & UTC_MASK) | - ((u + UAC_UNIT) & UAC_MASK)) << 32)) { - addWorker(); - break; + } finally { + if (!U.compareAndSwapInt(this, PLOCK, ps, nps)) + releasePlock(nps); + } + wt.setName(workerNamePrefix.concat(Integer.toString(w.poolIndex))); + return w; + } + + /** + * Final callback from terminating worker, as well as upon failure + * to construct or start a worker. Removes record of worker from + * array, and adjusts counts. If pool is shutting down, tries to + * complete termination. + * + * @param wt the worker thread or null if construction failed + * @param ex the exception causing failure, or null if none + */ + final void deregisterWorker(ForkJoinWorkerThread wt, Throwable ex) { + WorkQueue w = null; + if (wt != null && (w = wt.workQueue) != null) { + int ps; + w.qlock = -1; // ensure set + long ns = w.nsteals, sc; // collect steal count + do {} while (!U.compareAndSwapLong(this, STEALCOUNT, + sc = stealCount, sc + ns)); + if (((ps = plock) & PL_LOCK) != 0 || + !U.compareAndSwapInt(this, PLOCK, ps, ps += PL_LOCK)) + ps = acquirePlock(); + int nps = (ps & SHUTDOWN) | ((ps + PL_LOCK) & ~SHUTDOWN); + try { + int idx = w.poolIndex; + WorkQueue[] ws = workQueues; + if (ws != null && idx >= 0 && idx < ws.length && ws[idx] == w) + ws[idx] = null; + } finally { + if (!U.compareAndSwapInt(this, PLOCK, ps, nps)) + releasePlock(nps); } } - } - /** - * Variant of signalWork to help release waiters on rescans. - * Tries once to release a waiter if active count < 0. - * - * @return false if failed due to contention, else true - */ - private boolean tryReleaseWaiter() { - long c; int e, i; ForkJoinWorkerThread w; ForkJoinWorkerThread[] ws; - if ((e = (int)(c = ctl)) > 0 && - (int)(c >> AC_SHIFT) < 0 && - (ws = workers) != null && - (i = ~e & SMASK) < ws.length && - (w = ws[i]) != null) { - long nc = ((long)(w.nextWait & E_MASK) | - ((c + AC_UNIT) & (AC_MASK|TC_MASK))); - if (w.eventCount != e || - !UNSAFE.compareAndSwapLong(this, ctlOffset, c, nc)) - return false; - w.eventCount = (e + EC_UNIT) & E_MASK; - if (w.parked) - UNSAFE.unpark(w); + long c; // adjust ctl counts + do {} while (!U.compareAndSwapLong + (this, CTL, c = ctl, (((c - AC_UNIT) & AC_MASK) | + ((c - TC_UNIT) & TC_MASK) | + (c & ~(AC_MASK|TC_MASK))))); + + if (!tryTerminate(false, false) && w != null && w.array != null) { + w.cancelAll(); // cancel remaining tasks + WorkQueue[] ws; WorkQueue v; Thread p; int u, i, e; + while ((u = (int)((c = ctl) >>> 32)) < 0 && (e = (int)c) >= 0) { + if (e > 0) { // activate or create replacement + if ((ws = workQueues) == null || + (i = e & SMASK) >= ws.length || + (v = ws[i]) != null) + break; + long nc = (((long)(v.nextWait & E_MASK)) | + ((long)(u + UAC_UNIT) << 32)); + if (v.eventCount != (e | INT_SIGN)) + break; + if (U.compareAndSwapLong(this, CTL, c, nc)) { + v.eventCount = (e + E_SEQ) & E_MASK; + if ((p = v.parker) != null) + U.unpark(p); + break; + } + } + else { + if ((short)u < 0) + tryAddWorker(); + break; + } + } } - return true; + if (ex == null) // help clean refs on way out + ForkJoinTask.helpExpungeStaleExceptions(); + else // rethrow + ForkJoinTask.rethrow(ex); } - // Scanning for tasks + // Submissions /** - * Scans for and, if found, executes one task. Scans start at a - * random index of workers array, and randomly select the first - * (2*#workers)-1 probes, and then, if all empty, resort to 2 - * circular sweeps, which is necessary to check quiescence. and - * taking a submission only if no stealable tasks were found. The - * steal code inside the loop is a specialized form of - * ForkJoinWorkerThread.deqTask, followed bookkeeping to support - * helpJoinTask and signal propagation. The code for submission - * queues is almost identical. On each steal, the worker completes - * not only the task, but also all local tasks that this task may - * have generated. On detecting staleness or contention when - * trying to take a task, this method returns without finishing - * sweep, which allows global state rechecks before retry. - * - * @param w the worker - * @param a the number of active workers - * @return true if swept all queues without finding a task - */ - private boolean scan(ForkJoinWorkerThread w, int a) { - int g = scanGuard; // mask 0 avoids useless scans if only one active - int m = (parallelism == 1 - a && blockedCount == 0) ? 0 : g & SMASK; - ForkJoinWorkerThread[] ws = workers; - if (ws == null || ws.length <= m) // staleness check - return false; - for (int r = w.seed, k = r, j = -(m + m); j <= m + m; ++j) { - ForkJoinTask t; ForkJoinTask[] q; int b, i; - ForkJoinWorkerThread v = ws[k & m]; - if (v != null && (b = v.queueBase) != v.queueTop && - (q = v.queue) != null && (i = (q.length - 1) & b) >= 0) { - long u = (i << ASHIFT) + ABASE; - if ((t = q[i]) != null && v.queueBase == b && - UNSAFE.compareAndSwapObject(q, u, t, null)) { - int d = (v.queueBase = b + 1) - v.queueTop; - v.stealHint = w.poolIndex; - if (d != 0) - signalWork(); // propagate if nonempty - w.execTask(t); + * Unless shutting down, adds the given task to a submission queue + * at submitter's current queue index (modulo submission + * range). Only the most common path is directly handled in this + * method. All others are relayed to fullExternalPush. + * + * @param task the task. Caller must ensure non-null. + */ + final void externalPush(ForkJoinTask task) { + WorkQueue[] ws; WorkQueue q; Submitter z; int m; ForkJoinTask[] a; + if ((z = submitters.get()) != null && plock > 0 && + (ws = workQueues) != null && (m = (ws.length - 1)) >= 0 && + (q = ws[m & z.seed & SQMASK]) != null && + U.compareAndSwapInt(q, QLOCK, 0, 1)) { // lock + int b = q.base, s = q.top, n, an; + if ((a = q.array) != null && (an = a.length) > (n = s + 1 - b)) { + int j = (((an - 1) & s) << ASHIFT) + ABASE; + U.putOrderedObject(a, j, task); + q.top = s + 1; // push on to deque + q.qlock = 0; + if (n <= 2) + signalWork(q); + return; + } + q.qlock = 0; + } + fullExternalPush(task); + } + + /** + * Full version of externalPush. This method is called, among + * other times, upon the first submission of the first task to the + * pool, so must perform secondary initialization (via + * initWorkers). It also detects first submission by an external + * thread by looking up its ThreadLocal, and creates a new shared + * queue if the one at index if empty or contended. The plock lock + * body must be exception-free (so no try/finally) so we + * optimistically allocate new queues outside the lock and throw + * them away if (very rarely) not needed. + */ + private void fullExternalPush(ForkJoinTask task) { + int r = 0; // random index seed + for (Submitter z = submitters.get();;) { + WorkQueue[] ws; WorkQueue q; int ps, m, k; + if (z == null) { + if (U.compareAndSwapInt(this, INDEXSEED, r = indexSeed, + r += SEED_INCREMENT) && r != 0) + submitters.set(z = new Submitter(r)); + } + else if (r == 0) { // move to a different index + r = z.seed; + r ^= r << 13; // same xorshift as WorkQueues + r ^= r >>> 17; + z.seed = r ^ (r << 5); + } + else if ((ps = plock) < 0) + throw new RejectedExecutionException(); + else if (ps == 0 || (ws = workQueues) == null || + (m = ws.length - 1) < 0) + initWorkers(); + else if ((q = ws[k = r & m & SQMASK]) != null) { + if (q.qlock == 0 && U.compareAndSwapInt(q, QLOCK, 0, 1)) { + ForkJoinTask[] a = q.array; + int s = q.top; + boolean submitted = false; + try { // locked version of push + if ((a != null && a.length > s + 1 - q.base) || + (a = q.growArray()) != null) { // must presize + int j = (((a.length - 1) & s) << ASHIFT) + ABASE; + U.putOrderedObject(a, j, task); + q.top = s + 1; + submitted = true; + } + } finally { + q.qlock = 0; // unlock + } + if (submitted) { + signalWork(q); + return; + } } - r ^= r << 13; r ^= r >>> 17; w.seed = r ^ (r << 5); - return false; // store next seed + r = 0; // move on failure } - else if (j < 0) { // xorshift - r ^= r << 13; r ^= r >>> 17; k = r ^= r << 5; + else if (((ps = plock) & PL_LOCK) == 0) { // create new queue + q = new WorkQueue(this, null, SHARED_QUEUE, r); + if (((ps = plock) & PL_LOCK) != 0 || + !U.compareAndSwapInt(this, PLOCK, ps, ps += PL_LOCK)) + ps = acquirePlock(); + if ((ws = workQueues) != null && k < ws.length && ws[k] == null) + ws[k] = q; + int nps = (ps & SHUTDOWN) | ((ps + PL_LOCK) & ~SHUTDOWN); + if (!U.compareAndSwapInt(this, PLOCK, ps, nps)) + releasePlock(nps); } else - ++k; + r = 0; // try elsewhere while lock held } - if (scanGuard != g) // staleness check - return false; - else { // try to take submission - ForkJoinTask t; ForkJoinTask[] q; int b, i; - if ((b = queueBase) != queueTop && - (q = submissionQueue) != null && - (i = (q.length - 1) & b) >= 0) { - long u = (i << ASHIFT) + ABASE; - if ((t = q[i]) != null && queueBase == b && - UNSAFE.compareAndSwapObject(q, u, t, null)) { - queueBase = b + 1; - w.execTask(t); + } + + // Maintaining ctl counts + + /** + * Increments active count; mainly called upon return from blocking. + */ + final void incrementActiveCount() { + long c; + do {} while (!U.compareAndSwapLong(this, CTL, c = ctl, c + AC_UNIT)); + } + + /** + * Tries to create or activate a worker if too few are active. + * + * @param q the (non-null) queue holding tasks to be signalled + */ + final void signalWork(WorkQueue q) { + int hint = q.poolIndex; + long c; int e, u, i, n; WorkQueue[] ws; WorkQueue w; Thread p; + while ((u = (int)((c = ctl) >>> 32)) < 0) { + if ((e = (int)c) > 0) { + if ((ws = workQueues) != null && ws.length > (i = e & SMASK) && + (w = ws[i]) != null && w.eventCount == (e | INT_SIGN)) { + long nc = (((long)(w.nextWait & E_MASK)) | + ((long)(u + UAC_UNIT) << 32)); + if (U.compareAndSwapLong(this, CTL, c, nc)) { + w.hint = hint; + w.eventCount = (e + E_SEQ) & E_MASK; + if ((p = w.parker) != null) + U.unpark(p); + break; + } + if (q.top - q.base <= 0) + break; } - return false; + else + break; + } + else { + if ((short)u < 0) + tryAddWorker(); + break; } - return true; // all queues empty } } + // Scanning for tasks + + /** + * Top-level runloop for workers, called by ForkJoinWorkerThread.run. + */ + final void runWorker(WorkQueue w) { + w.growArray(); // allocate queue + do { w.runTask(scan(w)); } while (w.qlock >= 0); + } + /** - * Tries to enqueue worker w in wait queue and await change in - * worker's eventCount. If the pool is quiescent and there is - * more than one worker, possibly terminates worker upon exit. - * Otherwise, before blocking, rescans queues to avoid missed - * signals. Upon finding work, releases at least one worker - * (which may be the current worker). Rescans restart upon - * detected staleness or failure to release due to - * contention. Note the unusual conventions about Thread.interrupt - * here and elsewhere: Because interrupts are used solely to alert - * threads to check termination, which is checked here anyway, we - * clear status (using Thread.interrupted) before any call to - * park, so that park does not immediately return due to status - * being set via some other unrelated call to interrupt in user - * code. + * Scans for and, if found, returns one task, else possibly + * inactivates the worker. This method operates on single reads of + * volatile state and is designed to be re-invoked continuously, + * in part because it returns upon detecting inconsistencies, + * contention, or state changes that indicate possible success on + * re-invocation. * - * @param w the calling worker - * @param c the ctl value on entry - * @return true if waited or another thread was released upon enq - */ - private boolean tryAwaitWork(ForkJoinWorkerThread w, long c) { - int v = w.eventCount; - w.nextWait = (int)c; // w's successor record - long nc = (long)(v & E_MASK) | ((c - AC_UNIT) & (AC_MASK|TC_MASK)); - if (ctl != c || !UNSAFE.compareAndSwapLong(this, ctlOffset, c, nc)) { - long d = ctl; // return true if lost to a deq, to force scan - return (int)d != (int)c && (d & AC_MASK) >= (c & AC_MASK); - } - for (int sc = w.stealCount; sc != 0;) { // accumulate stealCount - long s = stealCount; - if (UNSAFE.compareAndSwapLong(this, stealCountOffset, s, s + sc)) - sc = w.stealCount = 0; - else if (w.eventCount != v) - return true; // update next time - } - if ((!shutdown || !tryTerminate(false)) && - (int)c != 0 && parallelism + (int)(nc >> AC_SHIFT) == 0 && - blockedCount == 0 && quiescerCount == 0) - idleAwaitWork(w, nc, c, v); // quiescent - for (boolean rescanned = false;;) { - if (w.eventCount != v) - return true; - if (!rescanned) { - int g = scanGuard, m = g & SMASK; - ForkJoinWorkerThread[] ws = workers; - if (ws != null && m < ws.length) { - rescanned = true; - for (int i = 0; i <= m; ++i) { - ForkJoinWorkerThread u = ws[i]; - if (u != null) { - if (u.queueBase != u.queueTop && - !tryReleaseWaiter()) - rescanned = false; // contended - if (w.eventCount != v) - return true; - } + * The scan searches for tasks across queues (starting at a random + * index, and relying on registerWorker to irregularly scatter + * them within array to avoid bias), checking each at least twice. + * The scan terminates upon either finding a non-empty queue, or + * completing the sweep. If the worker is not inactivated, it + * takes and returns a task from this queue. Otherwise, if not + * activated, it signals workers (that may include itself) and + * returns so caller can retry. Also returns for true if the + * worker array may have changed during an empty scan. On failure + * to find a task, we take one of the following actions, after + * which the caller will retry calling this method unless + * terminated. + * + * * If pool is terminating, terminate the worker. + * + * * If not already enqueued, try to inactivate and enqueue the + * worker on wait queue. Or, if inactivating has caused the pool + * to be quiescent, relay to idleAwaitWork to possibly shrink + * pool. + * + * * If already enqueued and none of the above apply, possibly + * park awaiting signal, else lingering to help scan and signal. + * + * * If a non-empty queue discovered or left as a hint, + * help wake up other workers before return. + * + * @param w the worker (via its WorkQueue) + * @return a task or null if none found + */ + private final ForkJoinTask scan(WorkQueue w) { + WorkQueue[] ws; int m; + int ps = plock; // read plock before ws + if (w != null && (ws = workQueues) != null && (m = ws.length - 1) >= 0) { + int ec = w.eventCount; // ec is negative if inactive + int r = w.seed; r ^= r << 13; r ^= r >>> 17; w.seed = r ^= r << 5; + w.hint = -1; // update seed and clear hint + int j = ((m + m + 1) | MIN_SCAN) & MAX_SCAN; + do { + WorkQueue q; ForkJoinTask[] a; int b; + if ((q = ws[(r + j) & m]) != null && (b = q.base) - q.top < 0 && + (a = q.array) != null) { // probably nonempty + int i = (((a.length - 1) & b) << ASHIFT) + ABASE; + ForkJoinTask t = (ForkJoinTask) + U.getObjectVolatile(a, i); + if (q.base == b && ec >= 0 && t != null && + U.compareAndSwapObject(a, i, t, null)) { + if ((q.base = b + 1) - q.top < 0) + signalWork(q); + return t; // taken + } + else if ((ec < 0 || j < m) && (int)(ctl >> AC_SHIFT) <= 0) { + w.hint = (r + j) & m; // help signal below + break; // cannot take } } - if (scanGuard != g || // stale - (queueBase != queueTop && !tryReleaseWaiter())) - rescanned = false; - if (!rescanned) - Thread.yield(); // reduce contention - else - Thread.interrupted(); // clear before park + } while (--j >= 0); + + int h, e, ns; long c, sc; WorkQueue q; + if ((ns = w.nsteals) != 0) { + if (U.compareAndSwapLong(this, STEALCOUNT, + sc = stealCount, sc + ns)) + w.nsteals = 0; // collect steals and rescan } + else if (plock != ps) // consistency check + ; // skip + else if ((e = (int)(c = ctl)) < 0) + w.qlock = -1; // pool is terminating else { - w.parked = true; // must recheck - if (w.eventCount != v) { - w.parked = false; - return true; + if ((h = w.hint) < 0) { + if (ec >= 0) { // try to enqueue/inactivate + long nc = (((long)ec | + ((c - AC_UNIT) & (AC_MASK|TC_MASK)))); + w.nextWait = e; // link and mark inactive + w.eventCount = ec | INT_SIGN; + if (ctl != c || !U.compareAndSwapLong(this, CTL, c, nc)) + w.eventCount = ec; // unmark on CAS failure + else if ((int)(c >> AC_SHIFT) == 1 - (config & SMASK)) + idleAwaitWork(w, nc, c); + } + else if (w.eventCount < 0 && !tryTerminate(false, false) && + ctl == c) { // block + Thread wt = Thread.currentThread(); + Thread.interrupted(); // clear status + U.putObject(wt, PARKBLOCKER, this); + w.parker = wt; // emulate LockSupport.park + if (w.eventCount < 0) // recheck + U.park(false, 0L); + w.parker = null; + U.putObject(wt, PARKBLOCKER, null); + } + } + if ((h >= 0 || (h = w.hint) >= 0) && + (ws = workQueues) != null && h < ws.length && + (q = ws[h]) != null) { // signal others before retry + WorkQueue v; Thread p; int u, i, s; + for (int n = (config & SMASK) >>> 1;;) { + int idleCount = (w.eventCount < 0) ? 0 : -1; + if (((s = idleCount - q.base + q.top) <= n && + (n = s) <= 0) || + (u = (int)((c = ctl) >>> 32)) >= 0 || + (e = (int)c) <= 0 || m < (i = e & SMASK) || + (v = ws[i]) == null) + break; + long nc = (((long)(v.nextWait & E_MASK)) | + ((long)(u + UAC_UNIT) << 32)); + if (v.eventCount != (e | INT_SIGN) || + !U.compareAndSwapLong(this, CTL, c, nc)) + break; + v.hint = h; + v.eventCount = (e + E_SEQ) & E_MASK; + if ((p = v.parker) != null) + U.unpark(p); + if (--n <= 0) + break; + } } - LockSupport.park(this); - rescanned = w.parked = false; } } + return null; } /** - * If inactivating worker w has caused pool to become - * quiescent, check for pool termination, and wait for event - * for up to SHRINK_RATE nanosecs (rescans are unnecessary in - * this case because quiescence reflects consensus about lack - * of work). On timeout, if ctl has not changed, terminate the - * worker. Upon its termination (see deregisterWorker), it may - * wake up another worker to possibly repeat this process. + * If inactivating worker w has caused the pool to become + * quiescent, checks for pool termination, and, so long as this is + * not the only worker, waits for event for up to a given + * duration. On timeout, if ctl has not changed, terminates the + * worker, which will in turn wake up another worker to possibly + * repeat this process. * * @param w the calling worker - * @param currentCtl the ctl value after enqueuing w - * @param prevCtl the ctl value if w terminated - * @param v the eventCount w awaits change - */ - private void idleAwaitWork(ForkJoinWorkerThread w, long currentCtl, - long prevCtl, int v) { - if (w.eventCount == v) { - if (shutdown) - tryTerminate(false); - ForkJoinTask.helpExpungeStaleExceptions(); // help clean weak refs + * @param currentCtl the ctl value triggering possible quiescence + * @param prevCtl the ctl value to restore if thread is terminated + */ + private void idleAwaitWork(WorkQueue w, long currentCtl, long prevCtl) { + if (w != null && w.eventCount < 0 && + !tryTerminate(false, false) && (int)prevCtl != 0) { + int dc = -(short)(currentCtl >>> TC_SHIFT); + long parkTime = dc < 0 ? FAST_IDLE_TIMEOUT: (dc + 1) * IDLE_TIMEOUT; + long deadline = System.nanoTime() + parkTime - TIMEOUT_SLOP; + Thread wt = Thread.currentThread(); while (ctl == currentCtl) { - long startTime = System.nanoTime(); - w.parked = true; - if (w.eventCount == v) // must recheck - LockSupport.parkNanos(this, SHRINK_RATE); - w.parked = false; - if (w.eventCount != v) + Thread.interrupted(); // timed variant of version in scan() + U.putObject(wt, PARKBLOCKER, this); + w.parker = wt; + if (ctl == currentCtl) + U.park(false, parkTime); + w.parker = null; + U.putObject(wt, PARKBLOCKER, null); + if (ctl != currentCtl) break; - else if (System.nanoTime() - startTime < - SHRINK_RATE - (SHRINK_RATE / 10)) // timing slop - Thread.interrupted(); // spurious wakeup - else if (UNSAFE.compareAndSwapLong(this, ctlOffset, - currentCtl, prevCtl)) { - w.terminate = true; // restore previous - w.eventCount = ((int)currentCtl + EC_UNIT) & E_MASK; + if (deadline - System.nanoTime() <= 0L && + U.compareAndSwapLong(this, CTL, currentCtl, prevCtl)) { + w.eventCount = (w.eventCount + E_SEQ) | E_MASK; + w.qlock = -1; // shrink break; } } } } - // Submissions - /** - * Enqueues the given task in the submissionQueue. Same idea as - * ForkJoinWorkerThread.pushTask except for use of submissionLock. + * Scans through queues looking for work while joining a task; if + * any present, signals. May return early if more signalling is + * detectably unneeded. * - * @param t the task + * @param task return early if done + * @param origin an index to start scan */ - private void addSubmission(ForkJoinTask t) { - final ReentrantLock lock = this.submissionLock; - lock.lock(); - try { - ForkJoinTask[] q; int s, m; - if ((q = submissionQueue) != null) { // ignore if queue removed - long u = (((s = queueTop) & (m = q.length-1)) << ASHIFT)+ABASE; - UNSAFE.putOrderedObject(q, u, t); - queueTop = s + 1; - if (s - queueBase == m) - growSubmissionQueue(); - } - } finally { - lock.unlock(); - } - signalWork(); - } - - // (pollSubmission is defined below with exported methods) - - /** - * Creates or doubles submissionQueue array. - * Basically identical to ForkJoinWorkerThread version. - */ - private void growSubmissionQueue() { - ForkJoinTask[] oldQ = submissionQueue; - int size = oldQ != null ? oldQ.length << 1 : INITIAL_QUEUE_CAPACITY; - if (size > MAXIMUM_QUEUE_CAPACITY) - throw new RejectedExecutionException("Queue capacity exceeded"); - if (size < INITIAL_QUEUE_CAPACITY) - size = INITIAL_QUEUE_CAPACITY; - ForkJoinTask[] q = submissionQueue = new ForkJoinTask[size]; - int mask = size - 1; - int top = queueTop; - int oldMask; - if (oldQ != null && (oldMask = oldQ.length - 1) >= 0) { - for (int b = queueBase; b != top; ++b) { - long u = ((b & oldMask) << ASHIFT) + ABASE; - Object x = UNSAFE.getObjectVolatile(oldQ, u); - if (x != null && UNSAFE.compareAndSwapObject(oldQ, u, x, null)) - UNSAFE.putObjectVolatile - (q, ((b & mask) << ASHIFT) + ABASE, x); + private void helpSignal(ForkJoinTask task, int origin) { + WorkQueue[] ws; WorkQueue w; Thread p; long c; int m, u, e, i, s; + if (task != null && task.status >= 0 && + (u = (int)(ctl >>> 32)) < 0 && (u >> UAC_SHIFT) < 0 && + (ws = workQueues) != null && (m = ws.length - 1) >= 0) { + outer: for (int k = origin, j = m; j >= 0; --j) { + WorkQueue q = ws[k++ & m]; + for (int n = m;;) { // limit to at most m signals + if (task.status < 0) + break outer; + if (q == null || + ((s = -q.base + q.top) <= n && (n = s) <= 0)) + break; + if ((u = (int)((c = ctl) >>> 32)) >= 0 || + (e = (int)c) <= 0 || m < (i = e & SMASK) || + (w = ws[i]) == null) + break outer; + long nc = (((long)(w.nextWait & E_MASK)) | + ((long)(u + UAC_UNIT) << 32)); + if (w.eventCount != (e | INT_SIGN)) + break outer; + if (U.compareAndSwapLong(this, CTL, c, nc)) { + w.eventCount = (e + E_SEQ) & E_MASK; + if ((p = w.parker) != null) + U.unpark(p); + if (--n <= 0) + break; + } + } } } } - // Blocking support - /** - * Tries to increment blockedCount, decrement active count - * (sometimes implicitly) and possibly release or create a - * compensating worker in preparation for blocking. Fails - * on contention or termination. - * - * @return true if the caller can block, else should recheck and retry - */ - private boolean tryPreBlock() { - int b = blockedCount; - if (UNSAFE.compareAndSwapInt(this, blockedCountOffset, b, b + 1)) { - int pc = parallelism; - do { - ForkJoinWorkerThread[] ws; ForkJoinWorkerThread w; - int e, ac, tc, i; - long c = ctl; - int u = (int)(c >>> 32); - if ((e = (int)c) < 0) { - // skip -- terminating - } - else if ((ac = (u >> UAC_SHIFT)) <= 0 && e != 0 && - (ws = workers) != null && - (i = ~e & SMASK) < ws.length && - (w = ws[i]) != null) { - long nc = ((long)(w.nextWait & E_MASK) | - (c & (AC_MASK|TC_MASK))); - if (w.eventCount == e && - UNSAFE.compareAndSwapLong(this, ctlOffset, c, nc)) { - w.eventCount = (e + EC_UNIT) & E_MASK; - if (w.parked) - UNSAFE.unpark(w); - return true; // release an idle worker + * Tries to locate and execute tasks for a stealer of the given + * task, or in turn one of its stealers, Traces currentSteal -> + * currentJoin links looking for a thread working on a descendant + * of the given task and with a non-empty queue to steal back and + * execute tasks from. The first call to this method upon a + * waiting join will often entail scanning/search, (which is OK + * because the joiner has nothing better to do), but this method + * leaves hints in workers to speed up subsequent calls. The + * implementation is very branchy to cope with potential + * inconsistencies or loops encountering chains that are stale, + * unknown, or so long that they are likely cyclic. + * + * @param joiner the joining worker + * @param task the task to join + * @return 0 if no progress can be made, negative if task + * known complete, else positive + */ + private int tryHelpStealer(WorkQueue joiner, ForkJoinTask task) { + int stat = 0, steps = 0; // bound to avoid cycles + if (joiner != null && task != null) { // hoist null checks + restart: for (;;) { + ForkJoinTask subtask = task; // current target + for (WorkQueue j = joiner, v;;) { // v is stealer of subtask + WorkQueue[] ws; int m, s, h; + if ((s = task.status) < 0) { + stat = s; + break restart; } - } - else if ((tc = (short)(u >>> UTC_SHIFT)) >= 0 && ac + pc > 1) { - long nc = ((c - AC_UNIT) & AC_MASK) | (c & ~AC_MASK); - if (UNSAFE.compareAndSwapLong(this, ctlOffset, c, nc)) - return true; // no compensation needed - } - else if (tc + pc < MAX_ID) { - long nc = ((c + TC_UNIT) & TC_MASK) | (c & ~TC_MASK); - if (UNSAFE.compareAndSwapLong(this, ctlOffset, c, nc)) { - addWorker(); - return true; // create a replacement + if ((ws = workQueues) == null || (m = ws.length - 1) <= 0) + break restart; // shutting down + if ((v = ws[h = (j.hint | 1) & m]) == null || + v.currentSteal != subtask) { + for (int origin = h;;) { // find stealer + if (((h = (h + 2) & m) & 15) == 1 && + (subtask.status < 0 || j.currentJoin != subtask)) + continue restart; // occasional staleness check + if ((v = ws[h]) != null && + v.currentSteal == subtask) { + j.hint = h; // save hint + break; + } + if (h == origin) + break restart; // cannot find stealer + } + } + for (;;) { // help stealer or descend to its stealer + ForkJoinTask[] a; int b; + if (subtask.status < 0) // surround probes with + continue restart; // consistency checks + if ((b = v.base) - v.top < 0 && (a = v.array) != null) { + int i = (((a.length - 1) & b) << ASHIFT) + ABASE; + ForkJoinTask t = + (ForkJoinTask)U.getObjectVolatile(a, i); + if (subtask.status < 0 || j.currentJoin != subtask || + v.currentSteal != subtask) + continue restart; // stale + stat = 1; // apparent progress + if (t != null && v.base == b && + U.compareAndSwapObject(a, i, t, null)) { + v.base = b + 1; // help stealer + joiner.runSubtask(t); + } + else if (v.base == b && ++steps == MAX_HELP) + break restart; // v apparently stalled + } + else { // empty -- try to descend + ForkJoinTask next = v.currentJoin; + if (subtask.status < 0 || j.currentJoin != subtask || + v.currentSteal != subtask) + continue restart; // stale + else if (next == null || ++steps == MAX_HELP) + break restart; // dead-end or maybe cyclic + else { + subtask = next; + j = v; + break; + } + } } } - // try to back out on any failure and let caller retry - } while (!UNSAFE.compareAndSwapInt(this, blockedCountOffset, - b = blockedCount, b - 1)); + } } - return false; - } - - /** - * Decrements blockedCount and increments active count. - */ - private void postBlock() { - long c; - do {} while (!UNSAFE.compareAndSwapLong(this, ctlOffset, // no mask - c = ctl, c + AC_UNIT)); - int b; - do {} while (!UNSAFE.compareAndSwapInt(this, blockedCountOffset, - b = blockedCount, b - 1)); + return stat; } /** - * Possibly blocks waiting for the given task to complete, or - * cancels the task if terminating. Fails to wait if contended. + * Analog of tryHelpStealer for CountedCompleters. Tries to steal + * and run tasks within the target's computation. * - * @param joinMe the task + * @param task the task to join + * @param mode if shared, exit upon completing any task + * if all workers are active */ - final void tryAwaitJoin(ForkJoinTask joinMe) { - Thread.interrupted(); // clear interrupts before checking termination - if (joinMe.status >= 0) { - if (tryPreBlock()) { - joinMe.tryAwaitDone(0L); - postBlock(); + private int helpComplete(ForkJoinTask task, int mode) { + WorkQueue[] ws; WorkQueue q; int m, n, s, u; + if (task != null && (ws = workQueues) != null && + (m = ws.length - 1) >= 0) { + for (int j = 1, origin = j;;) { + if ((s = task.status) < 0) + return s; + if ((q = ws[j & m]) != null && q.pollAndExecCC(task)) { + origin = j; + if (mode == SHARED_QUEUE && + ((u = (int)(ctl >>> 32)) >= 0 || (u >> UAC_SHIFT) >= 0)) + break; + } + else if ((j = (j + 2) & m) == origin) + break; + } + } + return 0; + } + + /** + * Tries to decrement active count (sometimes implicitly) and + * possibly release or create a compensating worker in preparation + * for blocking. Fails on contention or termination. Otherwise, + * adds a new thread if no idle workers are available and pool + * may become starved. + */ + final boolean tryCompensate() { + int pc = config & SMASK, e, i, tc; long c; + WorkQueue[] ws; WorkQueue w; Thread p; + if ((ws = workQueues) != null && (e = (int)(c = ctl)) >= 0) { + if (e != 0 && (i = e & SMASK) < ws.length && + (w = ws[i]) != null && w.eventCount == (e | INT_SIGN)) { + long nc = ((long)(w.nextWait & E_MASK) | + (c & (AC_MASK|TC_MASK))); + if (U.compareAndSwapLong(this, CTL, c, nc)) { + w.eventCount = (e + E_SEQ) & E_MASK; + if ((p = w.parker) != null) + U.unpark(p); + return true; // replace with idle worker + } + } + else if ((tc = (short)(c >>> TC_SHIFT)) >= 0 && + (int)(c >> AC_SHIFT) + pc > 1) { + long nc = ((c - AC_UNIT) & AC_MASK) | (c & ~AC_MASK); + if (U.compareAndSwapLong(this, CTL, c, nc)) + return true; // no compensation + } + else if (tc + pc < MAX_CAP) { + long nc = ((c + TC_UNIT) & TC_MASK) | (c & ~TC_MASK); + if (U.compareAndSwapLong(this, CTL, c, nc)) { + ForkJoinWorkerThreadFactory fac; + Throwable ex = null; + ForkJoinWorkerThread wt = null; + try { + if ((fac = factory) != null && + (wt = fac.newThread(this)) != null) { + wt.start(); + return true; + } + } catch (Throwable rex) { + ex = rex; + } + deregisterWorker(wt, ex); // clean up and return false + } } - else if ((ctl & STOP_BIT) != 0L) - joinMe.cancelIgnoringExceptions(); } + return false; } /** - * Possibly blocks the given worker waiting for joinMe to - * complete or timeout. + * Helps and/or blocks until the given task is done. * - * @param joinMe the task - * @param nanos the wait time for underlying Object.wait - */ - final void timedAwaitJoin(ForkJoinTask joinMe, long nanos) { - while (joinMe.status >= 0) { - Thread.interrupted(); - if ((ctl & STOP_BIT) != 0L) { - joinMe.cancelIgnoringExceptions(); - break; + * @param joiner the joining worker + * @param task the task + * @return task status on exit + */ + final int awaitJoin(WorkQueue joiner, ForkJoinTask task) { + int s = 0; + if (joiner != null && task != null && (s = task.status) >= 0) { + ForkJoinTask prevJoin = joiner.currentJoin; + joiner.currentJoin = task; + do {} while ((s = task.status) >= 0 && !joiner.isEmpty() && + joiner.tryRemoveAndExec(task)); // process local tasks + if (s >= 0 && (s = task.status) >= 0) { + helpSignal(task, joiner.poolIndex); + if ((s = task.status) >= 0 && + (task instanceof CountedCompleter)) + s = helpComplete(task, LIFO_QUEUE); } - if (tryPreBlock()) { - long last = System.nanoTime(); - while (joinMe.status >= 0) { - long millis = TimeUnit.NANOSECONDS.toMillis(nanos); - if (millis <= 0) - break; - joinMe.tryAwaitDone(millis); - if (joinMe.status < 0) - break; - if ((ctl & STOP_BIT) != 0L) { - joinMe.cancelIgnoringExceptions(); - break; + while (s >= 0 && (s = task.status) >= 0) { + if ((!joiner.isEmpty() || // try helping + (s = tryHelpStealer(joiner, task)) == 0) && + (s = task.status) >= 0) { + helpSignal(task, joiner.poolIndex); + if ((s = task.status) >= 0 && tryCompensate()) { + if (task.trySetSignal() && (s = task.status) >= 0) { + synchronized (task) { + if (task.status >= 0) { + try { // see ForkJoinTask + task.wait(); // for explanation + } catch (InterruptedException ie) { + } + } + else + task.notifyAll(); + } + } + long c; // re-activate + do {} while (!U.compareAndSwapLong + (this, CTL, c = ctl, c + AC_UNIT)); } - long now = System.nanoTime(); - nanos -= now - last; - last = now; } - postBlock(); - break; } + joiner.currentJoin = prevJoin; } + return s; } /** - * If necessary, compensates for blocker, and blocks. + * Stripped-down variant of awaitJoin used by timed joins. Tries + * to help join only while there is continuous progress. (Caller + * will then enter a timed wait.) + * + * @param joiner the joining worker + * @param task the task */ - private void awaitBlocker(ManagedBlocker blocker) - throws InterruptedException { - while (!blocker.isReleasable()) { - if (tryPreBlock()) { - try { - do {} while (!blocker.isReleasable() && !blocker.block()); - } finally { - postBlock(); - } - break; + final void helpJoinOnce(WorkQueue joiner, ForkJoinTask task) { + int s; + if (joiner != null && task != null && (s = task.status) >= 0) { + ForkJoinTask prevJoin = joiner.currentJoin; + joiner.currentJoin = task; + do {} while ((s = task.status) >= 0 && !joiner.isEmpty() && + joiner.tryRemoveAndExec(task)); + if (s >= 0 && (s = task.status) >= 0) { + helpSignal(task, joiner.poolIndex); + if ((s = task.status) >= 0 && + (task instanceof CountedCompleter)) + s = helpComplete(task, LIFO_QUEUE); } + if (s >= 0 && joiner.isEmpty()) { + do {} while (task.status >= 0 && + tryHelpStealer(joiner, task) > 0); + } + joiner.currentJoin = prevJoin; } } - // Creating, registering and deregistring workers - /** - * Tries to create and start a worker; minimally rolls back counts - * on failure. - */ - private void addWorker() { - Throwable ex = null; - ForkJoinWorkerThread t = null; - try { - t = factory.newThread(this); - } catch (Throwable e) { - ex = e; - } - if (t == null) { // null or exceptional factory return - long c; // adjust counts - do {} while (!UNSAFE.compareAndSwapLong - (this, ctlOffset, c = ctl, - (((c - AC_UNIT) & AC_MASK) | - ((c - TC_UNIT) & TC_MASK) | - (c & ~(AC_MASK|TC_MASK))))); - // Propagate exception if originating from an external caller - if (!tryTerminate(false) && ex != null && - !(Thread.currentThread() instanceof ForkJoinWorkerThread)) - SneakyThrow.sneakyThrow(ex); // android-changed + * Returns a (probably) non-empty steal queue, if one is found + * during a random, then cyclic scan, else null. This method must + * be retried by caller if, by the time it tries to use the queue, + * it is empty. + * @param r a (random) seed for scanning + */ + private WorkQueue findNonEmptyStealQueue(int r) { + for (WorkQueue[] ws;;) { + int ps = plock, m, n; + if ((ws = workQueues) == null || (m = ws.length - 1) < 1) + return null; + for (int j = (m + 1) << 2; ;) { + WorkQueue q = ws[(((r + j) << 1) | 1) & m]; + if (q != null && (n = q.base - q.top) < 0) { + if (n < -1) + signalWork(q); + return q; + } + else if (--j < 0) { + if (plock == ps) + return null; + break; + } + } } - else - t.start(); } /** - * Callback from ForkJoinWorkerThread constructor to assign a - * public name - */ - final String nextWorkerName() { - for (int n;;) { - if (UNSAFE.compareAndSwapInt(this, nextWorkerNumberOffset, - n = nextWorkerNumber, ++n)) - return workerNamePrefix + n; + * Runs tasks until {@code isQuiescent()}. We piggyback on + * active count ctl maintenance, but rather than blocking + * when tasks cannot be found, we rescan until all others cannot + * find tasks either. + */ + final void helpQuiescePool(WorkQueue w) { + for (boolean active = true;;) { + ForkJoinTask localTask; // exhaust local queue + while ((localTask = w.nextLocalTask()) != null) + localTask.doExec(); + // Similar to loop in scan(), but ignoring submissions + WorkQueue q = findNonEmptyStealQueue(w.nextSeed()); + if (q != null) { + ForkJoinTask t; int b; + if (!active) { // re-establish active count + long c; + active = true; + do {} while (!U.compareAndSwapLong + (this, CTL, c = ctl, c + AC_UNIT)); + } + if ((b = q.base) - q.top < 0 && (t = q.pollAt(b)) != null) + w.runSubtask(t); + } + else { + long c; + if (active) { // decrement active count without queuing + active = false; + do {} while (!U.compareAndSwapLong + (this, CTL, c = ctl, c -= AC_UNIT)); + } + else + c = ctl; // re-increment on exit + if ((int)(c >> AC_SHIFT) + (config & SMASK) == 0) { + do {} while (!U.compareAndSwapLong + (this, CTL, c = ctl, c + AC_UNIT)); + break; + } + } } } /** - * Callback from ForkJoinWorkerThread constructor to - * determine its poolIndex and record in workers array. + * Gets and removes a local or stolen task for the given worker. * - * @param w the worker - * @return the worker's pool index + * @return a task, if available */ - final int registerWorker(ForkJoinWorkerThread w) { - /* - * In the typical case, a new worker acquires the lock, uses - * next available index and returns quickly. Since we should - * not block callers (ultimately from signalWork or - * tryPreBlock) waiting for the lock needed to do this, we - * instead help release other workers while waiting for the - * lock. - */ - for (int g;;) { - ForkJoinWorkerThread[] ws; - if (((g = scanGuard) & SG_UNIT) == 0 && - UNSAFE.compareAndSwapInt(this, scanGuardOffset, - g, g | SG_UNIT)) { - int k = nextWorkerIndex; - try { - if ((ws = workers) != null) { // ignore on shutdown - int n = ws.length; - if (k < 0 || k >= n || ws[k] != null) { - for (k = 0; k < n && ws[k] != null; ++k) - ; - if (k == n) - ws = workers = Arrays.copyOf(ws, n << 1); - } - ws[k] = w; - nextWorkerIndex = k + 1; - int m = g & SMASK; - g = (k > m) ? ((m << 1) + 1) & SMASK : g + (SG_UNIT<<1); - } - } finally { - scanGuard = g; - } - return k; - } - else if ((ws = workers) != null) { // help release others - for (ForkJoinWorkerThread u : ws) { - if (u != null && u.queueBase != u.queueTop) { - if (tryReleaseWaiter()) - break; - } - } - } + final ForkJoinTask nextTaskFor(WorkQueue w) { + for (ForkJoinTask t;;) { + WorkQueue q; int b; + if ((t = w.nextLocalTask()) != null) + return t; + if ((q = findNonEmptyStealQueue(w.nextSeed())) == null) + return null; + if ((b = q.base) - q.top < 0 && (t = q.pollAt(b)) != null) + return t; } } /** - * Final callback from terminating worker. Removes record of - * worker from array, and adjusts counts. If pool is shutting - * down, tries to complete termination. - * - * @param w the worker - */ - final void deregisterWorker(ForkJoinWorkerThread w, Throwable ex) { - int idx = w.poolIndex; - int sc = w.stealCount; - int steps = 0; - // Remove from array, adjust worker counts and collect steal count. - // We can intermix failed removes or adjusts with steal updates - do { - long s, c; - int g; - if (steps == 0 && ((g = scanGuard) & SG_UNIT) == 0 && - UNSAFE.compareAndSwapInt(this, scanGuardOffset, - g, g |= SG_UNIT)) { - ForkJoinWorkerThread[] ws = workers; - if (ws != null && idx >= 0 && - idx < ws.length && ws[idx] == w) - ws[idx] = null; // verify - nextWorkerIndex = idx; - scanGuard = g + SG_UNIT; - steps = 1; - } - if (steps == 1 && - UNSAFE.compareAndSwapLong(this, ctlOffset, c = ctl, - (((c - AC_UNIT) & AC_MASK) | - ((c - TC_UNIT) & TC_MASK) | - (c & ~(AC_MASK|TC_MASK))))) - steps = 2; - if (sc != 0 && - UNSAFE.compareAndSwapLong(this, stealCountOffset, - s = stealCount, s + sc)) - sc = 0; - } while (steps != 2 || sc != 0); - if (!tryTerminate(false)) { - if (ex != null) // possibly replace if died abnormally - signalWork(); - else - tryReleaseWaiter(); + * Returns a cheap heuristic guide for task partitioning when + * programmers, frameworks, tools, or languages have little or no + * idea about task granularity. In essence by offering this + * method, we ask users only about tradeoffs in overhead vs + * expected throughput and its variance, rather than how finely to + * partition tasks. + * + * In a steady state strict (tree-structured) computation, each + * thread makes available for stealing enough tasks for other + * threads to remain active. Inductively, if all threads play by + * the same rules, each thread should make available only a + * constant number of tasks. + * + * The minimum useful constant is just 1. But using a value of 1 + * would require immediate replenishment upon each steal to + * maintain enough tasks, which is infeasible. Further, + * partitionings/granularities of offered tasks should minimize + * steal rates, which in general means that threads nearer the top + * of computation tree should generate more than those nearer the + * bottom. In perfect steady state, each thread is at + * approximately the same level of computation tree. However, + * producing extra tasks amortizes the uncertainty of progress and + * diffusion assumptions. + * + * So, users will want to use values larger (but not much larger) + * than 1 to both smooth over transient shortages and hedge + * against uneven progress; as traded off against the cost of + * extra task overhead. We leave the user to pick a threshold + * value to compare with the results of this call to guide + * decisions, but recommend values such as 3. + * + * When all threads are active, it is on average OK to estimate + * surplus strictly locally. In steady-state, if one thread is + * maintaining say 2 surplus tasks, then so are others. So we can + * just use estimated queue length. However, this strategy alone + * leads to serious mis-estimates in some non-steady-state + * conditions (ramp-up, ramp-down, other stalls). We can detect + * many of these by further considering the number of "idle" + * threads, that are known to have zero queued tasks, so + * compensate by a factor of (#idle/#active) threads. + * + * Note: The approximation of #busy workers as #active workers is + * not very good under current signalling scheme, and should be + * improved. + */ + static int getSurplusQueuedTaskCount() { + Thread t; ForkJoinWorkerThread wt; ForkJoinPool pool; WorkQueue q; + if (((t = Thread.currentThread()) instanceof ForkJoinWorkerThread)) { + int p = (pool = (wt = (ForkJoinWorkerThread)t).pool).config & SMASK; + int n = (q = wt.workQueue).top - q.base; + int a = (int)(pool.ctl >> AC_SHIFT) + p; + return n - (a > (p >>>= 1) ? 0 : + a > (p >>>= 1) ? 1 : + a > (p >>>= 1) ? 2 : + a > (p >>>= 1) ? 4 : + 8); } + return 0; } - // Shutdown and termination + // Termination /** - * Possibly initiates and/or completes termination. + * Possibly initiates and/or completes termination. The caller + * triggering termination runs three passes through workQueues: + * (0) Setting termination status, followed by wakeups of queued + * workers; (1) cancelling all tasks; (2) interrupting lagging + * threads (likely in external tasks, but possibly also blocked in + * joins). Each pass repeats previous steps because of potential + * lagging thread creation. * * @param now if true, unconditionally terminate, else only - * if shutdown and empty queue and no active workers + * if no work and no active workers + * @param enable if true, enable shutdown when next possible * @return true if now terminating or terminated */ - private boolean tryTerminate(boolean now) { - long c; - while (((c = ctl) & STOP_BIT) == 0) { - if (!now) { - if ((int)(c >> AC_SHIFT) != -parallelism) - return false; - if (!shutdown || blockedCount != 0 || quiescerCount != 0 || - queueBase != queueTop) { - if (ctl == c) // staleness check - return false; - continue; + private boolean tryTerminate(boolean now, boolean enable) { + if (this == commonPool) // cannot shut down + return false; + for (long c;;) { + if (((c = ctl) & STOP_BIT) != 0) { // already terminating + if ((short)(c >>> TC_SHIFT) == -(config & SMASK)) { + synchronized (this) { + notifyAll(); // signal when 0 workers + } } + return true; } - if (UNSAFE.compareAndSwapLong(this, ctlOffset, c, c | STOP_BIT)) - startTerminating(); - } - if ((short)(c >>> TC_SHIFT) == -parallelism) { // signal when 0 workers - final ReentrantLock lock = this.submissionLock; - lock.lock(); - try { - termination.signalAll(); - } finally { - lock.unlock(); + if (plock >= 0) { // not yet enabled + int ps; + if (!enable) + return false; + if (((ps = plock) & PL_LOCK) != 0 || + !U.compareAndSwapInt(this, PLOCK, ps, ps += PL_LOCK)) + ps = acquirePlock(); + if (!U.compareAndSwapInt(this, PLOCK, ps, SHUTDOWN)) + releasePlock(SHUTDOWN); } - } - return true; - } - - /** - * Runs up to three passes through workers: (0) Setting - * termination status for each worker, followed by wakeups up to - * queued workers; (1) helping cancel tasks; (2) interrupting - * lagging threads (likely in external tasks, but possibly also - * blocked in joins). Each pass repeats previous steps because of - * potential lagging thread creation. - */ - private void startTerminating() { - cancelSubmissions(); - for (int pass = 0; pass < 3; ++pass) { - ForkJoinWorkerThread[] ws = workers; - if (ws != null) { - for (ForkJoinWorkerThread w : ws) { - if (w != null) { - w.terminate = true; - if (pass > 0) { - w.cancelTasks(); - if (pass > 1 && !w.isInterrupted()) { - try { - w.interrupt(); - } catch (SecurityException ignore) { + if (!now) { // check if idle & no tasks + if ((int)(c >> AC_SHIFT) != -(config & SMASK) || + hasQueuedSubmissions()) + return false; + // Check for unqueued inactive workers. One pass suffices. + WorkQueue[] ws = workQueues; WorkQueue w; + if (ws != null) { + for (int i = 1; i < ws.length; i += 2) { + if ((w = ws[i]) != null && w.eventCount >= 0) + return false; + } + } + } + if (U.compareAndSwapLong(this, CTL, c, c | STOP_BIT)) { + for (int pass = 0; pass < 3; ++pass) { + WorkQueue[] ws = workQueues; + if (ws != null) { + WorkQueue w; Thread wt; + int n = ws.length; + for (int i = 0; i < n; ++i) { + if ((w = ws[i]) != null) { + w.qlock = -1; + if (pass > 0) { + w.cancelAll(); + if (pass > 1 && (wt = w.owner) != null) { + if (!wt.isInterrupted()) { + try { + wt.interrupt(); + } catch (SecurityException ignore) { + } + } + U.unpark(wt); + } } } } + // Wake up workers parked on event queue + int i, e; long cc; Thread p; + while ((e = (int)(cc = ctl) & E_MASK) != 0 && + (i = e & SMASK) < n && + (w = ws[i]) != null) { + long nc = ((long)(w.nextWait & E_MASK) | + ((cc + AC_UNIT) & AC_MASK) | + (cc & (TC_MASK|STOP_BIT))); + if (w.eventCount == (e | INT_SIGN) && + U.compareAndSwapLong(this, CTL, cc, nc)) { + w.eventCount = (e + E_SEQ) & E_MASK; + w.qlock = -1; + if ((p = w.parker) != null) + U.unpark(p); + } + } } } - terminateWaiters(); } } } + // external operations on common pool + /** - * Polls and cancels all submissions. Called only during termination. + * Returns common pool queue for a thread that has submitted at + * least one task. */ - private void cancelSubmissions() { - while (queueBase != queueTop) { - ForkJoinTask task = pollSubmission(); - if (task != null) { - try { - task.cancel(false); - } catch (Throwable ignore) { - } - } - } + static WorkQueue commonSubmitterQueue() { + ForkJoinPool p; WorkQueue[] ws; int m; Submitter z; + return ((z = submitters.get()) != null && + (p = commonPool) != null && + (ws = p.workQueues) != null && + (m = ws.length - 1) >= 0) ? + ws[m & z.seed & SQMASK] : null; } /** - * Tries to set the termination status of waiting workers, and - * then wakes them up (after which they will terminate). - */ - private void terminateWaiters() { - ForkJoinWorkerThread[] ws = workers; - if (ws != null) { - ForkJoinWorkerThread w; long c; int i, e; - int n = ws.length; - while ((i = ~(e = (int)(c = ctl)) & SMASK) < n && - (w = ws[i]) != null && w.eventCount == (e & E_MASK)) { - if (UNSAFE.compareAndSwapLong(this, ctlOffset, c, - (long)(w.nextWait & E_MASK) | - ((c + AC_UNIT) & AC_MASK) | - (c & (TC_MASK|STOP_BIT)))) { - w.terminate = true; - w.eventCount = e + EC_UNIT; - if (w.parked) - UNSAFE.unpark(w); + * Tries to pop the given task from submitter's queue in common pool. + */ + static boolean tryExternalUnpush(ForkJoinTask t) { + ForkJoinPool p; WorkQueue[] ws; WorkQueue q; Submitter z; + ForkJoinTask[] a; int m, s; + if (t != null && + (z = submitters.get()) != null && + (p = commonPool) != null && + (ws = p.workQueues) != null && + (m = ws.length - 1) >= 0 && + (q = ws[m & z.seed & SQMASK]) != null && + (s = q.top) != q.base && + (a = q.array) != null) { + long j = (((a.length - 1) & (s - 1)) << ASHIFT) + ABASE; + if (U.getObject(a, j) == t && + U.compareAndSwapInt(q, QLOCK, 0, 1)) { + if (q.array == a && q.top == s && // recheck + U.compareAndSwapObject(a, j, t, null)) { + q.top = s - 1; + q.qlock = 0; + return true; } + q.qlock = 0; } } + return false; } - // misc ForkJoinWorkerThread support - /** - * Increments or decrements quiescerCount. Needed only to prevent - * triggering shutdown if a worker is transiently inactive while - * checking quiescence. - * - * @param delta 1 for increment, -1 for decrement + * Tries to pop and run local tasks within the same computation + * as the given root. On failure, tries to help complete from + * other queues via helpComplete. */ - final void addQuiescerCount(int delta) { - int c; - do {} while (!UNSAFE.compareAndSwapInt(this, quiescerCountOffset, - c = quiescerCount, c + delta)); + private void externalHelpComplete(WorkQueue q, ForkJoinTask root) { + ForkJoinTask[] a; int m; + if (q != null && (a = q.array) != null && (m = (a.length - 1)) >= 0 && + root != null && root.status >= 0) { + for (;;) { + int s, u; Object o; CountedCompleter task = null; + if ((s = q.top) - q.base > 0) { + long j = ((m & (s - 1)) << ASHIFT) + ABASE; + if ((o = U.getObject(a, j)) != null && + (o instanceof CountedCompleter)) { + CountedCompleter t = (CountedCompleter)o, r = t; + do { + if (r == root) { + if (U.compareAndSwapInt(q, QLOCK, 0, 1)) { + if (q.array == a && q.top == s && + U.compareAndSwapObject(a, j, t, null)) { + q.top = s - 1; + task = t; + } + q.qlock = 0; + } + break; + } + } while ((r = r.completer) != null); + } + } + if (task != null) + task.doExec(); + if (root.status < 0 || + (u = (int)(ctl >>> 32)) >= 0 || (u >> UAC_SHIFT) >= 0) + break; + if (task == null) { + helpSignal(root, q.poolIndex); + if (root.status >= 0) + helpComplete(root, SHARED_QUEUE); + break; + } + } + } } /** - * Directly increments or decrements active count without queuing. - * This method is used to transiently assert inactivation while - * checking quiescence. - * - * @param delta 1 for increment, -1 for decrement - */ - final void addActiveCount(int delta) { - long d = (long)delta << AC_SHIFT; - long c; - do {} while (!UNSAFE.compareAndSwapLong(this, ctlOffset, - c = ctl, c + d)); + * Tries to help execute or signal availability of the given task + * from submitter's queue in common pool. + */ + static void externalHelpJoin(ForkJoinTask t) { + // Some hard-to-avoid overlap with tryExternalUnpush + ForkJoinPool p; WorkQueue[] ws; WorkQueue q, w; Submitter z; + ForkJoinTask[] a; int m, s, n; + if (t != null && + (z = submitters.get()) != null && + (p = commonPool) != null && + (ws = p.workQueues) != null && + (m = ws.length - 1) >= 0 && + (q = ws[m & z.seed & SQMASK]) != null && + (a = q.array) != null) { + int am = a.length - 1; + if ((s = q.top) != q.base) { + long j = ((am & (s - 1)) << ASHIFT) + ABASE; + if (U.getObject(a, j) == t && + U.compareAndSwapInt(q, QLOCK, 0, 1)) { + if (q.array == a && q.top == s && + U.compareAndSwapObject(a, j, t, null)) { + q.top = s - 1; + q.qlock = 0; + t.doExec(); + } + else + q.qlock = 0; + } + } + if (t.status >= 0) { + if (t instanceof CountedCompleter) + p.externalHelpComplete(q, t); + else + p.helpSignal(t, q.poolIndex); + } + } } /** - * Returns the approximate (non-atomic) number of idle threads per - * active thread. + * Restricted version of helpQuiescePool for external callers */ - final int idlePerActive() { - // Approximate at powers of two for small values, saturate past 4 - int p = parallelism; - int a = p + (int)(ctl >> AC_SHIFT); - return (a > (p >>>= 1) ? 0 : - a > (p >>>= 1) ? 1 : - a > (p >>>= 1) ? 2 : - a > (p >>>= 1) ? 4 : - 8); + static void externalHelpQuiescePool() { + ForkJoinPool p; ForkJoinTask t; WorkQueue q; int b; + if ((p = commonPool) != null && + (q = p.findNonEmptyStealQueue(1)) != null && + (b = q.base) - q.top < 0 && + (t = q.pollAt(b)) != null) + t.doExec(); } // Exported methods @@ -1379,7 +2489,7 @@ public class ForkJoinPool extends AbstractExecutorService { * no UncaughtExceptionHandler, and non-async LIFO processing mode. */ public ForkJoinPool() { - this(Runtime.getRuntime().availableProcessors(), + this(Math.min(MAX_CAP, Runtime.getRuntime().availableProcessors()), defaultForkJoinWorkerThreadFactory, null, false); } @@ -1424,31 +2534,46 @@ public class ForkJoinPool extends AbstractExecutorService { checkPermission(); if (factory == null) throw new NullPointerException(); - if (parallelism <= 0 || parallelism > MAX_ID) + if (parallelism <= 0 || parallelism > MAX_CAP) throw new IllegalArgumentException(); - this.parallelism = parallelism; this.factory = factory; this.ueh = handler; - this.locallyFifo = asyncMode; + this.config = parallelism | (asyncMode ? (FIFO_QUEUE << 16) : 0); long np = (long)(-parallelism); // offset ctl counts this.ctl = ((np << AC_SHIFT) & AC_MASK) | ((np << TC_SHIFT) & TC_MASK); - this.submissionQueue = new ForkJoinTask[INITIAL_QUEUE_CAPACITY]; - // initialize workers array with room for 2*parallelism if possible - int n = parallelism << 1; - if (n >= MAX_ID) - n = MAX_ID; - else { // See Hackers Delight, sec 3.2, where n < (1 << 16) - n |= n >>> 1; n |= n >>> 2; n |= n >>> 4; n |= n >>> 8; - } - workers = new ForkJoinWorkerThread[n + 1]; - this.submissionLock = new ReentrantLock(); - this.termination = submissionLock.newCondition(); + int pn = nextPoolId(); StringBuilder sb = new StringBuilder("ForkJoinPool-"); - sb.append(poolNumberGenerator.incrementAndGet()); + sb.append(Integer.toString(pn)); sb.append("-worker-"); this.workerNamePrefix = sb.toString(); } + /** + * Constructor for common pool, suitable only for static initialization. + * Basically the same as above, but uses smallest possible initial footprint. + */ + ForkJoinPool(int parallelism, long ctl, + ForkJoinWorkerThreadFactory factory, + Thread.UncaughtExceptionHandler handler) { + this.config = parallelism; + this.ctl = ctl; + this.factory = factory; + this.ueh = handler; + this.workerNamePrefix = "ForkJoinPool.commonPool-worker-"; + } + + /** + * Returns the common pool instance. + * + * @return the common pool instance + * @since 1.8 + * @hide + */ + public static ForkJoinPool commonPool() { + // assert commonPool != null : "static init error"; + return commonPool; + } + // Execution methods /** @@ -1468,34 +2593,10 @@ public class ForkJoinPool extends AbstractExecutorService { * scheduled for execution */ public T invoke(ForkJoinTask task) { - Thread t = Thread.currentThread(); if (task == null) throw new NullPointerException(); - if (shutdown) - throw new RejectedExecutionException(); - if ((t instanceof ForkJoinWorkerThread) && - ((ForkJoinWorkerThread)t).pool == this) - return task.invoke(); // bypass submit if in same pool - else { - addSubmission(task); - return task.join(); - } - } - - /** - * Unless terminating, forks task if within an ongoing FJ - * computation in the current pool, else submits as external task. - */ - private void forkOrSubmit(ForkJoinTask task) { - ForkJoinWorkerThread w; - Thread t = Thread.currentThread(); - if (shutdown) - throw new RejectedExecutionException(); - if ((t instanceof ForkJoinWorkerThread) && - (w = (ForkJoinWorkerThread)t).pool == this) - w.pushTask(task); - else - addSubmission(task); + externalPush(task); + return task.join(); } /** @@ -1509,7 +2610,7 @@ public class ForkJoinPool extends AbstractExecutorService { public void execute(ForkJoinTask task) { if (task == null) throw new NullPointerException(); - forkOrSubmit(task); + externalPush(task); } // AbstractExecutorService methods @@ -1526,8 +2627,8 @@ public class ForkJoinPool extends AbstractExecutorService { if (task instanceof ForkJoinTask) // avoid re-wrap job = (ForkJoinTask) task; else - job = ForkJoinTask.adapt(task, null); - forkOrSubmit(job); + job = new ForkJoinTask.AdaptedRunnableAction(task); + externalPush(job); } /** @@ -1542,7 +2643,7 @@ public class ForkJoinPool extends AbstractExecutorService { public ForkJoinTask submit(ForkJoinTask task) { if (task == null) throw new NullPointerException(); - forkOrSubmit(task); + externalPush(task); return task; } @@ -1552,10 +2653,8 @@ public class ForkJoinPool extends AbstractExecutorService { * scheduled for execution */ public ForkJoinTask submit(Callable task) { - if (task == null) - throw new NullPointerException(); - ForkJoinTask job = ForkJoinTask.adapt(task); - forkOrSubmit(job); + ForkJoinTask job = new ForkJoinTask.AdaptedCallable(task); + externalPush(job); return job; } @@ -1565,10 +2664,8 @@ public class ForkJoinPool extends AbstractExecutorService { * scheduled for execution */ public ForkJoinTask submit(Runnable task, T result) { - if (task == null) - throw new NullPointerException(); - ForkJoinTask job = ForkJoinTask.adapt(task, result); - forkOrSubmit(job); + ForkJoinTask job = new ForkJoinTask.AdaptedRunnable(task, result); + externalPush(job); return job; } @@ -1584,8 +2681,8 @@ public class ForkJoinPool extends AbstractExecutorService { if (task instanceof ForkJoinTask) // avoid re-wrap job = (ForkJoinTask) task; else - job = ForkJoinTask.adapt(task, null); - forkOrSubmit(job); + job = new ForkJoinTask.AdaptedRunnableAction(task); + externalPush(job); return job; } @@ -1594,25 +2691,27 @@ public class ForkJoinPool extends AbstractExecutorService { * @throws RejectedExecutionException {@inheritDoc} */ public List> invokeAll(Collection> tasks) { - ArrayList> forkJoinTasks = - new ArrayList>(tasks.size()); - for (Callable task : tasks) - forkJoinTasks.add(ForkJoinTask.adapt(task)); - invoke(new InvokeAll(forkJoinTasks)); - - @SuppressWarnings({"unchecked", "rawtypes"}) - List> futures = (List>) (List) forkJoinTasks; - return futures; - } - - static final class InvokeAll extends RecursiveAction { - final ArrayList> tasks; - InvokeAll(ArrayList> tasks) { this.tasks = tasks; } - public void compute() { - try { invokeAll(tasks); } - catch (Exception ignore) {} + // In previous versions of this class, this method constructed + // a task to run ForkJoinTask.invokeAll, but now external + // invocation of multiple tasks is at least as efficient. + ArrayList> futures = new ArrayList>(tasks.size()); + + boolean done = false; + try { + for (Callable t : tasks) { + ForkJoinTask f = new ForkJoinTask.AdaptedCallable(t); + futures.add(f); + externalPush(f); + } + for (int i = 0, size = futures.size(); i < size; i++) + ((ForkJoinTask)futures.get(i)).quietlyJoin(); + done = true; + return futures; + } finally { + if (!done) + for (int i = 0, size = futures.size(); i < size; i++) + futures.get(i).cancel(false); } - private static final long serialVersionUID = -7914297376763021607L; } /** @@ -1640,7 +2739,18 @@ public class ForkJoinPool extends AbstractExecutorService { * @return the targeted parallelism level of this pool */ public int getParallelism() { - return parallelism; + return config & SMASK; + } + + /** + * Returns the targeted parallelism level of the common pool. + * + * @return the targeted parallelism level of the common pool + * @since 1.8 + * @hide + */ + public static int getCommonPoolParallelism() { + return commonPoolParallelism; } /** @@ -1652,7 +2762,7 @@ public class ForkJoinPool extends AbstractExecutorService { * @return the number of worker threads */ public int getPoolSize() { - return parallelism + (short)(ctl >>> TC_SHIFT); + return (config & SMASK) + (short)(ctl >>> TC_SHIFT); } /** @@ -1662,7 +2772,7 @@ public class ForkJoinPool extends AbstractExecutorService { * @return {@code true} if this pool uses async mode */ public boolean getAsyncMode() { - return locallyFifo; + return (config >>> 16) == FIFO_QUEUE; } /** @@ -1674,8 +2784,15 @@ public class ForkJoinPool extends AbstractExecutorService { * @return the number of worker threads */ public int getRunningThreadCount() { - int r = parallelism + (int)(ctl >> AC_SHIFT); - return (r <= 0) ? 0 : r; // suppress momentarily negative values + int rc = 0; + WorkQueue[] ws; WorkQueue w; + if ((ws = workQueues) != null) { + for (int i = 1; i < ws.length; i += 2) { + if ((w = ws[i]) != null && w.isApparentlyUnblocked()) + ++rc; + } + } + return rc; } /** @@ -1686,7 +2803,7 @@ public class ForkJoinPool extends AbstractExecutorService { * @return the number of active threads */ public int getActiveThreadCount() { - int r = parallelism + (int)(ctl >> AC_SHIFT) + blockedCount; + int r = (config & SMASK) + (int)(ctl >> AC_SHIFT); return (r <= 0) ? 0 : r; // suppress momentarily negative values } @@ -1702,7 +2819,7 @@ public class ForkJoinPool extends AbstractExecutorService { * @return {@code true} if all threads are currently idle */ public boolean isQuiescent() { - return parallelism + (int)(ctl >> AC_SHIFT) + blockedCount == 0; + return (int)(ctl >> AC_SHIFT) + (config & SMASK) == 0; } /** @@ -1717,7 +2834,15 @@ public class ForkJoinPool extends AbstractExecutorService { * @return the number of steals */ public long getStealCount() { - return stealCount; + long count = stealCount; + WorkQueue[] ws; WorkQueue w; + if ((ws = workQueues) != null) { + for (int i = 1; i < ws.length; i += 2) { + if ((w = ws[i]) != null) + count += w.nsteals; + } + } + return count; } /** @@ -1732,12 +2857,12 @@ public class ForkJoinPool extends AbstractExecutorService { */ public long getQueuedTaskCount() { long count = 0; - ForkJoinWorkerThread[] ws; - if ((short)(ctl >>> TC_SHIFT) > -parallelism && - (ws = workers) != null) { - for (ForkJoinWorkerThread w : ws) - if (w != null) - count -= w.queueBase - w.queueTop; // must read base first + WorkQueue[] ws; WorkQueue w; + if ((ws = workQueues) != null) { + for (int i = 1; i < ws.length; i += 2) { + if ((w = ws[i]) != null) + count += w.queueSize(); + } } return count; } @@ -1750,7 +2875,15 @@ public class ForkJoinPool extends AbstractExecutorService { * @return the number of queued submissions */ public int getQueuedSubmissionCount() { - return -queueBase + queueTop; + int count = 0; + WorkQueue[] ws; WorkQueue w; + if ((ws = workQueues) != null) { + for (int i = 0; i < ws.length; i += 2) { + if ((w = ws[i]) != null) + count += w.queueSize(); + } + } + return count; } /** @@ -1760,7 +2893,14 @@ public class ForkJoinPool extends AbstractExecutorService { * @return {@code true} if there are any queued submissions */ public boolean hasQueuedSubmissions() { - return queueBase != queueTop; + WorkQueue[] ws; WorkQueue w; + if ((ws = workQueues) != null) { + for (int i = 0; i < ws.length; i += 2) { + if ((w = ws[i]) != null && !w.isEmpty()) + return true; + } + } + return false; } /** @@ -1771,16 +2911,11 @@ public class ForkJoinPool extends AbstractExecutorService { * @return the next submission, or {@code null} if none */ protected ForkJoinTask pollSubmission() { - ForkJoinTask t; ForkJoinTask[] q; int b, i; - while ((b = queueBase) != queueTop && - (q = submissionQueue) != null && - (i = (q.length - 1) & b) >= 0) { - long u = (i << ASHIFT) + ABASE; - if ((t = q[i]) != null && - queueBase == b && - UNSAFE.compareAndSwapObject(q, u, t, null)) { - queueBase = b + 1; - return t; + WorkQueue[] ws; WorkQueue w; ForkJoinTask t; + if ((ws = workQueues) != null) { + for (int i = 0; i < ws.length; i += 2) { + if ((w = ws[i]) != null && (t = w.poll()) != null) + return t; } } return null; @@ -1805,20 +2940,17 @@ public class ForkJoinPool extends AbstractExecutorService { */ protected int drainTasksTo(Collection> c) { int count = 0; - while (queueBase != queueTop) { - ForkJoinTask t = pollSubmission(); - if (t != null) { - c.add(t); - ++count; + WorkQueue[] ws; WorkQueue w; ForkJoinTask t; + if ((ws = workQueues) != null) { + for (int i = 0; i < ws.length; ++i) { + if ((w = ws[i]) != null) { + while ((t = w.poll()) != null) { + c.add(t); + ++count; + } + } } } - ForkJoinWorkerThread[] ws; - if ((short)(ctl >>> TC_SHIFT) > -parallelism && - (ws = workers) != null) { - for (ForkJoinWorkerThread w : ws) - if (w != null) - count += w.drainTasksTo(c); - } return count; } @@ -1830,21 +2962,36 @@ public class ForkJoinPool extends AbstractExecutorService { * @return a string identifying this pool, as well as its state */ public String toString() { - long st = getStealCount(); - long qt = getQueuedTaskCount(); - long qs = getQueuedSubmissionCount(); - int pc = parallelism; + // Use a single pass through workQueues to collect counts + long qt = 0L, qs = 0L; int rc = 0; + long st = stealCount; long c = ctl; + WorkQueue[] ws; WorkQueue w; + if ((ws = workQueues) != null) { + for (int i = 0; i < ws.length; ++i) { + if ((w = ws[i]) != null) { + int size = w.queueSize(); + if ((i & 1) == 0) + qs += size; + else { + qt += size; + st += w.nsteals; + if (w.isApparentlyUnblocked()) + ++rc; + } + } + } + } + int pc = (config & SMASK); int tc = pc + (short)(c >>> TC_SHIFT); - int rc = pc + (int)(c >> AC_SHIFT); - if (rc < 0) // ignore transient negative - rc = 0; - int ac = rc + blockedCount; + int ac = pc + (int)(c >> AC_SHIFT); + if (ac < 0) // ignore transient negative + ac = 0; String level; if ((c & STOP_BIT) != 0) level = (tc == 0) ? "Terminated" : "Terminating"; else - level = shutdown ? "Shutting down" : "Running"; + level = plock < 0 ? "Shutting down" : "Running"; return super.toString() + "[" + level + ", parallelism = " + pc + @@ -1858,34 +3005,41 @@ public class ForkJoinPool extends AbstractExecutorService { } /** - * Initiates an orderly shutdown in which previously submitted - * tasks are executed, but no new tasks will be accepted. - * Invocation has no additional effect if already shut down. - * Tasks that are in the process of being submitted concurrently - * during the course of this method may or may not be rejected. + * Possibly initiates an orderly shutdown in which previously + * submitted tasks are executed, but no new tasks will be + * accepted. Invocation has no effect on execution state if this + * is the {@link #commonPool()}, and no additional effect if + * already shut down. Tasks that are in the process of being + * submitted concurrently during the course of this method may or + * may not be rejected. + * + * @throws SecurityException if a security manager exists and + * the caller is not permitted to modify threads + * because it does not hold {@link + * java.lang.RuntimePermission}{@code ("modifyThread")} */ public void shutdown() { checkPermission(); - shutdown = true; - tryTerminate(false); + tryTerminate(false, true); } /** - * Attempts to cancel and/or stop all tasks, and reject all - * subsequently submitted tasks. Tasks that are in the process of - * being submitted or executed concurrently during the course of - * this method may or may not be rejected. This method cancels - * both existing and unexecuted tasks, in order to permit - * termination in the presence of task dependencies. So the method - * always returns an empty list (unlike the case for some other - * Executors). + * Possibly attempts to cancel and/or stop all tasks, and reject + * all subsequently submitted tasks. Invocation has no effect on + * execution state if this is the {@link #commonPool()}, and no + * additional effect if already shut down. Otherwise, tasks that + * are in the process of being submitted or executed concurrently + * during the course of this method may or may not be + * rejected. This method cancels both existing and unexecuted + * tasks, in order to permit termination in the presence of task + * dependencies. So the method always returns an empty list + * (unlike the case for some other Executors). * * @return an empty list */ public List shutdownNow() { checkPermission(); - shutdown = true; - tryTerminate(true); + tryTerminate(true, true); return Collections.emptyList(); } @@ -1897,7 +3051,7 @@ public class ForkJoinPool extends AbstractExecutorService { public boolean isTerminated() { long c = ctl; return ((c & STOP_BIT) != 0L && - (short)(c >>> TC_SHIFT) == -parallelism); + (short)(c >>> TC_SHIFT) == -(config & SMASK)); } /** @@ -1905,7 +3059,7 @@ public class ForkJoinPool extends AbstractExecutorService { * commenced but not yet completed. This method may be useful for * debugging. A return of {@code true} reported a sufficient * period after shutdown may indicate that submitted tasks have - * ignored or suppressed interruption, or are waiting for IO, + * ignored or suppressed interruption, or are waiting for I/O, * causing this executor not to properly terminate. (See the * advisory notes for class {@link ForkJoinTask} stating that * tasks should not normally entail blocking operations. But if @@ -1916,14 +3070,7 @@ public class ForkJoinPool extends AbstractExecutorService { public boolean isTerminating() { long c = ctl; return ((c & STOP_BIT) != 0L && - (short)(c >>> TC_SHIFT) != -parallelism); - } - - /** - * Returns true if terminating or terminated. Used by ForkJoinWorkerThread. - */ - final boolean isAtLeastTerminating() { - return (ctl & STOP_BIT) != 0L; + (short)(c >>> TC_SHIFT) != -(config & SMASK)); } /** @@ -1932,13 +3079,15 @@ public class ForkJoinPool extends AbstractExecutorService { * @return {@code true} if this pool has been shut down */ public boolean isShutdown() { - return shutdown; + return plock < 0; } /** - * Blocks until all tasks have completed execution after a shutdown - * request, or the timeout occurs, or the current thread is - * interrupted, whichever happens first. + * Blocks until all tasks have completed execution after a + * shutdown request, or the timeout occurs, or the current thread + * is interrupted, whichever happens first. Note that the {@link + * #commonPool()} never terminates until program shutdown so + * this method will always time out. * * @param timeout the maximum time to wait * @param unit the time unit of the timeout argument @@ -1949,18 +3098,21 @@ public class ForkJoinPool extends AbstractExecutorService { public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException { long nanos = unit.toNanos(timeout); - final ReentrantLock lock = this.submissionLock; - lock.lock(); - try { + if (isTerminated()) + return true; + if (nanos <= 0L) + return false; + long deadline = System.nanoTime() + nanos; + synchronized (this) { for (;;) { if (isTerminated()) return true; - if (nanos <= 0) + if (nanos <= 0L) return false; - nanos = termination.awaitNanos(nanos); + long millis = TimeUnit.NANOSECONDS.toMillis(nanos); + wait(millis > 0L ? millis : 1L); + nanos = deadline - System.nanoTime(); } - } finally { - lock.unlock(); } } @@ -2061,11 +3213,35 @@ public class ForkJoinPool extends AbstractExecutorService { throws InterruptedException { Thread t = Thread.currentThread(); if (t instanceof ForkJoinWorkerThread) { - ForkJoinWorkerThread w = (ForkJoinWorkerThread) t; - w.pool.awaitBlocker(blocker); + ForkJoinPool p = ((ForkJoinWorkerThread)t).pool; + while (!blocker.isReleasable()) { // variant of helpSignal + WorkQueue[] ws; WorkQueue q; int m, u; + if ((ws = p.workQueues) != null && (m = ws.length - 1) >= 0) { + for (int i = 0; i <= m; ++i) { + if (blocker.isReleasable()) + return; + if ((q = ws[i]) != null && q.base - q.top < 0) { + p.signalWork(q); + if ((u = (int)(p.ctl >>> 32)) >= 0 || + (u >> UAC_SHIFT) >= 0) + break; + } + } + } + if (p.tryCompensate()) { + try { + do {} while (!blocker.isReleasable() && + !blocker.block()); + } finally { + p.incrementActiveCount(); + } + break; + } + } } else { - do {} while (!blocker.isReleasable() && !blocker.block()); + do {} while (!blocker.isReleasable() && + !blocker.block()); } } @@ -2074,54 +3250,93 @@ public class ForkJoinPool extends AbstractExecutorService { // implement RunnableFuture. protected RunnableFuture newTaskFor(Runnable runnable, T value) { - return (RunnableFuture) ForkJoinTask.adapt(runnable, value); + return new ForkJoinTask.AdaptedRunnable(runnable, value); } protected RunnableFuture newTaskFor(Callable callable) { - return (RunnableFuture) ForkJoinTask.adapt(callable); + return new ForkJoinTask.AdaptedCallable(callable); } // Unsafe mechanics - private static final sun.misc.Unsafe UNSAFE; - private static final long ctlOffset; - private static final long stealCountOffset; - private static final long blockedCountOffset; - private static final long quiescerCountOffset; - private static final long scanGuardOffset; - private static final long nextWorkerNumberOffset; - private static final long ABASE; + private static final sun.misc.Unsafe U; + private static final long CTL; + private static final long PARKBLOCKER; + private static final int ABASE; private static final int ASHIFT; + private static final long STEALCOUNT; + private static final long PLOCK; + private static final long INDEXSEED; + private static final long QLOCK; static { - poolNumberGenerator = new AtomicInteger(); - workerSeedGenerator = new Random(); - modifyThreadPermission = new RuntimePermission("modifyThread"); - defaultForkJoinWorkerThreadFactory = - new DefaultForkJoinWorkerThreadFactory(); + // initialize field offsets for CAS etc try { - UNSAFE = sun.misc.Unsafe.getUnsafe(); + U = sun.misc.Unsafe.getUnsafe(); Class k = ForkJoinPool.class; - ctlOffset = UNSAFE.objectFieldOffset + CTL = U.objectFieldOffset (k.getDeclaredField("ctl")); - stealCountOffset = UNSAFE.objectFieldOffset + STEALCOUNT = U.objectFieldOffset (k.getDeclaredField("stealCount")); - blockedCountOffset = UNSAFE.objectFieldOffset - (k.getDeclaredField("blockedCount")); - quiescerCountOffset = UNSAFE.objectFieldOffset - (k.getDeclaredField("quiescerCount")); - scanGuardOffset = UNSAFE.objectFieldOffset - (k.getDeclaredField("scanGuard")); - nextWorkerNumberOffset = UNSAFE.objectFieldOffset - (k.getDeclaredField("nextWorkerNumber")); + PLOCK = U.objectFieldOffset + (k.getDeclaredField("plock")); + INDEXSEED = U.objectFieldOffset + (k.getDeclaredField("indexSeed")); + Class tk = Thread.class; + PARKBLOCKER = U.objectFieldOffset + (tk.getDeclaredField("parkBlocker")); + Class wk = WorkQueue.class; + QLOCK = U.objectFieldOffset + (wk.getDeclaredField("qlock")); + Class ak = ForkJoinTask[].class; + ABASE = U.arrayBaseOffset(ak); + int scale = U.arrayIndexScale(ak); + if ((scale & (scale - 1)) != 0) + throw new Error("data type scale not a power of two"); + ASHIFT = 31 - Integer.numberOfLeadingZeros(scale); } catch (Exception e) { throw new Error(e); } - Class a = ForkJoinTask[].class; - ABASE = UNSAFE.arrayBaseOffset(a); - int s = UNSAFE.arrayIndexScale(a); - if ((s & (s-1)) != 0) - throw new Error("data type scale not a power of two"); - ASHIFT = 31 - Integer.numberOfLeadingZeros(s); + + submitters = new ThreadLocal(); + ForkJoinWorkerThreadFactory fac = defaultForkJoinWorkerThreadFactory = + new DefaultForkJoinWorkerThreadFactory(); + modifyThreadPermission = new RuntimePermission("modifyThread"); + + /* + * Establish common pool parameters. For extra caution, + * computations to set up common pool state are here; the + * constructor just assigns these values to fields. + */ + + int par = 0; + Thread.UncaughtExceptionHandler handler = null; + try { // TBD: limit or report ignored exceptions? + String pp = System.getProperty + ("java.util.concurrent.ForkJoinPool.common.parallelism"); + String hp = System.getProperty + ("java.util.concurrent.ForkJoinPool.common.exceptionHandler"); + String fp = System.getProperty + ("java.util.concurrent.ForkJoinPool.common.threadFactory"); + if (fp != null) + fac = ((ForkJoinWorkerThreadFactory)ClassLoader. + getSystemClassLoader().loadClass(fp).newInstance()); + if (hp != null) + handler = ((Thread.UncaughtExceptionHandler)ClassLoader. + getSystemClassLoader().loadClass(hp).newInstance()); + if (pp != null) + par = Integer.parseInt(pp); + } catch (Exception ignore) { + } + + if (par <= 0) + par = Runtime.getRuntime().availableProcessors(); + if (par > MAX_CAP) + par = MAX_CAP; + commonPoolParallelism = par; + long np = (long)(-par); // precompute initial ctl value + long ct = ((np << AC_SHIFT) & AC_MASK) | ((np << TC_SHIFT) & TC_MASK); + + commonPool = new ForkJoinPool(par, ct, fac, handler); } } diff --git a/luni/src/main/java/java/util/concurrent/ForkJoinTask.java b/luni/src/main/java/java/util/concurrent/ForkJoinTask.java index 86a29d7..818788e 100644 --- a/luni/src/main/java/java/util/concurrent/ForkJoinTask.java +++ b/luni/src/main/java/java/util/concurrent/ForkJoinTask.java @@ -22,7 +22,6 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.concurrent.locks.ReentrantLock; import java.lang.reflect.Constructor; -import libcore.util.SneakyThrow; /** * Abstract base class for tasks that run within a {@link ForkJoinPool}. @@ -31,46 +30,59 @@ import libcore.util.SneakyThrow; * subtasks may be hosted by a small number of actual threads in a * ForkJoinPool, at the price of some usage limitations. * - *

    A "main" {@code ForkJoinTask} begins execution when submitted - * to a {@link ForkJoinPool}. Once started, it will usually in turn - * start other subtasks. As indicated by the name of this class, - * many programs using {@code ForkJoinTask} employ only methods - * {@link #fork} and {@link #join}, or derivatives such as {@link + *

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

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

    It is possible to define and use ForkJoinTasks that may block, + * but doing do requires three further considerations: (1) Completion + * of few if any other tasks should be dependent on a task + * that blocks on external synchronization or I/O. Event-style async + * tasks that are never joined (for example, those subclassing {@link + * CountedCompleter}) often fall into this category. (2) To minimize + * resource impact, tasks should be small; ideally performing only the + * (possibly) blocking action. (3) Unless the {@link + * ForkJoinPool.ManagedBlocker} API is used, or the number of possibly + * blocked tasks is known to be less than the pool's {@link + * ForkJoinPool#getParallelism} level, the pool cannot guarantee that + * enough threads will be available to ensure progress or good + * performance. * *

    The primary method for awaiting completion and extracting * results of a task is {@link #join}, but there are several variants: @@ -86,6 +98,13 @@ import libcore.util.SneakyThrow; * performs the most common form of parallel invocation: forking a set * of tasks and joining them all. * + *

    In the most typical usages, a fork-join pair act like a call + * (fork) and return (join) from a parallel recursive function. As is + * the case with other forms of recursive calls, returns (joins) + * should be performed innermost-first. For example, {@code a.fork(); + * b.fork(); b.join(); a.join();} is likely to be substantially more + * efficient than joining {@code a} before {@code b}. + * *

    The execution status of tasks may be queried at several levels * of detail: {@link #isDone} is true if a task completed in any way * (including the case where a task was cancelled without executing); @@ -101,18 +120,13 @@ import libcore.util.SneakyThrow; *

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

    Method {@link #join} and its variants are appropriate for use * only when completion dependencies are acyclic; that is, the @@ -122,7 +136,17 @@ import libcore.util.SneakyThrow; * supports other methods and techniques (for example the use of * {@link Phaser}, {@link #helpQuiesce}, and {@link #complete}) that * may be of use in constructing custom subclasses for problems that - * are not statically structured as DAGs. + * are not statically structured as DAGs. To support such usages a + * ForkJoinTask may be atomically tagged with a {@code short} + * value using {@link #setForkJoinTaskTag} or {@link + * #compareAndSetForkJoinTaskTag} and checked using {@link + * #getForkJoinTaskTag}. The ForkJoinTask implementation does not use + * these {@code protected} methods or tags for any purpose, but they + * may be of use in the construction of specialized subclasses. For + * example, parallel graph traversals can use the supplied methods to + * avoid revisiting nodes/tasks that have already been processed. + * (Method names for tagging are bulky in part to encourage definition + * of methods that reflect their usage patterns.) * *

    Most base support methods are {@code final}, to prevent * overriding of implementations that are intrinsically tied to the @@ -177,29 +201,36 @@ public abstract class ForkJoinTask implements Future, Serializable { * The status field holds run control status bits packed into a * single int to minimize footprint and to ensure atomicity (via * CAS). Status is initially zero, and takes on nonnegative - * values until completed, upon which status holds value - * NORMAL, CANCELLED, or EXCEPTIONAL. Tasks undergoing blocking - * waits by other threads have the SIGNAL bit set. Completion of - * a stolen task with SIGNAL set awakens any waiters via - * notifyAll. Even though suboptimal for some purposes, we use - * basic builtin wait/notify to take advantage of "monitor - * inflation" in JVMs that we would otherwise need to emulate to - * avoid adding further per-task bookkeeping overhead. We want - * these monitors to be "fat", i.e., not use biasing or thin-lock - * techniques, so use some odd coding idioms that tend to avoid - * them. + * values until completed, upon which status (anded with + * DONE_MASK) holds value NORMAL, CANCELLED, or EXCEPTIONAL. Tasks + * undergoing blocking waits by other threads have the SIGNAL bit + * set. Completion of a stolen task with SIGNAL set awakens any + * waiters via notifyAll. Even though suboptimal for some + * purposes, we use basic builtin wait/notify to take advantage of + * "monitor inflation" in JVMs that we would otherwise need to + * emulate to avoid adding further per-task bookkeeping overhead. + * We want these monitors to be "fat", i.e., not use biasing or + * thin-lock techniques, so use some odd coding idioms that tend + * to avoid them, mainly by arranging that every synchronized + * block performs a wait, notifyAll or both. + * + * These control bits occupy only (some of) the upper half (16 + * bits) of status field. The lower bits are used for user-defined + * tags. */ /** The run status of this task */ volatile int status; // accessed directly by pool and workers - private static final int NORMAL = -1; - private static final int CANCELLED = -2; - private static final int EXCEPTIONAL = -3; - private static final int SIGNAL = 1; + static final int DONE_MASK = 0xf0000000; // mask out non-completion bits + static final int NORMAL = 0xf0000000; // must be negative + static final int CANCELLED = 0xc0000000; // must be < NORMAL + static final int EXCEPTIONAL = 0x80000000; // must be < CANCELLED + static final int SIGNAL = 0x00010000; // must be >= 1 << 16 + static final int SMASK = 0x0000ffff; // short bits for tags /** - * Marks completion and wakes up threads waiting to join this task, - * also clearing signal request bits. + * Marks completion and wakes up threads waiting to join this + * task. * * @param completion one of NORMAL, CANCELLED, EXCEPTIONAL * @return completion status on exit @@ -208,8 +239,8 @@ public abstract class ForkJoinTask implements Future, Serializable { for (int s;;) { if ((s = status) < 0) return s; - if (UNSAFE.compareAndSwapInt(this, statusOffset, s, completion)) { - if (s != 0) + if (U.compareAndSwapInt(this, STATUS, s, s | completion)) { + if ((s >>> 16) != 0) synchronized (this) { notifyAll(); } return completion; } @@ -217,27 +248,36 @@ public abstract class ForkJoinTask implements Future, Serializable { } /** - * Tries to block a worker thread until completed or timed out. - * Uses Object.wait time argument conventions. - * May fail on contention or interrupt. + * Primary execution method for stolen tasks. Unless done, calls + * exec and records status if completed, but doesn't wait for + * completion otherwise. * - * @param millis if > 0, wait time. + * @return status on exit from this method */ - final void tryAwaitDone(long millis) { - int s; - try { - if (((s = status) > 0 || - (s == 0 && - UNSAFE.compareAndSwapInt(this, statusOffset, 0, SIGNAL))) && - status > 0) { - synchronized (this) { - if (status > 0) - wait(millis); - } + final int doExec() { + int s; boolean completed; + if ((s = status) >= 0) { + try { + completed = exec(); + } catch (Throwable rex) { + return setExceptionalCompletion(rex); } - } catch (InterruptedException ie) { - // caller must check termination + if (completed) + s = setCompletion(NORMAL); } + return s; + } + + /** + * Tries to set SIGNAL status unless already completed. Used by + * ForkJoinPool. Other variants are directly incorporated into + * externalAwaitDone etc. + * + * @return true if successful + */ + final boolean trySetSignal() { + int s = status; + return s >= 0 && U.compareAndSwapInt(this, STATUS, s, s | SIGNAL); } /** @@ -246,113 +286,78 @@ public abstract class ForkJoinTask implements Future, Serializable { */ private int externalAwaitDone() { int s; - if ((s = status) >= 0) { - boolean interrupted = false; - synchronized (this) { - while ((s = status) >= 0) { - if (s == 0) - UNSAFE.compareAndSwapInt(this, statusOffset, - 0, SIGNAL); - else { + ForkJoinPool.externalHelpJoin(this); + boolean interrupted = false; + while ((s = status) >= 0) { + if (U.compareAndSwapInt(this, STATUS, s, s | SIGNAL)) { + synchronized (this) { + if (status >= 0) { try { wait(); } catch (InterruptedException ie) { interrupted = true; } } + else + notifyAll(); } } - if (interrupted) - Thread.currentThread().interrupt(); } + if (interrupted) + Thread.currentThread().interrupt(); return s; } /** - * Blocks a non-worker-thread until completion or interruption or timeout. + * Blocks a non-worker-thread until completion or interruption. */ - private int externalInterruptibleAwaitDone(long millis) - throws InterruptedException { + private int externalInterruptibleAwaitDone() throws InterruptedException { int s; if (Thread.interrupted()) throw new InterruptedException(); - if ((s = status) >= 0) { - synchronized (this) { - while ((s = status) >= 0) { - if (s == 0) - UNSAFE.compareAndSwapInt(this, statusOffset, - 0, SIGNAL); - else { - wait(millis); - if (millis > 0L) - break; - } + ForkJoinPool.externalHelpJoin(this); + while ((s = status) >= 0) { + if (U.compareAndSwapInt(this, STATUS, s, s | SIGNAL)) { + synchronized (this) { + if (status >= 0) + wait(); + else + notifyAll(); } } } return s; } - /** - * Primary execution method for stolen tasks. Unless done, calls - * exec and records status if completed, but doesn't wait for - * completion otherwise. - */ - final void doExec() { - if (status >= 0) { - boolean completed; - try { - completed = exec(); - } catch (Throwable rex) { - setExceptionalCompletion(rex); - return; - } - if (completed) - setCompletion(NORMAL); // must be outside try block - } - } /** - * Primary mechanics for join, get, quietlyJoin. + * Implementation for join, get, quietlyJoin. Directly handles + * only cases of already-completed, external wait, and + * unfork+exec. Others are relayed to ForkJoinPool.awaitJoin. + * * @return status upon completion */ private int doJoin() { - Thread t; ForkJoinWorkerThread w; int s; boolean completed; - if ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) { - if ((s = status) < 0) - return s; - if ((w = (ForkJoinWorkerThread)t).unpushTask(this)) { - try { - completed = exec(); - } catch (Throwable rex) { - return setExceptionalCompletion(rex); - } - if (completed) - return setCompletion(NORMAL); - } - return w.joinTask(this); - } - else - return externalAwaitDone(); + int s; Thread t; ForkJoinWorkerThread wt; ForkJoinPool.WorkQueue w; + return (s = status) < 0 ? s : + ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) ? + (w = (wt = (ForkJoinWorkerThread)t).workQueue). + tryUnpush(this) && (s = doExec()) < 0 ? s : + wt.pool.awaitJoin(w, this) : + externalAwaitDone(); } /** - * Primary mechanics for invoke, quietlyInvoke. + * Implementation for invoke, quietlyInvoke. + * * @return status upon completion */ private int doInvoke() { - int s; boolean completed; - if ((s = status) < 0) - return s; - try { - completed = exec(); - } catch (Throwable rex) { - return setExceptionalCompletion(rex); - } - if (completed) - return setCompletion(NORMAL); - else - return doJoin(); + int s; Thread t; ForkJoinWorkerThread wt; + return (s = doExec()) < 0 ? s : + ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) ? + (wt = (ForkJoinWorkerThread)t).pool.awaitJoin(wt.workQueue, this) : + externalAwaitDone(); } // Exception table support @@ -387,7 +392,7 @@ public abstract class ForkJoinTask implements Future, Serializable { * any ForkJoinPool will call helpExpungeStaleExceptions when its * pool becomes isQuiescent. */ - static final class ExceptionNode extends WeakReference>{ + static final class ExceptionNode extends WeakReference> { final Throwable ex; ExceptionNode next; final long thrower; // use id not ref to avoid weak cycles @@ -400,34 +405,71 @@ public abstract class ForkJoinTask implements Future, Serializable { } /** - * Records exception and sets exceptional completion. + * Records exception and sets status. * * @return status on exit */ - private int setExceptionalCompletion(Throwable ex) { - int h = System.identityHashCode(this); - final ReentrantLock lock = exceptionTableLock; - lock.lock(); - try { - expungeStaleExceptions(); - ExceptionNode[] t = exceptionTable; - int i = h & (t.length - 1); - for (ExceptionNode e = t[i]; ; e = e.next) { - if (e == null) { - t[i] = new ExceptionNode(this, ex, t[i]); - break; + final int recordExceptionalCompletion(Throwable ex) { + int s; + if ((s = status) >= 0) { + int h = System.identityHashCode(this); + final ReentrantLock lock = exceptionTableLock; + lock.lock(); + try { + expungeStaleExceptions(); + ExceptionNode[] t = exceptionTable; + int i = h & (t.length - 1); + for (ExceptionNode e = t[i]; ; e = e.next) { + if (e == null) { + t[i] = new ExceptionNode(this, ex, t[i]); + break; + } + if (e.get() == this) // already present + break; } - if (e.get() == this) // already present - break; + } finally { + lock.unlock(); + } + s = setCompletion(EXCEPTIONAL); + } + return s; + } + + /** + * Records exception and possibly propagates. + * + * @return status on exit + */ + private int setExceptionalCompletion(Throwable ex) { + int s = recordExceptionalCompletion(ex); + if ((s & DONE_MASK) == EXCEPTIONAL) + internalPropagateException(ex); + return s; + } + + /** + * Hook for exception propagation support for tasks with completers. + */ + void internalPropagateException(Throwable ex) { + } + + /** + * Cancels, ignoring any exceptions thrown by cancel. Used during + * worker and pool shutdown. Cancel is spec'ed not to throw any + * exceptions, but if it does anyway, we have no recourse during + * shutdown, so guard against this case. + */ + static final void cancelIgnoringExceptions(ForkJoinTask t) { + if (t != null && t.status >= 0) { + try { + t.cancel(false); + } catch (Throwable ignore) { } - } finally { - lock.unlock(); } - return setCompletion(EXCEPTIONAL); } /** - * Removes exception node and clears status + * Removes exception node and clears status. */ private void clearExceptionalCompletion() { int h = System.identityHashCode(this); @@ -472,7 +514,7 @@ public abstract class ForkJoinTask implements Future, Serializable { * @return the exception, or null if none */ private Throwable getThrowableException() { - if (status != EXCEPTIONAL) + if ((status & DONE_MASK) != EXCEPTIONAL) return null; int h = System.identityHashCode(this); ExceptionNode e; @@ -490,7 +532,7 @@ public abstract class ForkJoinTask implements Future, Serializable { Throwable ex; if (e == null || (ex = e.ex) == null) return null; - if (e.thrower != Thread.currentThread().getId()) { + if (false && e.thrower != Thread.currentThread().getId()) { Class ec = ex.getClass(); try { Constructor noArgCtor = null; @@ -557,41 +599,61 @@ public abstract class ForkJoinTask implements Future, Serializable { } /** - * Report the result of invoke or join; called only upon - * non-normal return of internal versions. + * A version of "sneaky throw" to relay exceptions + */ + static void rethrow(final Throwable ex) { + if (ex != null) { + if (ex instanceof Error) + throw (Error)ex; + if (ex instanceof RuntimeException) + throw (RuntimeException)ex; + throw uncheckedThrowable(ex, RuntimeException.class); + } + } + + /** + * The sneaky part of sneaky throw, relying on generics + * limitations to evade compiler complaints about rethrowing + * unchecked exceptions */ - private V reportResult() { - int s; Throwable ex; - if ((s = status) == CANCELLED) + @SuppressWarnings("unchecked") static + T uncheckedThrowable(final Throwable t, final Class c) { + return (T)t; // rely on vacuous cast + } + + /** + * Throws exception, if any, associated with the given status. + */ + private void reportException(int s) { + if (s == CANCELLED) throw new CancellationException(); - if (s == EXCEPTIONAL && (ex = getThrowableException()) != null) - SneakyThrow.sneakyThrow(ex); // android-changed - return getRawResult(); + if (s == EXCEPTIONAL) + rethrow(getThrowableException()); } // public methods /** - * Arranges to asynchronously execute this task. While it is not - * necessarily enforced, it is a usage error to fork a task more - * than once unless it has completed and been reinitialized. - * Subsequent modifications to the state of this task or any data - * it operates on are not necessarily consistently observable by - * any thread other than the one executing it unless preceded by a - * call to {@link #join} or related methods, or a call to {@link - * #isDone} returning {@code true}. - * - *

    This method may be invoked only from within {@code - * ForkJoinPool} computations (as may be determined using method - * {@link #inForkJoinPool}). Attempts to invoke in other contexts - * result in exceptions or errors, possibly including {@code - * ClassCastException}. + * Arranges to asynchronously execute this task in the pool the + * current task is running in, if applicable, or using the {@link + * ForkJoinPool#commonPool()} if not {@link #inForkJoinPool}. While + * it is not necessarily enforced, it is a usage error to fork a + * task more than once unless it has completed and been + * reinitialized. Subsequent modifications to the state of this + * task or any data it operates on are not necessarily + * consistently observable by any thread other than the one + * executing it unless preceded by a call to {@link #join} or + * related methods, or a call to {@link #isDone} returning {@code + * true}. * * @return {@code this}, to simplify usage */ public final ForkJoinTask fork() { - ((ForkJoinWorkerThread) Thread.currentThread()) - .pushTask(this); + Thread t; + if ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) + ((ForkJoinWorkerThread)t).workQueue.push(this); + else + ForkJoinPool.commonPool.externalPush(this); return this; } @@ -607,10 +669,10 @@ public abstract class ForkJoinTask implements Future, Serializable { * @return the computed result */ public final V join() { - if (doJoin() != NORMAL) - return reportResult(); - else - return getRawResult(); + int s; + if ((s = doJoin() & DONE_MASK) != NORMAL) + reportException(s); + return getRawResult(); } /** @@ -622,10 +684,10 @@ public abstract class ForkJoinTask implements Future, Serializable { * @return the computed result */ public final V invoke() { - if (doInvoke() != NORMAL) - return reportResult(); - else - return getRawResult(); + int s; + if ((s = doInvoke() & DONE_MASK) != NORMAL) + reportException(s); + return getRawResult(); } /** @@ -641,20 +703,17 @@ public abstract class ForkJoinTask implements Future, Serializable { * cancelled, completed normally or exceptionally, or left * unprocessed. * - *

    This method may be invoked only from within {@code - * ForkJoinPool} computations (as may be determined using method - * {@link #inForkJoinPool}). Attempts to invoke in other contexts - * result in exceptions or errors, possibly including {@code - * ClassCastException}. - * * @param t1 the first task * @param t2 the second task * @throws NullPointerException if any task is null */ public static void invokeAll(ForkJoinTask t1, ForkJoinTask t2) { + int s1, s2; t2.fork(); - t1.invoke(); - t2.join(); + if ((s1 = t1.doInvoke() & DONE_MASK) != NORMAL) + t1.reportException(s1); + if ((s2 = t2.doJoin() & DONE_MASK) != NORMAL) + t2.reportException(s2); } /** @@ -669,12 +728,6 @@ public abstract class ForkJoinTask implements Future, Serializable { * related methods to check if they have been cancelled, completed * normally or exceptionally, or left unprocessed. * - *

    This method may be invoked only from within {@code - * ForkJoinPool} computations (as may be determined using method - * {@link #inForkJoinPool}). Attempts to invoke in other contexts - * result in exceptions or errors, possibly including {@code - * ClassCastException}. - * * @param tasks the tasks * @throws NullPointerException if any task is null */ @@ -702,7 +755,7 @@ public abstract class ForkJoinTask implements Future, Serializable { } } if (ex != null) - SneakyThrow.sneakyThrow(ex); // android-changed + rethrow(ex); } /** @@ -718,15 +771,11 @@ public abstract class ForkJoinTask implements Future, Serializable { * cancelled, completed normally or exceptionally, or left * unprocessed. * - *

    This method may be invoked only from within {@code - * ForkJoinPool} computations (as may be determined using method - * {@link #inForkJoinPool}). Attempts to invoke in other contexts - * result in exceptions or errors, possibly including {@code - * ClassCastException}. - * * @param tasks the collection of tasks * @return the tasks argument, to simplify usage * @throws NullPointerException if tasks or any element are null + + * @hide */ public static > Collection invokeAll(Collection tasks) { if (!(tasks instanceof RandomAccess) || !(tasks instanceof List)) { @@ -759,7 +808,7 @@ public abstract class ForkJoinTask implements Future, Serializable { } } if (ex != null) - SneakyThrow.sneakyThrow(ex); // android-changed + rethrow(ex); return tasks; } @@ -791,20 +840,7 @@ public abstract class ForkJoinTask implements Future, Serializable { * @return {@code true} if this task is now cancelled */ public boolean cancel(boolean mayInterruptIfRunning) { - return setCompletion(CANCELLED) == CANCELLED; - } - - /** - * Cancels, ignoring any exceptions thrown by cancel. Used during - * worker and pool shutdown. Cancel is spec'ed not to throw any - * exceptions, but if it does anyway, we have no recourse during - * shutdown, so guard against this case. - */ - final void cancelIgnoringExceptions() { - try { - cancel(false); - } catch (Throwable ignore) { - } + return (setCompletion(CANCELLED) & DONE_MASK) == CANCELLED; } public final boolean isDone() { @@ -812,7 +848,7 @@ public abstract class ForkJoinTask implements Future, Serializable { } public final boolean isCancelled() { - return status == CANCELLED; + return (status & DONE_MASK) == CANCELLED; } /** @@ -832,7 +868,7 @@ public abstract class ForkJoinTask implements Future, Serializable { * exception and was not cancelled */ public final boolean isCompletedNormally() { - return status == NORMAL; + return (status & DONE_MASK) == NORMAL; } /** @@ -843,7 +879,7 @@ public abstract class ForkJoinTask implements Future, Serializable { * @return the exception, or {@code null} if none */ public final Throwable getException() { - int s = status; + int s = status & DONE_MASK; return ((s >= NORMAL) ? null : (s == CANCELLED) ? new CancellationException() : getThrowableException()); @@ -893,6 +929,19 @@ public abstract class ForkJoinTask implements Future, Serializable { } /** + * Completes this task normally without setting a value. The most + * recent value established by {@link #setRawResult} (or {@code + * null} by default) will be returned as the result of subsequent + * invocations of {@code join} and related operations. + * + * @since 1.8 + * @hide + */ + public final void quietlyComplete() { + setCompletion(NORMAL); + } + + /** * Waits if necessary for the computation to complete, and then * retrieves its result. * @@ -905,9 +954,9 @@ public abstract class ForkJoinTask implements Future, Serializable { */ public final V get() throws InterruptedException, ExecutionException { int s = (Thread.currentThread() instanceof ForkJoinWorkerThread) ? - doJoin() : externalInterruptibleAwaitDone(0L); + doJoin() : externalInterruptibleAwaitDone(); Throwable ex; - if (s == CANCELLED) + if ((s &= DONE_MASK) == CANCELLED) throw new CancellationException(); if (s == EXCEPTIONAL && (ex = getThrowableException()) != null) throw new ExecutionException(ex); @@ -930,32 +979,63 @@ public abstract class ForkJoinTask implements Future, Serializable { */ public final V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { - Thread t = Thread.currentThread(); - if (t instanceof ForkJoinWorkerThread) { - ForkJoinWorkerThread w = (ForkJoinWorkerThread) t; - long nanos = unit.toNanos(timeout); - if (status >= 0) { - boolean completed = false; - if (w.unpushTask(this)) { - try { - completed = exec(); - } catch (Throwable rex) { - setExceptionalCompletion(rex); + if (Thread.interrupted()) + throw new InterruptedException(); + // Messy in part because we measure in nanosecs, but wait in millisecs + int s; long ms; + long ns = unit.toNanos(timeout); + if ((s = status) >= 0 && ns > 0L) { + long deadline = System.nanoTime() + ns; + ForkJoinPool p = null; + ForkJoinPool.WorkQueue w = null; + Thread t = Thread.currentThread(); + if (t instanceof ForkJoinWorkerThread) { + ForkJoinWorkerThread wt = (ForkJoinWorkerThread)t; + p = wt.pool; + w = wt.workQueue; + p.helpJoinOnce(w, this); // no retries on failure + } + else + ForkJoinPool.externalHelpJoin(this); + boolean canBlock = false; + boolean interrupted = false; + try { + while ((s = status) >= 0) { + if (w != null && w.qlock < 0) + cancelIgnoringExceptions(this); + else if (!canBlock) { + if (p == null || p.tryCompensate()) + canBlock = true; + } + else { + if ((ms = TimeUnit.NANOSECONDS.toMillis(ns)) > 0L && + U.compareAndSwapInt(this, STATUS, s, s | SIGNAL)) { + synchronized (this) { + if (status >= 0) { + try { + wait(ms); + } catch (InterruptedException ie) { + if (p == null) + interrupted = true; + } + } + else + notifyAll(); + } + } + if ((s = status) < 0 || interrupted || + (ns = deadline - System.nanoTime()) <= 0L) + break; } } - if (completed) - setCompletion(NORMAL); - else if (status >= 0 && nanos > 0) - w.pool.timedAwaitJoin(this, nanos); + } finally { + if (p != null && canBlock) + p.incrementActiveCount(); } + if (interrupted) + throw new InterruptedException(); } - else { - long millis = unit.toMillis(timeout); - if (millis > 0) - externalInterruptibleAwaitDone(millis); - } - int s = status; - if (s != NORMAL) { + if ((s &= DONE_MASK) != NORMAL) { Throwable ex; if (s == CANCELLED) throw new CancellationException(); @@ -992,16 +1072,15 @@ public abstract class ForkJoinTask implements Future, Serializable { * be of use in designs in which many tasks are forked, but none * are explicitly joined, instead executing them until all are * processed. - * - *

    This method may be invoked only from within {@code - * ForkJoinPool} computations (as may be determined using method - * {@link #inForkJoinPool}). Attempts to invoke in other contexts - * result in exceptions or errors, possibly including {@code - * ClassCastException}. */ public static void helpQuiesce() { - ((ForkJoinWorkerThread) Thread.currentThread()) - .helpQuiescePool(); + Thread t; + if ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) { + ForkJoinWorkerThread wt = (ForkJoinWorkerThread)t; + wt.pool.helpQuiescePool(wt.workQueue); + } + else + ForkJoinPool.externalHelpQuiescePool(); } /** @@ -1021,7 +1100,7 @@ public abstract class ForkJoinTask implements Future, Serializable { * setRawResult(null)}. */ public void reinitialize() { - if (status == EXCEPTIONAL) + if ((status & DONE_MASK) == EXCEPTIONAL) clearExceptionalCompletion(); else status = 0; @@ -1054,23 +1133,19 @@ public abstract class ForkJoinTask implements Future, Serializable { /** * Tries to unschedule this task for execution. This method will - * typically succeed if this task is the most recently forked task - * by the current thread, and has not commenced executing in - * another thread. This method may be useful when arranging - * alternative local processing of tasks that could have been, but - * were not, stolen. - * - *

    This method may be invoked only from within {@code - * ForkJoinPool} computations (as may be determined using method - * {@link #inForkJoinPool}). Attempts to invoke in other contexts - * result in exceptions or errors, possibly including {@code - * ClassCastException}. + * typically (but is not guaranteed to) succeed if this task is + * the most recently forked task by the current thread, and has + * not commenced executing in another thread. This method may be + * useful when arranging alternative local processing of tasks + * that could have been, but were not, stolen. * * @return {@code true} if unforked */ public boolean tryUnfork() { - return ((ForkJoinWorkerThread) Thread.currentThread()) - .unpushTask(this); + Thread t; + return (((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) ? + ((ForkJoinWorkerThread)t).workQueue.tryUnpush(this) : + ForkJoinPool.tryExternalUnpush(this)); } /** @@ -1079,40 +1154,32 @@ public abstract class ForkJoinTask implements Future, Serializable { * value may be useful for heuristic decisions about whether to * fork other tasks. * - *

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

    This method may be invoked only from within {@code - * ForkJoinPool} computations (as may be determined using method - * {@link #inForkJoinPool}). Attempts to invoke in other contexts - * result in exceptions or errors, possibly including {@code - * ClassCastException}. - * * @return the surplus number of tasks, which may be negative */ public static int getSurplusQueuedTaskCount() { - return ((ForkJoinWorkerThread) Thread.currentThread()) - .getEstimatedSurplusTaskCount(); + return ForkJoinPool.getSurplusQueuedTaskCount(); } // Extension methods @@ -1138,15 +1205,18 @@ public abstract class ForkJoinTask implements Future, Serializable { protected abstract void setRawResult(V value); /** - * Immediately performs the base action of this task. This method - * is designed to support extensions, and should not in general be - * called otherwise. The return value controls whether this task - * is considered to be done normally. It may return false in + * Immediately performs the base action of this task and returns + * true if, upon return from this method, this task is guaranteed + * to have completed normally. This method may return false + * otherwise, to indicate that this task is not necessarily + * complete (or is not known to be complete), for example in * asynchronous actions that require explicit invocations of - * {@link #complete} to become joinable. It may also throw an - * (unchecked) exception to indicate abnormal exit. + * completion methods. This method may also throw an (unchecked) + * exception to indicate abnormal exit. This method is designed to + * support extensions, and should not in general be called + * otherwise. * - * @return {@code true} if completed normally + * @return {@code true} if this task is known to have completed normally */ protected abstract boolean exec(); @@ -1160,59 +1230,105 @@ public abstract class ForkJoinTask implements Future, Serializable { * primarily to support extensions, and is unlikely to be useful * otherwise. * - *

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

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

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

    * Sample Usage (Note that the following classes are all @@ -43,16 +43,16 @@ package java.util.concurrent; * } * }} * - * The {@link FutureTask} class is an implementation of Future that - * implements Runnable, and so may be executed by an Executor. - * For example, the above construction with submit could be replaced by: + * The {@link FutureTask} class is an implementation of {@code Future} that + * implements {@code Runnable}, and so may be executed by an {@code Executor}. + * For example, the above construction with {@code submit} could be replaced by: *

     {@code
    - *     FutureTask future =
    - *       new FutureTask(new Callable() {
    - *         public String call() {
    - *           return searcher.search(target);
    - *       }});
    - *     executor.execute(future);}
    + * FutureTask future = + * new FutureTask(new Callable() { + * public String call() { + * return searcher.search(target); + * }}); + * executor.execute(future);} * *

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

    After this method returns, subsequent calls to {@link #isDone} will - * always return true. Subsequent calls to {@link #isCancelled} - * will always return true if this method returned true. + * always return {@code true}. Subsequent calls to {@link #isCancelled} + * will always return {@code true} if this method returned {@code true}. * - * @param mayInterruptIfRunning true if the thread executing this + * @param mayInterruptIfRunning {@code true} if the thread executing this * task should be interrupted; otherwise, in-progress tasks are allowed * to complete - * @return false if the task could not be cancelled, + * @return {@code false} if the task could not be cancelled, * typically because it has already completed normally; - * true otherwise + * {@code true} otherwise */ boolean cancel(boolean mayInterruptIfRunning); /** - * Returns true if this task was cancelled before it completed + * Returns {@code true} if this task was cancelled before it completed * normally. * - * @return true if this task was cancelled before it completed + * @return {@code true} if this task was cancelled before it completed */ boolean isCancelled(); /** - * Returns true if this task completed. + * Returns {@code true} if this task completed. * * Completion may be due to normal termination, an exception, or * cancellation -- in all of these cases, this method will return - * true. + * {@code true}. * - * @return true if this task completed + * @return {@code true} if this task completed */ boolean isDone(); diff --git a/luni/src/main/java/java/util/concurrent/FutureTask.java b/luni/src/main/java/java/util/concurrent/FutureTask.java index d51881d..114fe49 100644 --- a/luni/src/main/java/java/util/concurrent/FutureTask.java +++ b/luni/src/main/java/java/util/concurrent/FutureTask.java @@ -83,12 +83,11 @@ public class FutureTask implements RunnableFuture { * * @param s completed state value */ + @SuppressWarnings("unchecked") private V report(int s) throws ExecutionException { Object x = outcome; - if (s == NORMAL) { - @SuppressWarnings("unchecked") V v = (V)x; - return v; - } + if (s == NORMAL) + return (V)x; if (s >= CANCELLED) throw new CancellationException(); throw new ExecutionException((Throwable)x); @@ -134,19 +133,23 @@ public class FutureTask implements RunnableFuture { } public boolean cancel(boolean mayInterruptIfRunning) { - if (state != NEW) + if (!(state == NEW && + UNSAFE.compareAndSwapInt(this, stateOffset, NEW, + mayInterruptIfRunning ? INTERRUPTING : CANCELLED))) return false; - if (mayInterruptIfRunning) { - if (!UNSAFE.compareAndSwapInt(this, stateOffset, NEW, INTERRUPTING)) - return false; - Thread t = runner; - if (t != null) - t.interrupt(); - UNSAFE.putOrderedInt(this, stateOffset, INTERRUPTED); // final state + try { // in case call to interrupt throws exception + if (mayInterruptIfRunning) { + try { + Thread t = runner; + if (t != null) + t.interrupt(); + } finally { // final state + UNSAFE.putOrderedInt(this, stateOffset, INTERRUPTED); + } + } + } finally { + finishCompletion(); } - else if (!UNSAFE.compareAndSwapInt(this, stateOffset, NEW, CANCELLED)) - return false; - finishCompletion(); return true; } @@ -363,7 +366,7 @@ public class FutureTask implements RunnableFuture { */ private int awaitDone(boolean timed, long nanos) throws InterruptedException { - long last = timed ? System.nanoTime() : 0L; + final long deadline = timed ? System.nanoTime() + nanos : 0L; WaitNode q = null; boolean queued = false; for (;;) { @@ -378,18 +381,19 @@ public class FutureTask implements RunnableFuture { q.thread = null; return s; } + else if (s == COMPLETING) // cannot time out yet + Thread.yield(); else if (q == null) q = new WaitNode(); else if (!queued) queued = UNSAFE.compareAndSwapObject(this, waitersOffset, q.next = waiters, q); else if (timed) { - long now = System.nanoTime(); - if ((nanos -= (now - last)) <= 0L) { + nanos = deadline - System.nanoTime(); + if (nanos <= 0L) { removeWaiter(q); return state; } - last = now; LockSupport.parkNanos(this, nanos); } else diff --git a/luni/src/main/java/java/util/concurrent/LinkedBlockingDeque.java b/luni/src/main/java/java/util/concurrent/LinkedBlockingDeque.java index 6f32c47..64b0bf1 100644 --- a/luni/src/main/java/java/util/concurrent/LinkedBlockingDeque.java +++ b/luni/src/main/java/java/util/concurrent/LinkedBlockingDeque.java @@ -21,7 +21,7 @@ import java.util.concurrent.locks.ReentrantLock; * An optionally-bounded {@linkplain BlockingDeque blocking deque} based on * linked nodes. * - *

    The optional capacity bound constructor argument serves as a + *

    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 @@ -44,7 +44,7 @@ import java.util.concurrent.locks.ReentrantLock; */ public class LinkedBlockingDeque extends AbstractQueue - implements BlockingDeque, java.io.Serializable { + implements BlockingDeque, java.io.Serializable { /* * Implemented as a simple doubly-linked list protected by a @@ -1123,11 +1123,10 @@ public class LinkedBlockingDeque } /** - * Saves the state of this deque to a stream (that is, serializes it). + * Saves this deque to a stream (that is, serializes 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 { @@ -1148,8 +1147,6 @@ public class LinkedBlockingDeque /** * Reconstitutes this deque from a stream (that is, deserializes it). - * - * @param s the stream */ private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { diff --git a/luni/src/main/java/java/util/concurrent/LinkedBlockingQueue.java b/luni/src/main/java/java/util/concurrent/LinkedBlockingQueue.java index e8c9edb..0719828 100644 --- a/luni/src/main/java/java/util/concurrent/LinkedBlockingQueue.java +++ b/luni/src/main/java/java/util/concurrent/LinkedBlockingQueue.java @@ -31,7 +31,7 @@ import java.util.NoSuchElementException; * Linked queues typically have higher throughput than array-based queues but * less predictable performance in most concurrent applications. * - *

    The optional capacity bound constructor argument serves as a + *

    The optional capacity bound constructor argument serves as a * way to prevent excessive queue expansion. The capacity, if unspecified, * is equal to {@link Integer#MAX_VALUE}. Linked nodes are * dynamically created upon each insertion unless this would bring the @@ -44,7 +44,6 @@ import java.util.NoSuchElementException; * @since 1.5 * @author Doug Lea * @param the type of elements held in this collection - * */ public class LinkedBlockingQueue extends AbstractQueue implements BlockingQueue, java.io.Serializable { @@ -188,7 +187,7 @@ public class LinkedBlockingQueue extends AbstractQueue } /** - * Lock to prevent both puts and takes. + * Locks to prevent both puts and takes. */ void fullyLock() { putLock.lock(); @@ -196,7 +195,7 @@ public class LinkedBlockingQueue extends AbstractQueue } /** - * Unlock to allow both puts and takes. + * Unlocks to allow both puts and takes. */ void fullyUnlock() { takeLock.unlock(); @@ -262,7 +261,6 @@ public class LinkedBlockingQueue extends AbstractQueue } } - // this doc comment is overridden to remove the reference to collections // greater in size than Integer.MAX_VALUE /** @@ -335,7 +333,7 @@ public class LinkedBlockingQueue extends AbstractQueue * necessary up to the specified wait time for space to become available. * * @return {@code true} if successful, or {@code false} if - * the specified waiting time elapses before space is available. + * the specified waiting time elapses before space is available * @throws InterruptedException {@inheritDoc} * @throws NullPointerException {@inheritDoc} */ @@ -401,7 +399,6 @@ public class LinkedBlockingQueue extends AbstractQueue return c >= 0; } - public E take() throws InterruptedException { E x; int c = -1; @@ -756,6 +753,7 @@ public class LinkedBlockingQueue extends AbstractQueue * item to hand out so that if hasNext() reports true, we will * still have it to return even if lost race with a take etc. */ + private Node current; private Node lastRet; private E currentElement; @@ -830,12 +828,11 @@ public class LinkedBlockingQueue extends AbstractQueue } /** - * Saves the state to a stream (that is, serializes it). + * Saves this queue to a stream (that is, serializes it). * * @serialData The capacity is emitted (int), followed by all of * its elements (each an {@code Object}) in the proper order, * followed by a null - * @param s the stream */ private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException { @@ -858,8 +855,6 @@ public class LinkedBlockingQueue extends AbstractQueue /** * Reconstitutes this queue from a stream (that is, deserializes it). - * - * @param s the stream */ private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { diff --git a/luni/src/main/java/java/util/concurrent/LinkedTransferQueue.java b/luni/src/main/java/java/util/concurrent/LinkedTransferQueue.java index 2a3446e..cff5dbf 100644 --- a/luni/src/main/java/java/util/concurrent/LinkedTransferQueue.java +++ b/luni/src/main/java/java/util/concurrent/LinkedTransferQueue.java @@ -667,7 +667,7 @@ public class LinkedTransferQueue extends AbstractQueue * @return matched item, or e if unmatched on interrupt or timeout */ private E awaitMatch(Node s, Node pred, E e, boolean timed, long nanos) { - long lastTime = timed ? System.nanoTime() : 0L; + final long deadline = timed ? System.nanoTime() + nanos : 0L; Thread w = Thread.currentThread(); int spins = -1; // initialized after first item and cancel checks ThreadLocalRandom randomYields = null; // bound if needed @@ -698,10 +698,9 @@ public class LinkedTransferQueue extends AbstractQueue s.waiter = w; // request unpark then recheck } else if (timed) { - long now = System.nanoTime(); - if ((nanos -= now - lastTime) > 0) + nanos = deadline - System.nanoTime(); + if (nanos > 0L) LockSupport.parkNanos(this, nanos); - lastTime = now; } else { LockSupport.park(this); @@ -980,7 +979,6 @@ public class LinkedTransferQueue extends AbstractQueue return false; } - /** * Creates an initially empty {@code LinkedTransferQueue}. */ @@ -1267,11 +1265,10 @@ public class LinkedTransferQueue extends AbstractQueue } /** - * Saves the state to a stream (that is, serializes it). + * Saves this queue to a stream (that is, serializes it). * * @serialData All of the elements (each an {@code E}) in * the proper order, followed by a null - * @param s the stream */ private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException { @@ -1283,16 +1280,14 @@ public class LinkedTransferQueue extends AbstractQueue } /** - * Reconstitutes the Queue instance from a stream (that is, - * deserializes it). - * - * @param s the stream + * Reconstitutes this queue from a stream (that is, deserializes it). */ private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { s.defaultReadObject(); for (;;) { - @SuppressWarnings("unchecked") E item = (E) s.readObject(); + @SuppressWarnings("unchecked") + E item = (E) s.readObject(); if (item == null) break; else diff --git a/luni/src/main/java/java/util/concurrent/Phaser.java b/luni/src/main/java/java/util/concurrent/Phaser.java index 25ff743..a9adbe5 100644 --- a/luni/src/main/java/java/util/concurrent/Phaser.java +++ b/luni/src/main/java/java/util/concurrent/Phaser.java @@ -17,7 +17,7 @@ import java.util.concurrent.locks.LockSupport; * {@link java.util.concurrent.CountDownLatch CountDownLatch} * but supporting more flexible usage. * - *

    Registration. Unlike the case for other barriers, the + *

    Registration. Unlike the case for other barriers, the * number of parties registered to synchronize on a phaser * may vary over time. Tasks may be registered at any time (using * methods {@link #register}, {@link #bulkRegister}, or forms of @@ -30,7 +30,7 @@ import java.util.concurrent.locks.LockSupport; * (However, you can introduce such bookkeeping by subclassing this * class.) * - *

    Synchronization. Like a {@code CyclicBarrier}, a {@code + *

    Synchronization. Like a {@code CyclicBarrier}, a {@code * Phaser} may be repeatedly awaited. Method {@link * #arriveAndAwaitAdvance} has effect analogous to {@link * java.util.concurrent.CyclicBarrier#await CyclicBarrier.await}. Each @@ -74,7 +74,7 @@ import java.util.concurrent.locks.LockSupport; * * * - *

    Termination. A phaser may enter a termination + *

    Termination. A phaser may enter a termination * state, that may be checked using method {@link #isTerminated}. Upon * termination, all synchronization methods immediately return without * waiting for advance, as indicated by a negative return value. @@ -89,7 +89,7 @@ import java.util.concurrent.locks.LockSupport; * also available to abruptly release waiting threads and allow them * to terminate. * - *

    Tiering. Phasers may be tiered (i.e., + *

    Tiering. Phasers may be tiered (i.e., * constructed in tree structures) to reduce contention. Phasers with * large numbers of parties that would otherwise experience heavy * synchronization contention costs may instead be set up so that @@ -1065,7 +1065,7 @@ public class Phaser { final boolean timed; boolean wasInterrupted; long nanos; - long lastTime; + final long deadline; volatile Thread thread; // nulled to cancel wait QNode next; @@ -1076,7 +1076,7 @@ public class Phaser { this.interruptible = interruptible; this.nanos = nanos; this.timed = timed; - this.lastTime = timed ? System.nanoTime() : 0L; + this.deadline = timed ? System.nanoTime() + nanos : 0L; thread = Thread.currentThread(); } @@ -1095,9 +1095,7 @@ public class Phaser { } if (timed) { if (nanos > 0L) { - long now = System.nanoTime(); - nanos -= now - lastTime; - lastTime = now; + nanos = deadline - System.nanoTime(); } if (nanos <= 0L) { thread = null; @@ -1112,7 +1110,7 @@ public class Phaser { return true; else if (!timed) LockSupport.park(this); - else if (nanos > 0) + else if (nanos > 0L) LockSupport.parkNanos(this, nanos); return isReleasable(); } diff --git a/luni/src/main/java/java/util/concurrent/PriorityBlockingQueue.java b/luni/src/main/java/java/util/concurrent/PriorityBlockingQueue.java index 26c72eb..0f9e715 100644 --- a/luni/src/main/java/java/util/concurrent/PriorityBlockingQueue.java +++ b/luni/src/main/java/java/util/concurrent/PriorityBlockingQueue.java @@ -6,7 +6,8 @@ package java.util.concurrent; -import java.util.concurrent.locks.*; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.ReentrantLock; import java.util.*; // BEGIN android-note @@ -65,6 +66,7 @@ import java.util.*; * @author Doug Lea * @param the type of elements held in this collection */ +@SuppressWarnings("unchecked") public class PriorityBlockingQueue extends AbstractQueue implements BlockingQueue, java.io.Serializable { private static final long serialVersionUID = 5595510919245408276L; @@ -311,7 +313,6 @@ public class PriorityBlockingQueue extends AbstractQueue * @param k the position to fill * @param x the item to insert * @param array the heap array - * @param n heap size */ private static void siftUpComparable(int k, T x, Object[] array) { Comparable key = (Comparable) x; @@ -351,39 +352,43 @@ public class PriorityBlockingQueue extends AbstractQueue */ private static void siftDownComparable(int k, T x, Object[] array, int n) { - Comparable key = (Comparable)x; - int half = n >>> 1; // loop while a non-leaf - while (k < half) { - int child = (k << 1) + 1; // assume left child is least - Object c = array[child]; - int right = child + 1; - if (right < n && - ((Comparable) c).compareTo((T) array[right]) > 0) - c = array[child = right]; - if (key.compareTo((T) c) <= 0) - break; - array[k] = c; - k = child; + if (n > 0) { + Comparable key = (Comparable)x; + int half = n >>> 1; // loop while a non-leaf + while (k < half) { + int child = (k << 1) + 1; // assume left child is least + Object c = array[child]; + int right = child + 1; + if (right < n && + ((Comparable) c).compareTo((T) array[right]) > 0) + c = array[child = right]; + if (key.compareTo((T) c) <= 0) + break; + array[k] = c; + k = child; + } + array[k] = key; } - array[k] = key; } private static void siftDownUsingComparator(int k, T x, Object[] array, int n, Comparator cmp) { - int half = n >>> 1; - while (k < half) { - int child = (k << 1) + 1; - Object c = array[child]; - int right = child + 1; - if (right < n && cmp.compare((T) c, (T) array[right]) > 0) - c = array[child = right]; - if (cmp.compare(x, (T) c) <= 0) - break; - array[k] = c; - k = child; + if (n > 0) { + int half = n >>> 1; + while (k < half) { + int child = (k << 1) + 1; + Object c = array[child]; + int right = child + 1; + if (right < n && cmp.compare((T) c, (T) array[right]) > 0) + c = array[child = right]; + if (cmp.compare(x, (T) c) <= 0) + break; + array[k] = c; + k = child; + } + array[k] = x; } - array[k] = x; } /** @@ -866,10 +871,11 @@ public class PriorityBlockingQueue extends AbstractQueue } /** - * Saves the state to a stream (that is, serializes it). For - * compatibility with previous version of this class, - * elements are first copied to a java.util.PriorityQueue, - * which is then serialized. + * Saves this queue to a stream (that is, serializes it). + * + * For compatibility with previous version of this class, elements + * are first copied to a java.util.PriorityQueue, which is then + * serialized. */ private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException { @@ -886,10 +892,7 @@ public class PriorityBlockingQueue extends AbstractQueue } /** - * Reconstitutes the {@code PriorityBlockingQueue} instance from a stream - * (that is, deserializes it). - * - * @param s the stream + * Reconstitutes this queue from a stream (that is, deserializes it). */ private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { diff --git a/luni/src/main/java/java/util/concurrent/RecursiveAction.java b/luni/src/main/java/java/util/concurrent/RecursiveAction.java index 48066c9..8d666f6 100644 --- a/luni/src/main/java/java/util/concurrent/RecursiveAction.java +++ b/luni/src/main/java/java/util/concurrent/RecursiveAction.java @@ -34,7 +34,7 @@ package java.util.concurrent; * } * } * // implementation details follow: - * final static int THRESHOLD = 1000; + * static final int THRESHOLD = 1000; * void sortSequentially(int lo, int hi) { * Arrays.sort(array, lo, hi); * } @@ -111,21 +111,21 @@ package java.util.concurrent; * int h = hi; * Applyer right = null; * while (h - l > 1 && getSurplusQueuedTaskCount() <= 3) { - * int mid = (l + h) >>> 1; - * right = new Applyer(array, mid, h, right); - * right.fork(); - * h = mid; + * int mid = (l + h) >>> 1; + * right = new Applyer(array, mid, h, right); + * right.fork(); + * h = mid; * } * double sum = atLeaf(l, h); * while (right != null) { - * if (right.tryUnfork()) // directly calculate if not stolen - * sum += right.atLeaf(right.lo, right.hi); + * if (right.tryUnfork()) // directly calculate if not stolen + * sum += right.atLeaf(right.lo, right.hi); * else { - * right.join(); - * sum += right.result; - * } - * right = right.next; - * } + * right.join(); + * sum += right.result; + * } + * right = right.next; + * } * result = sum; * } * }} diff --git a/luni/src/main/java/java/util/concurrent/RecursiveTask.java b/luni/src/main/java/java/util/concurrent/RecursiveTask.java index 5e17280..421c9d3 100644 --- a/luni/src/main/java/java/util/concurrent/RecursiveTask.java +++ b/luni/src/main/java/java/util/concurrent/RecursiveTask.java @@ -17,7 +17,7 @@ package java.util.concurrent; * Fibonacci(int n) { this.n = n; } * Integer compute() { * if (n <= 1) - * return n; + * return n; * Fibonacci f1 = new Fibonacci(n - 1); * f1.fork(); * Fibonacci f2 = new Fibonacci(n - 2); diff --git a/luni/src/main/java/java/util/concurrent/RejectedExecutionException.java b/luni/src/main/java/java/util/concurrent/RejectedExecutionException.java index f0005d1..c61365f 100644 --- a/luni/src/main/java/java/util/concurrent/RejectedExecutionException.java +++ b/luni/src/main/java/java/util/concurrent/RejectedExecutionException.java @@ -17,14 +17,14 @@ public class RejectedExecutionException extends RuntimeException { private static final long serialVersionUID = -375805702767069545L; /** - * Constructs a RejectedExecutionException with no detail message. + * Constructs a {@code RejectedExecutionException} with no detail message. * The cause is not initialized, and may subsequently be * initialized by a call to {@link #initCause(Throwable) initCause}. */ public RejectedExecutionException() { } /** - * Constructs a RejectedExecutionException with the + * Constructs a {@code RejectedExecutionException} with the * specified detail message. The cause is not initialized, and may * subsequently be initialized by a call to {@link * #initCause(Throwable) initCause}. @@ -36,7 +36,7 @@ public class RejectedExecutionException extends RuntimeException { } /** - * Constructs a RejectedExecutionException with the + * Constructs a {@code RejectedExecutionException} with the * specified detail message and cause. * * @param message the detail message @@ -48,10 +48,10 @@ public class RejectedExecutionException extends RuntimeException { } /** - * Constructs a RejectedExecutionException with the + * Constructs a {@code RejectedExecutionException} with the * specified cause. The detail message is set to {@code (cause == * null ? null : cause.toString())} (which typically contains - * the class and detail message of cause). + * the class and detail message of {@code cause}). * * @param cause the cause (which is saved for later retrieval by the * {@link #getCause()} method) diff --git a/luni/src/main/java/java/util/concurrent/RunnableFuture.java b/luni/src/main/java/java/util/concurrent/RunnableFuture.java index 2d6d52c..ccd28e3 100644 --- a/luni/src/main/java/java/util/concurrent/RunnableFuture.java +++ b/luni/src/main/java/java/util/concurrent/RunnableFuture.java @@ -8,13 +8,13 @@ package java.util.concurrent; /** * A {@link Future} that is {@link Runnable}. Successful execution of - * the run method causes completion of the Future + * the {@code run} method causes completion of the {@code Future} * and allows access to its results. * @see FutureTask * @see Executor * @since 1.6 * @author Doug Lea - * @param The result type returned by this Future's get method + * @param The result type returned by this Future's {@code get} method */ public interface RunnableFuture extends Runnable, Future { /** diff --git a/luni/src/main/java/java/util/concurrent/RunnableScheduledFuture.java b/luni/src/main/java/java/util/concurrent/RunnableScheduledFuture.java index fbb995c..7125233 100644 --- a/luni/src/main/java/java/util/concurrent/RunnableScheduledFuture.java +++ b/luni/src/main/java/java/util/concurrent/RunnableScheduledFuture.java @@ -8,13 +8,13 @@ package java.util.concurrent; /** * A {@link ScheduledFuture} that is {@link Runnable}. Successful - * execution of the run method causes completion of the - * Future and allows access to its results. + * execution of the {@code run} method causes completion of the + * {@code Future} and allows access to its results. * @see FutureTask * @see Executor * @since 1.6 * @author Doug Lea - * @param The result type returned by this Future's get method + * @param The result type returned by this Future's {@code get} method */ public interface RunnableScheduledFuture extends RunnableFuture, ScheduledFuture { diff --git a/luni/src/main/java/java/util/concurrent/ScheduledExecutorService.java b/luni/src/main/java/java/util/concurrent/ScheduledExecutorService.java index 71e57ed..b978fae 100644 --- a/luni/src/main/java/java/util/concurrent/ScheduledExecutorService.java +++ b/luni/src/main/java/java/util/concurrent/ScheduledExecutorService.java @@ -10,26 +10,26 @@ package java.util.concurrent; * An {@link ExecutorService} that can schedule commands to run after a given * delay, or to execute periodically. * - *

    The schedule methods create tasks with various delays + *

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

    Commands submitted using the {@link Executor#execute} and - * {@link ExecutorService} submit methods are scheduled with + *

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

    All schedule methods accept relative delays and + *

    All {@code schedule} methods accept relative delays and * periods as arguments, not absolute times or dates. It is a simple * matter to transform an absolute time represented as a {@link * java.util.Date} to the required form. For example, to schedule at - * a certain future date, you can use: schedule(task, + * a certain future {@code date}, you can use: {@code schedule(task, * date.getTime() - System.currentTimeMillis(), - * TimeUnit.MILLISECONDS). Beware however that expiration of a - * relative delay need not coincide with the current Date at + * TimeUnit.MILLISECONDS)}. Beware however that expiration of a + * relative delay need not coincide with the current {@code Date} at * which the task is enabled due to network time synchronization * protocols, clock drift, or other factors. * @@ -72,8 +72,8 @@ public interface ScheduledExecutorService extends ExecutorService { * @param delay the time from now to delay execution * @param unit the time unit of the delay parameter * @return a ScheduledFuture representing pending completion of - * the task and whose get() method will return - * null upon completion + * the task and whose {@code get()} method will return + * {@code null} upon completion * @throws RejectedExecutionException if the task cannot be * scheduled for execution * @throws NullPointerException if command is null @@ -100,8 +100,8 @@ public interface ScheduledExecutorService extends ExecutorService { * Creates and executes a periodic action that becomes enabled first * after the given initial delay, and subsequently with the given * period; that is executions will commence after - * initialDelay then initialDelay+period, then - * initialDelay + 2 * period, and so on. + * {@code initialDelay} then {@code initialDelay+period}, then + * {@code initialDelay + 2 * period}, and so on. * If any execution of the task * encounters an exception, subsequent executions are suppressed. * Otherwise, the task will only terminate via cancellation or @@ -114,7 +114,7 @@ public interface ScheduledExecutorService extends ExecutorService { * @param period the period between successive executions * @param unit the time unit of the initialDelay and period parameters * @return a ScheduledFuture representing pending completion of - * the task, and whose get() method will throw an + * the task, and whose {@code get()} method will throw an * exception upon cancellation * @throws RejectedExecutionException if the task cannot be * scheduled for execution @@ -141,7 +141,7 @@ public interface ScheduledExecutorService extends ExecutorService { * execution and the commencement of the next * @param unit the time unit of the initialDelay and delay parameters * @return a ScheduledFuture representing pending completion of - * the task, and whose get() method will throw an + * the task, and whose {@code get()} method will throw an * exception upon cancellation * @throws RejectedExecutionException if the task cannot be * scheduled for execution diff --git a/luni/src/main/java/java/util/concurrent/ScheduledThreadPoolExecutor.java b/luni/src/main/java/java/util/concurrent/ScheduledThreadPoolExecutor.java index e41f0c3..a52351b 100644 --- a/luni/src/main/java/java/util/concurrent/ScheduledThreadPoolExecutor.java +++ b/luni/src/main/java/java/util/concurrent/ScheduledThreadPoolExecutor.java @@ -13,7 +13,6 @@ import java.util.*; // BEGIN android-note // omit class-level docs on setRemoveOnCancelPolicy() -// removed security manager docs // END android-note /** @@ -31,7 +30,7 @@ import java.util.*; * submission. * *

    When a submitted task is cancelled before it is run, execution - * is suppressed. Such a cancelled task is not + * 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. @@ -54,7 +53,7 @@ import java.util.*; * without threads to handle tasks once they become eligible to run. * *

    Extension notes: This class overrides the - * {@link ThreadPoolExecutor#execute execute} and + * {@link ThreadPoolExecutor#execute(Runnable) execute} and * {@link AbstractExecutorService#submit(Runnable) submit} * methods to generate internal {@link ScheduledFuture} objects to * control per-task delays and scheduling. To preserve @@ -196,7 +195,7 @@ public class ScheduledThreadPoolExecutor } /** - * Creates a one-shot action with given nanoTime-based trigger. + * Creates a one-shot action with given nanoTime-based trigger time. */ ScheduledFutureTask(Callable callable, long ns) { super(callable); @@ -224,15 +223,14 @@ public class ScheduledThreadPoolExecutor else return 1; } - long diff = (getDelay(NANOSECONDS) - - other.getDelay(NANOSECONDS)); + long diff = getDelay(NANOSECONDS) - other.getDelay(NANOSECONDS); return (diff < 0) ? -1 : (diff > 0) ? 1 : 0; } /** - * Returns true if this is a periodic (not a one-shot) action. + * Returns {@code true} if this is a periodic (not a one-shot) action. * - * @return true if periodic + * @return {@code true} if periodic */ public boolean isPeriodic() { return period != 0; @@ -289,7 +287,7 @@ public class ScheduledThreadPoolExecutor * is shut down, rejects the task. Otherwise adds task to queue * and starts a thread, if necessary, to run it. (We cannot * prestart the thread to run the task because the task (probably) - * shouldn't be run yet,) If the pool is shut down while the task + * shouldn't be run yet.) If the pool is shut down while the task * is being added, cancel and remove it if required by state and * run-after-shutdown parameters. * @@ -628,7 +626,7 @@ public class ScheduledThreadPoolExecutor * {@code false} when already shutdown. * This value is by default {@code false}. * - * @param value if {@code true}, continue after shutdown, else don't. + * @param value if {@code true}, continue after shutdown, else don't * @see #getContinueExistingPeriodicTasksAfterShutdownPolicy */ public void setContinueExistingPeriodicTasksAfterShutdownPolicy(boolean value) { @@ -660,7 +658,7 @@ public class ScheduledThreadPoolExecutor * {@code false} when already shutdown. * This value is by default {@code true}. * - * @param value if {@code true}, execute after shutdown, else don't. + * @param value if {@code true}, execute after shutdown, else don't * @see #getExecuteExistingDelayedTasksAfterShutdownPolicy */ public void setExecuteExistingDelayedTasksAfterShutdownPolicy(boolean value) { @@ -834,7 +832,7 @@ public class ScheduledThreadPoolExecutor private final Condition available = lock.newCondition(); /** - * Set f's heapIndex if it is a ScheduledFutureTask. + * Sets f's heapIndex if it is a ScheduledFutureTask. */ private void setIndex(RunnableScheduledFuture f, int idx) { if (f instanceof ScheduledFutureTask) @@ -842,7 +840,7 @@ public class ScheduledThreadPoolExecutor } /** - * Sift element added at bottom up to its heap-ordered spot. + * Sifts element added at bottom up to its heap-ordered spot. * Call only when holding lock. */ private void siftUp(int k, RunnableScheduledFuture key) { @@ -860,7 +858,7 @@ public class ScheduledThreadPoolExecutor } /** - * Sift element added at top down to its heap-ordered spot. + * Sifts element added at top down to its heap-ordered spot. * Call only when holding lock. */ private void siftDown(int k, RunnableScheduledFuture key) { @@ -882,7 +880,7 @@ public class ScheduledThreadPoolExecutor } /** - * Resize the heap array. Call only when holding lock. + * Resizes the heap array. Call only when holding lock. */ private void grow() { int oldCapacity = queue.length; @@ -893,7 +891,7 @@ public class ScheduledThreadPoolExecutor } /** - * Find index of given object, or -1 if absent + * Finds index of given object, or -1 if absent. */ private int indexOf(Object x) { if (x != null) { @@ -1054,7 +1052,8 @@ public class ScheduledThreadPoolExecutor long delay = first.getDelay(NANOSECONDS); if (delay <= 0) return finishPoll(first); - else if (leader != null) + first = null; // don't retain ref while waiting + if (leader != null) available.await(); else { Thread thisThread = Thread.currentThread(); @@ -1094,6 +1093,7 @@ public class ScheduledThreadPoolExecutor return finishPoll(first); if (nanos <= 0) return null; + first = null; // don't retain ref while waiting if (nanos < delay || leader != null) nanos = available.awaitNanos(nanos); else { @@ -1134,7 +1134,7 @@ public class ScheduledThreadPoolExecutor } /** - * Return first element only if it is expired. + * Returns first element only if it is expired. * Used only by drainTo. Call only when holding lock. */ private RunnableScheduledFuture peekExpired() { diff --git a/luni/src/main/java/java/util/concurrent/Semaphore.java b/luni/src/main/java/java/util/concurrent/Semaphore.java index bf2524c..9ee18a8 100644 --- a/luni/src/main/java/java/util/concurrent/Semaphore.java +++ b/luni/src/main/java/java/util/concurrent/Semaphore.java @@ -5,8 +5,8 @@ */ package java.util.concurrent; -import java.util.*; -import java.util.concurrent.locks.*; +import java.util.Collection; +import java.util.concurrent.locks.AbstractQueuedSynchronizer; /** * A counting semaphore. Conceptually, a semaphore maintains a set of @@ -79,13 +79,13 @@ import java.util.concurrent.locks.*; * exclusion lock. This is more commonly known as a binary * semaphore, because it only has two states: one permit * available, or zero permits available. When used in this way, the - * binary semaphore has the property (unlike many {@link Lock} + * binary semaphore has the property (unlike many {@link java.util.concurrent.locks.Lock} * implementations), that the "lock" can be released by a * thread other than the owner (as semaphores have no notion of * ownership). This can be useful in some specialized contexts, such * as deadlock recovery. * - *

    The constructor for this class optionally accepts a + *

    The constructor for this class optionally accepts a * fairness parameter. When set false, this class makes no * guarantees about the order in which threads acquire permits. In * particular, barging is permitted, that is, a thread @@ -123,9 +123,7 @@ import java.util.concurrent.locks.*; * * @since 1.5 * @author Doug Lea - * */ - public class Semaphore implements java.io.Serializable { private static final long serialVersionUID = -3222578661600680210L; /** All mechanics via AbstractQueuedSynchronizer subclass */ @@ -461,7 +459,6 @@ public class Semaphore implements java.io.Serializable { * * @param permits the number of permits to acquire * @throws IllegalArgumentException if {@code permits} is negative - * */ public void acquireUninterruptibly(int permits) { if (permits < 0) throw new IllegalArgumentException(); diff --git a/luni/src/main/java/java/util/concurrent/SynchronousQueue.java b/luni/src/main/java/java/util/concurrent/SynchronousQueue.java index b05ae0a..ea6b3d1 100644 --- a/luni/src/main/java/java/util/concurrent/SynchronousQueue.java +++ b/luni/src/main/java/java/util/concurrent/SynchronousQueue.java @@ -6,7 +6,8 @@ */ package java.util.concurrent; -import java.util.concurrent.locks.*; +import java.util.concurrent.locks.LockSupport; +import java.util.concurrent.locks.ReentrantLock; import java.util.*; // BEGIN android-note @@ -18,17 +19,17 @@ import java.util.*; * operation must wait for a corresponding remove operation by another * thread, and vice versa. A synchronous queue does not have any * internal capacity, not even a capacity of one. You cannot - * peek at a synchronous queue because an element is only + * {@code peek} at a synchronous queue because an element is only * present when you try to remove it; you cannot insert an element * (using any method) unless another thread is trying to remove it; * you cannot iterate as there is nothing to iterate. The * head of the queue is the element that the first queued * inserting thread is trying to add to the queue; if there is no such * queued thread then no element is available for removal and - * poll() will return null. For purposes of other - * Collection methods (for example contains), a - * SynchronousQueue acts as an empty collection. This queue - * does not permit null elements. + * {@code poll()} will return {@code null}. For purposes of other + * {@code Collection} methods (for example {@code contains}), a + * {@code SynchronousQueue} acts as an empty collection. This queue + * does not permit {@code null} elements. * *

    Synchronous queues are similar to rendezvous channels used in * CSP and Ada. They are well suited for handoff designs, in which an @@ -36,10 +37,10 @@ import java.util.*; * in another thread in order to hand it some information, event, or * task. * - *

    This class supports an optional fairness policy for ordering + *

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

    This class and its iterator implement all of the * optional methods of the {@link Collection} and {@link @@ -133,7 +134,7 @@ public class SynchronousQueue extends AbstractQueue /** * Shared internal API for dual stacks and queues. */ - abstract static class Transferer { + abstract static class Transferer { /** * Performs a put or take. * @@ -147,7 +148,7 @@ public class SynchronousQueue extends AbstractQueue * the caller can distinguish which of these occurred * by checking Thread.interrupted. */ - abstract Object transfer(Object e, boolean timed, long nanos); + abstract E transfer(E e, boolean timed, long nanos); } /** The number of CPUs, for spin control */ @@ -176,7 +177,7 @@ public class SynchronousQueue extends AbstractQueue static final long spinForTimeoutThreshold = 1000L; /** Dual stack */ - static final class TransferStack extends Transferer { + static final class TransferStack extends Transferer { /* * This extends Scherer-Scott dual stack algorithm, differing, * among other ways, by using "covering" nodes rather than @@ -193,7 +194,7 @@ public class SynchronousQueue extends AbstractQueue /** Node is fulfilling another unfulfilled DATA or REQUEST */ static final int FULFILLING = 2; - /** Return true if m has fulfilling bit set */ + /** Returns true if m has fulfilling bit set. */ static boolean isFulfilling(int m) { return (m & FULFILLING) != 0; } /** Node class for TransferStacks. */ @@ -292,7 +293,8 @@ public class SynchronousQueue extends AbstractQueue /** * Puts or takes an item. */ - Object transfer(Object e, boolean timed, long nanos) { + @SuppressWarnings("unchecked") + E transfer(E e, boolean timed, long nanos) { /* * Basic algorithm is to loop trying one of three actions: * @@ -333,7 +335,7 @@ public class SynchronousQueue extends AbstractQueue } if ((h = head) != null && h.next == s) casHead(h, s.next); // help s's fulfiller - return (mode == REQUEST) ? m.item : s.item; + return (E) ((mode == REQUEST) ? m.item : s.item); } } else if (!isFulfilling(h.mode)) { // try to fulfill if (h.isCancelled()) // already cancelled @@ -349,7 +351,7 @@ public class SynchronousQueue extends AbstractQueue SNode mn = m.next; if (m.tryMatch(s)) { casHead(s, mn); // pop both s and m - return (mode == REQUEST) ? m.item : s.item; + return (E) ((mode == REQUEST) ? m.item : s.item); } else // lost match s.casNext(m, mn); // help unlink } @@ -400,7 +402,7 @@ public class SynchronousQueue extends AbstractQueue * and don't wait at all, so are trapped in transfer * method rather than calling awaitFulfill. */ - long lastTime = timed ? System.nanoTime() : 0; + final long deadline = timed ? System.nanoTime() + nanos : 0L; Thread w = Thread.currentThread(); int spins = (shouldSpin(s) ? (timed ? maxTimedSpins : maxUntimedSpins) : 0); @@ -411,10 +413,8 @@ public class SynchronousQueue extends AbstractQueue if (m != null) return m; if (timed) { - long now = System.nanoTime(); - nanos -= now - lastTime; - lastTime = now; - if (nanos <= 0) { + nanos = deadline - System.nanoTime(); + if (nanos <= 0L) { s.tryCancel(); continue; } @@ -492,7 +492,7 @@ public class SynchronousQueue extends AbstractQueue } /** Dual Queue */ - static final class TransferQueue extends Transferer { + static final class TransferQueue extends Transferer { /* * This extends Scherer-Scott dual queue algorithm, differing, * among other ways, by using modes within nodes rather than @@ -570,7 +570,7 @@ public class SynchronousQueue extends AbstractQueue /** * Reference to a cancelled node that might not yet have been * unlinked from queue because it was the last inserted node - * when it cancelled. + * when it was cancelled. */ transient volatile QNode cleanMe; @@ -609,7 +609,8 @@ public class SynchronousQueue extends AbstractQueue /** * Puts or takes an item. */ - Object transfer(Object e, boolean timed, long nanos) { + @SuppressWarnings("unchecked") + E transfer(E e, boolean timed, long nanos) { /* Basic algorithm is to loop trying to take either of * two actions: * @@ -672,7 +673,7 @@ public class SynchronousQueue extends AbstractQueue s.item = s; s.waiter = null; } - return (x != null) ? x : e; + return (x != null) ? (E)x : e; } else { // complementary-mode QNode m = h.next; // node to fulfill @@ -689,7 +690,7 @@ public class SynchronousQueue extends AbstractQueue advanceHead(h, m); // successfully fulfilled LockSupport.unpark(m.waiter); - return (x != null) ? x : e; + return (x != null) ? (E)x : e; } } } @@ -703,9 +704,9 @@ public class SynchronousQueue extends AbstractQueue * @param nanos timeout value * @return matched item, or s if cancelled */ - Object awaitFulfill(QNode s, Object e, boolean timed, long nanos) { + Object awaitFulfill(QNode s, E e, boolean timed, long nanos) { /* Same idea as TransferStack.awaitFulfill */ - long lastTime = timed ? System.nanoTime() : 0; + final long deadline = timed ? System.nanoTime() + nanos : 0L; Thread w = Thread.currentThread(); int spins = ((head.next == s) ? (timed ? maxTimedSpins : maxUntimedSpins) : 0); @@ -716,10 +717,8 @@ public class SynchronousQueue extends AbstractQueue if (x != e) return x; if (timed) { - long now = System.nanoTime(); - nanos -= now - lastTime; - lastTime = now; - if (nanos <= 0) { + nanos = deadline - System.nanoTime(); + if (nanos <= 0L) { s.tryCancel(e); continue; } @@ -816,23 +815,23 @@ public class SynchronousQueue extends AbstractQueue * isn't a noticeable performance penalty for using volatile * instead of final here. */ - private transient volatile Transferer transferer; + private transient volatile Transferer transferer; /** - * Creates a SynchronousQueue with nonfair access policy. + * Creates a {@code SynchronousQueue} with nonfair access policy. */ public SynchronousQueue() { this(false); } /** - * Creates a SynchronousQueue with the specified fairness policy. + * Creates a {@code SynchronousQueue} with the specified fairness policy. * * @param fair if true, waiting threads contend in FIFO order for * access; otherwise the order is unspecified. */ public SynchronousQueue(boolean fair) { - transferer = fair ? new TransferQueue() : new TransferStack(); + transferer = fair ? new TransferQueue() : new TransferStack(); } /** @@ -842,9 +841,9 @@ public class SynchronousQueue extends AbstractQueue * @throws InterruptedException {@inheritDoc} * @throws NullPointerException {@inheritDoc} */ - public void put(E o) throws InterruptedException { - if (o == null) throw new NullPointerException(); - if (transferer.transfer(o, false, 0) == null) { + public void put(E e) throws InterruptedException { + if (e == null) throw new NullPointerException(); + if (transferer.transfer(e, false, 0) == null) { Thread.interrupted(); throw new InterruptedException(); } @@ -854,15 +853,15 @@ public class SynchronousQueue extends AbstractQueue * Inserts the specified element into this queue, waiting if necessary * up to the specified wait time for another thread to receive it. * - * @return true if successful, or false if the - * specified waiting time elapses before a consumer appears. + * @return {@code true} if successful, or {@code false} if the + * specified waiting time elapses before a consumer appears * @throws InterruptedException {@inheritDoc} * @throws NullPointerException {@inheritDoc} */ - public boolean offer(E o, long timeout, TimeUnit unit) + public boolean offer(E e, long timeout, TimeUnit unit) throws InterruptedException { - if (o == null) throw new NullPointerException(); - if (transferer.transfer(o, true, unit.toNanos(timeout)) != null) + if (e == null) throw new NullPointerException(); + if (transferer.transfer(e, true, unit.toNanos(timeout)) != null) return true; if (!Thread.interrupted()) return false; @@ -874,8 +873,8 @@ public class SynchronousQueue extends AbstractQueue * waiting to receive it. * * @param e the element to add - * @return true if the element was added to this queue, else - * false + * @return {@code true} if the element was added to this queue, else + * {@code false} * @throws NullPointerException if the specified element is null */ public boolean offer(E e) { @@ -891,9 +890,9 @@ public class SynchronousQueue extends AbstractQueue * @throws InterruptedException {@inheritDoc} */ public E take() throws InterruptedException { - Object e = transferer.transfer(null, false, 0); + E e = transferer.transfer(null, false, 0); if (e != null) - return (E)e; + return e; Thread.interrupted(); throw new InterruptedException(); } @@ -903,14 +902,14 @@ public class SynchronousQueue extends AbstractQueue * if necessary up to the specified wait time, for another thread * to insert it. * - * @return the head of this queue, or null if the - * specified waiting time elapses before an element is present. + * @return the head of this queue, or {@code null} if the + * specified waiting time elapses before an element is present * @throws InterruptedException {@inheritDoc} */ public E poll(long timeout, TimeUnit unit) throws InterruptedException { - Object e = transferer.transfer(null, true, unit.toNanos(timeout)); + E e = transferer.transfer(null, true, unit.toNanos(timeout)); if (e != null || !Thread.interrupted()) - return (E)e; + return e; throw new InterruptedException(); } @@ -918,18 +917,18 @@ public class SynchronousQueue extends AbstractQueue * Retrieves and removes the head of this queue, if another thread * is currently making an element available. * - * @return the head of this queue, or null if no - * element is available. + * @return the head of this queue, or {@code null} if no + * element is available */ public E poll() { - return (E)transferer.transfer(null, true, 0); + return transferer.transfer(null, true, 0); } /** - * Always returns true. - * A SynchronousQueue has no internal capacity. + * Always returns {@code true}. + * A {@code SynchronousQueue} has no internal capacity. * - * @return true + * @return {@code true} */ public boolean isEmpty() { return true; @@ -937,9 +936,9 @@ public class SynchronousQueue extends AbstractQueue /** * Always returns zero. - * A SynchronousQueue has no internal capacity. + * A {@code SynchronousQueue} has no internal capacity. * - * @return zero. + * @return zero */ public int size() { return 0; @@ -947,9 +946,9 @@ public class SynchronousQueue extends AbstractQueue /** * Always returns zero. - * A SynchronousQueue has no internal capacity. + * A {@code SynchronousQueue} has no internal capacity. * - * @return zero. + * @return zero */ public int remainingCapacity() { return 0; @@ -957,80 +956,80 @@ public class SynchronousQueue extends AbstractQueue /** * Does nothing. - * A SynchronousQueue has no internal capacity. + * A {@code SynchronousQueue} has no internal capacity. */ public void clear() { } /** - * Always returns false. - * A SynchronousQueue has no internal capacity. + * Always returns {@code false}. + * A {@code SynchronousQueue} has no internal capacity. * * @param o the element - * @return false + * @return {@code false} */ public boolean contains(Object o) { return false; } /** - * Always returns false. - * A SynchronousQueue has no internal capacity. + * Always returns {@code false}. + * A {@code SynchronousQueue} has no internal capacity. * * @param o the element to remove - * @return false + * @return {@code false} */ public boolean remove(Object o) { return false; } /** - * Returns false unless the given collection is empty. - * A SynchronousQueue has no internal capacity. + * Returns {@code false} unless the given collection is empty. + * A {@code SynchronousQueue} has no internal capacity. * * @param c the collection - * @return false unless given collection is empty + * @return {@code false} unless given collection is empty */ public boolean containsAll(Collection c) { return c.isEmpty(); } /** - * Always returns false. - * A SynchronousQueue has no internal capacity. + * Always returns {@code false}. + * A {@code SynchronousQueue} has no internal capacity. * * @param c the collection - * @return false + * @return {@code false} */ public boolean removeAll(Collection c) { return false; } /** - * Always returns false. - * A SynchronousQueue has no internal capacity. + * Always returns {@code false}. + * A {@code SynchronousQueue} has no internal capacity. * * @param c the collection - * @return false + * @return {@code false} */ public boolean retainAll(Collection c) { return false; } /** - * Always returns null. - * A SynchronousQueue does not return elements + * Always returns {@code null}. + * A {@code SynchronousQueue} does not return elements * unless actively waited on. * - * @return null + * @return {@code null} */ public E peek() { return null; } /** - * Returns an empty iterator in which hasNext always returns - * false. + * Returns an empty iterator in which {@code hasNext} always returns + * {@code false}. * * @return an empty iterator */ @@ -1058,7 +1057,7 @@ public class SynchronousQueue extends AbstractQueue } /** - * Sets the zeroeth element of the specified array to null + * Sets the zeroeth element of the specified array to {@code null} * (if the array has non-zero length) and returns it. * * @param a the array @@ -1117,6 +1116,7 @@ public class SynchronousQueue extends AbstractQueue * object is ever serialized or deserialized. */ + @SuppressWarnings("serial") static class WaitQueue implements java.io.Serializable { } static class LifoWaitQueue extends WaitQueue { private static final long serialVersionUID = -3633113410248163686L; @@ -1129,9 +1129,7 @@ public class SynchronousQueue extends AbstractQueue private WaitQueue waitingConsumers; /** - * Saves the state to a stream (that is, serializes it). - * - * @param s the stream + * Saves this queue to a stream (that is, serializes it). */ private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException { @@ -1149,13 +1147,16 @@ public class SynchronousQueue extends AbstractQueue s.defaultWriteObject(); } + /** + * Reconstitutes this queue from a stream (that is, deserializes it). + */ private void readObject(final java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { s.defaultReadObject(); if (waitingProducers instanceof FifoWaitQueue) - transferer = new TransferQueue(); + transferer = new TransferQueue(); else - transferer = new TransferStack(); + transferer = new TransferStack(); } // Unsafe mechanics diff --git a/luni/src/main/java/java/util/concurrent/ThreadPoolExecutor.java b/luni/src/main/java/java/util/concurrent/ThreadPoolExecutor.java index 331e225..9586293 100644 --- a/luni/src/main/java/java/util/concurrent/ThreadPoolExecutor.java +++ b/luni/src/main/java/java/util/concurrent/ThreadPoolExecutor.java @@ -5,8 +5,10 @@ */ package java.util.concurrent; -import java.util.concurrent.locks.*; -import java.util.concurrent.atomic.*; +import java.util.concurrent.locks.AbstractQueuedSynchronizer; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.ReentrantLock; +import java.util.concurrent.atomic.AtomicInteger; import java.util.*; // BEGIN android-note @@ -48,22 +50,23 @@ import java.util.*; * corePoolSize (see {@link #getCorePoolSize}) and * maximumPoolSize (see {@link #getMaximumPoolSize}). * - * When a new task is submitted in method {@link #execute}, and fewer - * than corePoolSize threads are running, a new thread is created to - * handle the request, even if other worker threads are idle. If - * there are more than corePoolSize but less than maximumPoolSize - * threads running, a new thread will be created only if the queue is - * full. By setting corePoolSize and maximumPoolSize the same, you - * create a fixed-size thread pool. By setting maximumPoolSize to an - * essentially unbounded value such as {@code Integer.MAX_VALUE}, you - * allow the pool to accommodate an arbitrary number of concurrent - * tasks. Most typically, core and maximum pool sizes are set only - * upon construction, but they may also be changed dynamically using - * {@link #setCorePoolSize} and {@link #setMaximumPoolSize}. + * When a new task is submitted in method {@link #execute(Runnable)}, + * and fewer than corePoolSize threads are running, a new thread is + * created to handle the request, even if other worker threads are + * idle. If there are more than corePoolSize but less than + * maximumPoolSize threads running, a new thread will be created only + * if the queue is full. By setting corePoolSize and maximumPoolSize + * the same, you create a fixed-size thread pool. By setting + * maximumPoolSize to an essentially unbounded value such as {@code + * Integer.MAX_VALUE}, you allow the pool to accommodate an arbitrary + * number of concurrent tasks. Most typically, core and maximum pool + * sizes are set only upon construction, but they may also be changed + * dynamically using {@link #setCorePoolSize} and {@link + * #setMaximumPoolSize}. * *

    On-demand construction
    * - *
    By default, even core threads are initially created and + *
    By default, even core threads are initially created and * started only when new tasks arrive, but this can be overridden * dynamically using method {@link #prestartCoreThread} or {@link * #prestartAllCoreThreads}. You probably want to prestart threads if @@ -85,17 +88,17 @@ import java.util.*; * *
    If the pool currently has more than corePoolSize threads, * excess threads will be terminated if they have been idle for more - * than the keepAliveTime (see {@link #getKeepAliveTime}). This - * provides a means of reducing resource consumption when the pool is - * not being actively used. If the pool becomes more active later, new - * threads will be constructed. This parameter can also be changed - * dynamically using method {@link #setKeepAliveTime}. Using a value - * of {@code Long.MAX_VALUE} {@link TimeUnit#NANOSECONDS} effectively - * disables idle threads from ever terminating prior to shut down. By - * default, the keep-alive policy applies only when there are more - * than corePoolSizeThreads. But method {@link - * #allowCoreThreadTimeOut(boolean)} can be used to apply this - * time-out policy to core threads as well, so long as the + * than the keepAliveTime (see {@link #getKeepAliveTime(TimeUnit)}). + * This provides a means of reducing resource consumption when the + * pool is not being actively used. If the pool becomes more active + * later, new threads will be constructed. This parameter can also be + * changed dynamically using method {@link #setKeepAliveTime(long, + * TimeUnit)}. Using a value of {@code Long.MAX_VALUE} {@link + * TimeUnit#NANOSECONDS} effectively disables idle threads from ever + * terminating prior to shut down. By default, the keep-alive policy + * applies only when there are more than corePoolSize threads. But + * method {@link #allowCoreThreadTimeOut(boolean)} can be used to + * apply this time-out policy to core threads as well, so long as the * keepAliveTime value is non-zero.
    * *
    Queuing
    @@ -165,14 +168,14 @@ import java.util.*; * *
    Rejected tasks
    * - *
    New tasks submitted in method {@link #execute} will be - * rejected when the Executor has been shut down, and also - * when the Executor uses finite bounds for both maximum threads and - * work queue capacity, and is saturated. In either case, the {@code - * execute} method invokes the {@link - * RejectedExecutionHandler#rejectedExecution} method of its {@link - * RejectedExecutionHandler}. Four predefined handler policies are - * provided: + *
    New tasks submitted in method {@link #execute(Runnable)} will be + * rejected when the Executor has been shut down, and also when + * the Executor uses finite bounds for both maximum threads and work queue + * capacity, and is saturated. In either case, the {@code execute} method + * invokes the {@link + * RejectedExecutionHandler#rejectedExecution(Runnable, ThreadPoolExecutor)} + * method of its {@link RejectedExecutionHandler}. Four predefined handler + * policies are provided: * *
      * @@ -202,30 +205,31 @@ import java.util.*; * *
      Hook methods
      * - *
      This class provides {@code protected} overridable {@link - * #beforeExecute} and {@link #afterExecute} methods that are called + *
      This class provides {@code protected} overridable + * {@link #beforeExecute(Thread, Runnable)} and + * {@link #afterExecute(Runnable, Throwable)} methods that are called * before and after execution of each task. These can be used to * manipulate the execution environment; for example, reinitializing - * ThreadLocals, gathering statistics, or adding log - * entries. Additionally, method {@link #terminated} can be overridden - * to perform any special processing that needs to be done once the - * Executor has fully terminated. + * ThreadLocals, gathering statistics, or adding log entries. + * Additionally, method {@link #terminated} can be overridden to perform + * any special processing that needs to be done once the Executor has + * fully terminated. * *

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

      * *
      Queue maintenance
      * - *
      Method {@link #getQueue} allows access to the work queue for - * purposes of monitoring and debugging. Use of this method for any - * other purpose is strongly discouraged. Two supplied methods, - * {@link #remove} and {@link #purge} are available to assist in - * storage reclamation when large numbers of queued tasks become - * cancelled.
      + *
      Method {@link #getQueue()} allows access to the work queue + * for purposes of monitoring and debugging. Use of this method for + * any other purpose is strongly discouraged. Two supplied methods, + * {@link #remove(Runnable)} and {@link #purge} are available to + * assist in storage reclamation when large numbers of queued tasks + * become cancelled.
      * *
      Finalization
      * - *
      A pool that is no longer referenced in a program AND + *
      A pool that is no longer referenced in a program AND * has no remaining threads will be {@code shutdown} automatically. If * you would like to ensure that unreferenced pools are reclaimed even * if users forget to call {@link #shutdown}, then you must arrange @@ -235,7 +239,7 @@ import java.util.*; * * * - *

      Extension example. Most extensions of this class + *

      Extension example. Most extensions of this class * override one or more of the protected hook methods. For example, * here is a subclass that adds a simple pause/resume feature: * @@ -304,7 +308,7 @@ public class ThreadPoolExecutor extends AbstractExecutorService { * bookkeeping before terminating. The user-visible pool size is * reported as the current size of the workers set. * - * The runState provides the main lifecyle control, taking on values: + * The runState provides the main lifecycle control, taking on values: * * RUNNING: Accept new tasks and process queued tasks * SHUTDOWN: Don't accept new tasks, but process queued tasks @@ -374,14 +378,14 @@ public class ThreadPoolExecutor extends AbstractExecutorService { } /** - * Attempt to CAS-increment the workerCount field of ctl. + * Attempts to CAS-increment the workerCount field of ctl. */ private boolean compareAndIncrementWorkerCount(int expect) { return ctl.compareAndSet(expect, expect + 1); } /** - * Attempt to CAS-decrement the workerCount field of ctl. + * Attempts to CAS-decrement the workerCount field of ctl. */ private boolean compareAndDecrementWorkerCount(int expect) { return ctl.compareAndSet(expect, expect - 1); @@ -461,10 +465,15 @@ public class ThreadPoolExecutor extends AbstractExecutorService { * policy limiting the number of threads. Even though it is not * treated as an error, failure to create threads may result in * new tasks being rejected or existing ones remaining stuck in - * the queue. On the other hand, no special precautions exist to - * handle OutOfMemoryErrors that might be thrown while trying to - * create threads, since there is generally no recourse from - * within this class. + * the queue. + * + * We go further and preserve pool invariants even in the face of + * errors such as OutOfMemoryError, that might be thrown while + * trying to create threads. Such errors are rather common due to + * the need to allocate a native stack in Thread.start, and users + * will want to perform clean pool shutdown to clean up. There + * will likely be enough memory available for the cleanup code to + * complete without encountering yet another OutOfMemoryError. */ private volatile ThreadFactory threadFactory; @@ -538,9 +547,13 @@ public class ThreadPoolExecutor extends AbstractExecutorService { * task execution. This protects against interrupts that are * intended to wake up a worker thread waiting for a task from * instead interrupting a task being run. We implement a simple - * non-reentrant mutual exclusion lock rather than use ReentrantLock - * because we do not want worker tasks to be able to reacquire the - * lock when they invoke pool control methods like setCorePoolSize. + * non-reentrant mutual exclusion lock rather than use + * ReentrantLock because we do not want worker tasks to be able to + * reacquire the lock when they invoke pool control methods like + * setCorePoolSize. Additionally, to suppress interrupts until + * the thread actually starts running tasks, we initialize lock + * state to a negative value, and clear it upon start (in + * runWorker). */ private final class Worker extends AbstractQueuedSynchronizer @@ -564,6 +577,7 @@ public class ThreadPoolExecutor extends AbstractExecutorService { * @param firstTask the first task (null if none) */ Worker(Runnable firstTask) { + setState(-1); // inhibit interrupts until runWorker this.firstTask = firstTask; this.thread = getThreadFactory().newThread(this); } @@ -579,7 +593,7 @@ public class ThreadPoolExecutor extends AbstractExecutorService { // The value 1 represents the locked state. protected boolean isHeldExclusively() { - return getState() == 1; + return getState() != 0; } protected boolean tryAcquire(int unused) { @@ -600,6 +614,16 @@ public class ThreadPoolExecutor extends AbstractExecutorService { public boolean tryLock() { return tryAcquire(1); } public void unlock() { release(1); } public boolean isLocked() { return isHeldExclusively(); } + + void interruptIfStarted() { + Thread t; + if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) { + try { + t.interrupt(); + } catch (SecurityException ignore) { + } + } + } } /* @@ -698,12 +722,8 @@ public class ThreadPoolExecutor extends AbstractExecutorService { final ReentrantLock mainLock = this.mainLock; mainLock.lock(); try { - for (Worker w : workers) { - try { - w.thread.interrupt(); - } catch (SecurityException ignore) { - } - } + for (Worker w : workers) + w.interruptIfStarted(); } finally { mainLock.unlock(); } @@ -760,19 +780,6 @@ public class ThreadPoolExecutor extends AbstractExecutorService { private static final boolean ONLY_ONE = true; - /** - * Ensures that unless the pool is stopping, the current thread - * does not have its interrupt set. This requires a double-check - * of state in case the interrupt was cleared concurrently with a - * shutdownNow -- if so, the interrupt is re-enabled. - */ - private void clearInterruptsForTaskRun() { - if (runStateLessThan(ctl.get(), STOP) && - Thread.interrupted() && - runStateAtLeast(ctl.get(), STOP)) - Thread.currentThread().interrupt(); - } - /* * Misc utilities, most of which are also exported to * ScheduledThreadPoolExecutor @@ -813,7 +820,7 @@ public class ThreadPoolExecutor extends AbstractExecutorService { */ private List drainQueue() { BlockingQueue q = workQueue; - List taskList = new ArrayList(); + ArrayList taskList = new ArrayList(); q.drainTo(taskList); if (!q.isEmpty()) { for (Runnable r : q.toArray(new Runnable[0])) { @@ -832,12 +839,13 @@ public class ThreadPoolExecutor extends AbstractExecutorService { * Checks if a new worker can be added with respect to current * pool state and the given bound (either core or maximum). If so, * the worker count is adjusted accordingly, and, if possible, a - * new worker is created and started running firstTask as its + * new worker is created and started, running firstTask as its * first task. This method returns false if the pool is stopped or * eligible to shut down. It also returns false if the thread - * factory fails to create a thread when asked, which requires a - * backout of workerCount, and a recheck for termination, in case - * the existence of this worker was holding up termination. + * factory fails to create a thread when asked. If the thread + * creation fails, either due to the thread factory returning + * null, or due to an exception (typically OutOfMemoryError in + * Thread.start()), we roll back cleanly. * * @param firstTask the task the new thread should run first (or * null if none). Workers are created with an initial first task @@ -880,46 +888,64 @@ public class ThreadPoolExecutor extends AbstractExecutorService { } } - Worker w = new Worker(firstTask); - Thread t = w.thread; + boolean workerStarted = false; + boolean workerAdded = false; + Worker w = null; + try { + w = new Worker(firstTask); + final Thread t = w.thread; + if (t != null) { + final ReentrantLock mainLock = this.mainLock; + mainLock.lock(); + try { + // Recheck while holding lock. + // Back out on ThreadFactory failure or if + // shut down before lock acquired. + int rs = runStateOf(ctl.get()); + + if (rs < SHUTDOWN || + (rs == SHUTDOWN && firstTask == null)) { + if (t.isAlive()) // precheck that t is startable + throw new IllegalThreadStateException(); + workers.add(w); + int s = workers.size(); + if (s > largestPoolSize) + largestPoolSize = s; + workerAdded = true; + } + } finally { + mainLock.unlock(); + } + if (workerAdded) { + t.start(); + workerStarted = true; + } + } + } finally { + if (! workerStarted) + addWorkerFailed(w); + } + return workerStarted; + } + /** + * Rolls back the worker thread creation. + * - removes worker from workers, if present + * - decrements worker count + * - rechecks for termination, in case the existence of this + * worker was holding up termination + */ + private void addWorkerFailed(Worker w) { final ReentrantLock mainLock = this.mainLock; mainLock.lock(); try { - // Recheck while holding lock. - // Back out on ThreadFactory failure or if - // shut down before lock acquired. - int c = ctl.get(); - int rs = runStateOf(c); - - if (t == null || - (rs >= SHUTDOWN && - ! (rs == SHUTDOWN && - firstTask == null))) { - decrementWorkerCount(); - tryTerminate(); - return false; - } - - workers.add(w); - - int s = workers.size(); - if (s > largestPoolSize) - largestPoolSize = s; + if (w != null) + workers.remove(w); + decrementWorkerCount(); + tryTerminate(); } finally { mainLock.unlock(); } - - t.start(); - // It is possible (but unlikely) for a thread to have been - // added to workers, but not yet started, during transition to - // STOP, which could result in a rare missed interrupt, - // because Thread.interrupt is not guaranteed to have any effect - // on a non-yet-started Thread (see Thread#interrupt). - if (runStateOf(ctl.get()) == STOP && ! t.isInterrupted()) - t.interrupt(); - - return true; } /** @@ -974,7 +1000,8 @@ public class ThreadPoolExecutor extends AbstractExecutorService { * 4. This worker timed out waiting for a task, and timed-out * workers are subject to termination (that is, * {@code allowCoreThreadTimeOut || workerCount > corePoolSize}) - * both before and after the timed wait. + * both before and after the timed wait, and if the queue is + * non-empty, this worker is not the last thread in the pool. * * @return task, or null if the worker must exit, in which case * workerCount is decremented @@ -982,7 +1009,6 @@ public class ThreadPoolExecutor extends AbstractExecutorService { private Runnable getTask() { boolean timedOut = false; // Did the last poll() time out? - retry: for (;;) { int c = ctl.get(); int rs = runStateOf(c); @@ -993,20 +1019,16 @@ public class ThreadPoolExecutor extends AbstractExecutorService { return null; } - boolean timed; // Are workers subject to culling? + int wc = workerCountOf(c); - for (;;) { - int wc = workerCountOf(c); - timed = allowCoreThreadTimeOut || wc > corePoolSize; + // Are workers subject to culling? + boolean timed = allowCoreThreadTimeOut || wc > corePoolSize; - if (wc <= maximumPoolSize && ! (timedOut && timed)) - break; + if ((wc > maximumPoolSize || (timed && timedOut)) + && (wc > 1 || workQueue.isEmpty())) { if (compareAndDecrementWorkerCount(c)) return null; - c = ctl.get(); // Re-read ctl - if (runStateOf(c) != rs) - continue retry; - // else CAS failed due to workerCount change; retry inner loop + continue; } try { @@ -1035,9 +1057,9 @@ public class ThreadPoolExecutor extends AbstractExecutorService { * usually leads processWorkerExit to replace this thread. * * 2. Before running any task, the lock is acquired to prevent - * other pool interrupts while the task is executing, and - * clearInterruptsForTaskRun called to ensure that unless pool is - * stopping, this thread does not have its interrupt set. + * other pool interrupts while the task is executing, and then we + * ensure that unless pool is stopping, this thread does not have + * its interrupt set. * * 3. Each task run is preceded by a call to beforeExecute, which * might throw an exception, in which case we cause thread to die @@ -1045,12 +1067,12 @@ public class ThreadPoolExecutor extends AbstractExecutorService { * the task. * * 4. Assuming beforeExecute completes normally, we run the task, - * gathering any of its thrown exceptions to send to - * afterExecute. We separately handle RuntimeException, Error - * (both of which the specs guarantee that we trap) and arbitrary - * Throwables. Because we cannot rethrow Throwables within - * Runnable.run, we wrap them within Errors on the way out (to the - * thread's UncaughtExceptionHandler). Any thrown exception also + * gathering any of its thrown exceptions to send to afterExecute. + * We separately handle RuntimeException, Error (both of which the + * specs guarantee that we trap) and arbitrary Throwables. + * Because we cannot rethrow Throwables within Runnable.run, we + * wrap them within Errors on the way out (to the thread's + * UncaughtExceptionHandler). Any thrown exception also * conservatively causes thread to die. * * 5. After task.run completes, we call afterExecute, which may @@ -1066,15 +1088,25 @@ public class ThreadPoolExecutor extends AbstractExecutorService { * @param w the worker */ final void runWorker(Worker w) { + Thread wt = Thread.currentThread(); Runnable task = w.firstTask; w.firstTask = null; + w.unlock(); // allow interrupts boolean completedAbruptly = true; try { while (task != null || (task = getTask()) != null) { w.lock(); - clearInterruptsForTaskRun(); + // If pool is stopping, ensure thread is interrupted; + // if not, ensure thread is not interrupted. This + // requires a recheck in second case to deal with + // shutdownNow race while clearing interrupt + if ((runStateAtLeast(ctl.get(), STOP) || + (Thread.interrupted() && + runStateAtLeast(ctl.get(), STOP))) && + !wt.isInterrupted()) + wt.interrupt(); try { - beforeExecute(w.thread, task); + beforeExecute(wt, task); Throwable thrown = null; try { task.run(); @@ -1374,7 +1406,7 @@ public class ThreadPoolExecutor extends AbstractExecutorService { * ignored or suppressed interruption, causing this executor not * to properly terminate. * - * @return true if terminating but not yet terminated + * @return {@code true} if terminating but not yet terminated */ public boolean isTerminating() { int c = ctl.get(); @@ -1428,7 +1460,7 @@ public class ThreadPoolExecutor extends AbstractExecutorService { * Returns the thread factory used to create new threads. * * @return the current thread factory - * @see #setThreadFactory + * @see #setThreadFactory(ThreadFactory) */ public ThreadFactory getThreadFactory() { return threadFactory; @@ -1451,7 +1483,7 @@ public class ThreadPoolExecutor extends AbstractExecutorService { * Returns the current handler for unexecutable tasks. * * @return the current handler - * @see #setRejectedExecutionHandler + * @see #setRejectedExecutionHandler(RejectedExecutionHandler) */ public RejectedExecutionHandler getRejectedExecutionHandler() { return handler; @@ -1623,7 +1655,7 @@ public class ThreadPoolExecutor extends AbstractExecutorService { * @param unit the time unit of the {@code time} argument * @throws IllegalArgumentException if {@code time} less than zero or * if {@code time} is zero and {@code allowsCoreThreadTimeOut} - * @see #getKeepAliveTime + * @see #getKeepAliveTime(TimeUnit) */ public void setKeepAliveTime(long time, TimeUnit unit) { if (time < 0) @@ -1644,7 +1676,7 @@ public class ThreadPoolExecutor extends AbstractExecutorService { * * @param unit the desired time unit of the result * @return the time limit - * @see #setKeepAliveTime + * @see #setKeepAliveTime(long, TimeUnit) */ public long getKeepAliveTime(TimeUnit unit) { return unit.convert(keepAliveTime, TimeUnit.NANOSECONDS); @@ -1669,7 +1701,7 @@ public class ThreadPoolExecutor extends AbstractExecutorService { * present, thus causing it not to be run if it has not already * started. * - *

      This method may be useful as one part of a cancellation + *

      This method may be useful as one part of a cancellation * scheme. It may fail to remove tasks that have been converted * into other forms before being placed on the internal queue. For * example, a task entered using {@code submit} might be @@ -1678,7 +1710,7 @@ public class ThreadPoolExecutor extends AbstractExecutorService { * remove those Futures that have been cancelled. * * @param task the task to remove - * @return true if the task was removed + * @return {@code true} if the task was removed */ public boolean remove(Runnable task) { boolean removed = workQueue.remove(task); @@ -1973,7 +2005,7 @@ public class ThreadPoolExecutor extends AbstractExecutorService { * * @param r the runnable task requested to be executed * @param e the executor attempting to execute this task - * @throws RejectedExecutionException always. + * @throws RejectedExecutionException always */ public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { throw new RejectedExecutionException("Task " + r.toString() + diff --git a/luni/src/main/java/java/util/concurrent/TimeUnit.java b/luni/src/main/java/java/util/concurrent/TimeUnit.java index 50f6ce0..eb2c495 100644 --- a/luni/src/main/java/java/util/concurrent/TimeUnit.java +++ b/luni/src/main/java/java/util/concurrent/TimeUnit.java @@ -7,10 +7,10 @@ package java.util.concurrent; /** - * A TimeUnit represents time durations at a given unit of + * A {@code TimeUnit} represents time durations at a given unit of * granularity and provides utility methods to convert across units, * and to perform timing and delay operations in these units. A - * TimeUnit does not maintain time information, but only + * {@code TimeUnit} does not maintain time information, but only * helps organize and use time representations that may be maintained * separately across various contexts. A nanosecond is defined as one * thousandth of a microsecond, a microsecond as one thousandth of a @@ -18,7 +18,7 @@ package java.util.concurrent; * as sixty seconds, an hour as sixty minutes, and a day as twenty four * hours. * - *

      A TimeUnit is mainly used to inform time-based methods + *

      A {@code TimeUnit} is mainly used to inform time-based methods * how a given timing parameter should be interpreted. For example, * the following code will timeout in 50 milliseconds if the {@link * java.util.concurrent.locks.Lock lock} is not available: @@ -34,7 +34,7 @@ package java.util.concurrent; * * Note however, that there is no guarantee that a particular timeout * implementation will be able to notice the passage of time at the - * same granularity as the given TimeUnit. + * same granularity as the given {@code TimeUnit}. * * @since 1.5 * @author Doug Lea @@ -148,31 +148,31 @@ public enum TimeUnit { * Convert the given time duration in the given unit to this * unit. Conversions from finer to coarser granularities * truncate, so lose precision. For example converting - * 999 milliseconds to seconds results in - * 0. Conversions from coarser to finer granularities + * {@code 999} milliseconds to seconds results in + * {@code 0}. Conversions from coarser to finer granularities * with arguments that would numerically overflow saturate to - * Long.MIN_VALUE if negative or Long.MAX_VALUE + * {@code Long.MIN_VALUE} if negative or {@code Long.MAX_VALUE} * if positive. * *

      For example, to convert 10 minutes to milliseconds, use: - * TimeUnit.MILLISECONDS.convert(10L, TimeUnit.MINUTES) + * {@code TimeUnit.MILLISECONDS.convert(10L, TimeUnit.MINUTES)} * - * @param sourceDuration the time duration in the given sourceUnit - * @param sourceUnit the unit of the sourceDuration argument + * @param sourceDuration the time duration in the given {@code sourceUnit} + * @param sourceUnit the unit of the {@code sourceDuration} argument * @return the converted duration in this unit, - * or Long.MIN_VALUE if conversion would negatively - * overflow, or Long.MAX_VALUE if it would positively overflow. + * or {@code Long.MIN_VALUE} if conversion would negatively + * overflow, or {@code Long.MAX_VALUE} if it would positively overflow. */ public long convert(long sourceDuration, TimeUnit sourceUnit) { throw new AbstractMethodError(); } /** - * Equivalent to NANOSECONDS.convert(duration, this). + * Equivalent to {@code NANOSECONDS.convert(duration, this)}. * @param duration the duration * @return the converted duration, - * or Long.MIN_VALUE if conversion would negatively - * overflow, or Long.MAX_VALUE if it would positively overflow. + * or {@code Long.MIN_VALUE} if conversion would negatively + * overflow, or {@code Long.MAX_VALUE} if it would positively overflow. * @see #convert */ public long toNanos(long duration) { @@ -180,11 +180,11 @@ public enum TimeUnit { } /** - * Equivalent to MICROSECONDS.convert(duration, this). + * Equivalent to {@code MICROSECONDS.convert(duration, this)}. * @param duration the duration * @return the converted duration, - * or Long.MIN_VALUE if conversion would negatively - * overflow, or Long.MAX_VALUE if it would positively overflow. + * or {@code Long.MIN_VALUE} if conversion would negatively + * overflow, or {@code Long.MAX_VALUE} if it would positively overflow. * @see #convert */ public long toMicros(long duration) { @@ -192,11 +192,11 @@ public enum TimeUnit { } /** - * Equivalent to MILLISECONDS.convert(duration, this). + * Equivalent to {@code MILLISECONDS.convert(duration, this)}. * @param duration the duration * @return the converted duration, - * or Long.MIN_VALUE if conversion would negatively - * overflow, or Long.MAX_VALUE if it would positively overflow. + * or {@code Long.MIN_VALUE} if conversion would negatively + * overflow, or {@code Long.MAX_VALUE} if it would positively overflow. * @see #convert */ public long toMillis(long duration) { @@ -204,11 +204,11 @@ public enum TimeUnit { } /** - * Equivalent to SECONDS.convert(duration, this). + * Equivalent to {@code SECONDS.convert(duration, this)}. * @param duration the duration * @return the converted duration, - * or Long.MIN_VALUE if conversion would negatively - * overflow, or Long.MAX_VALUE if it would positively overflow. + * or {@code Long.MIN_VALUE} if conversion would negatively + * overflow, or {@code Long.MAX_VALUE} if it would positively overflow. * @see #convert */ public long toSeconds(long duration) { @@ -216,11 +216,11 @@ public enum TimeUnit { } /** - * Equivalent to MINUTES.convert(duration, this). + * Equivalent to {@code MINUTES.convert(duration, this)}. * @param duration the duration * @return the converted duration, - * or Long.MIN_VALUE if conversion would negatively - * overflow, or Long.MAX_VALUE if it would positively overflow. + * or {@code Long.MIN_VALUE} if conversion would negatively + * overflow, or {@code Long.MAX_VALUE} if it would positively overflow. * @see #convert * @since 1.6 */ @@ -229,11 +229,11 @@ public enum TimeUnit { } /** - * Equivalent to HOURS.convert(duration, this). + * Equivalent to {@code HOURS.convert(duration, this)}. * @param duration the duration * @return the converted duration, - * or Long.MIN_VALUE if conversion would negatively - * overflow, or Long.MAX_VALUE if it would positively overflow. + * or {@code Long.MIN_VALUE} if conversion would negatively + * overflow, or {@code Long.MAX_VALUE} if it would positively overflow. * @see #convert * @since 1.6 */ @@ -242,7 +242,7 @@ public enum TimeUnit { } /** - * Equivalent to DAYS.convert(duration, this). + * Equivalent to {@code DAYS.convert(duration, this)}. * @param duration the duration * @return the converted duration * @see #convert @@ -265,9 +265,9 @@ public enum TimeUnit { * Performs a timed {@link Object#wait(long, int) Object.wait} * using this time unit. * This is a convenience method that converts timeout arguments - * into the form required by the Object.wait method. + * into the form required by the {@code Object.wait} method. * - *

      For example, you could implement a blocking poll + *

      For example, you could implement a blocking {@code poll} * method (see {@link BlockingQueue#poll BlockingQueue.poll}) * using: * @@ -298,7 +298,7 @@ public enum TimeUnit { * Performs a timed {@link Thread#join(long, int) Thread.join} * using this time unit. * This is a convenience method that converts time arguments into the - * form required by the Thread.join method. + * form required by the {@code Thread.join} method. * * @param thread the thread to wait for * @param timeout the maximum time to wait. If less than @@ -318,7 +318,7 @@ public enum TimeUnit { * Performs a {@link Thread#sleep(long, int) Thread.sleep} using * this time unit. * This is a convenience method that converts time arguments into the - * form required by the Thread.sleep method. + * form required by the {@code Thread.sleep} method. * * @param timeout the minimum time to sleep. If less than * or equal to zero, do not sleep at all. diff --git a/luni/src/main/java/java/util/concurrent/TimeoutException.java b/luni/src/main/java/java/util/concurrent/TimeoutException.java index 83934f0..1d7e634 100644 --- a/luni/src/main/java/java/util/concurrent/TimeoutException.java +++ b/luni/src/main/java/java/util/concurrent/TimeoutException.java @@ -11,7 +11,7 @@ package java.util.concurrent; * operations for which a timeout is specified need a means to * indicate that the timeout has occurred. For many such operations it * is possible to return a value that indicates timeout; when that is - * not possible or desirable then TimeoutException should be + * not possible or desirable then {@code TimeoutException} should be * declared and thrown. * * @since 1.5 @@ -21,13 +21,13 @@ public class TimeoutException extends Exception { private static final long serialVersionUID = 1900926677490660714L; /** - * Constructs a TimeoutException with no specified detail + * Constructs a {@code TimeoutException} with no specified detail * message. */ public TimeoutException() {} /** - * Constructs a TimeoutException with the specified detail + * Constructs a {@code TimeoutException} with the specified detail * message. * * @param message the detail message diff --git a/luni/src/main/java/java/util/concurrent/atomic/AtomicBoolean.java b/luni/src/main/java/java/util/concurrent/atomic/AtomicBoolean.java index d531f25..13b12aa 100644 --- a/luni/src/main/java/java/util/concurrent/atomic/AtomicBoolean.java +++ b/luni/src/main/java/java/util/concurrent/atomic/AtomicBoolean.java @@ -76,13 +76,13 @@ public class AtomicBoolean implements java.io.Serializable { * Atomically sets the value to the given updated value * if the current value {@code ==} the expected value. * - *

      May fail spuriously - * and does not provide ordering guarantees, so is only rarely an - * appropriate alternative to {@code compareAndSet}. + *

      May fail + * spuriously and does not provide ordering guarantees, so is + * only rarely an appropriate alternative to {@code compareAndSet}. * * @param expect the expected value * @param update the new value - * @return true if successful. + * @return true if successful */ public boolean weakCompareAndSet(boolean expect, boolean update) { int e = expect ? 1 : 0; @@ -126,7 +126,7 @@ public class AtomicBoolean implements java.io.Serializable { /** * Returns the String representation of the current value. - * @return the String representation of the current value. + * @return the String representation of the current value */ public String toString() { return Boolean.toString(get()); diff --git a/luni/src/main/java/java/util/concurrent/atomic/AtomicInteger.java b/luni/src/main/java/java/util/concurrent/atomic/AtomicInteger.java index e0a0018..d67b20a 100644 --- a/luni/src/main/java/java/util/concurrent/atomic/AtomicInteger.java +++ b/luni/src/main/java/java/util/concurrent/atomic/AtomicInteger.java @@ -110,13 +110,13 @@ public class AtomicInteger extends Number implements java.io.Serializable { * Atomically sets the value to the given updated value * if the current value {@code ==} the expected value. * - *

      May fail spuriously - * and does not provide ordering guarantees, so is only rarely an - * appropriate alternative to {@code compareAndSet}. + *

      May fail + * spuriously and does not provide ordering guarantees, so is + * only rarely an appropriate alternative to {@code compareAndSet}. * * @param expect the expected value * @param update the new value - * @return true if successful. + * @return true if successful */ public final boolean weakCompareAndSet(int expect, int update) { return unsafe.compareAndSwapInt(this, valueOffset, expect, update); @@ -210,13 +210,12 @@ public class AtomicInteger extends Number implements java.io.Serializable { /** * Returns the String representation of the current value. - * @return the String representation of the current value. + * @return the String representation of the current value */ public String toString() { return Integer.toString(get()); } - /** * Returns the value of this {@code AtomicInteger} as an {@code int}. */ diff --git a/luni/src/main/java/java/util/concurrent/atomic/AtomicIntegerArray.java b/luni/src/main/java/java/util/concurrent/atomic/AtomicIntegerArray.java index 804a51e..1f6980d 100644 --- a/luni/src/main/java/java/util/concurrent/atomic/AtomicIntegerArray.java +++ b/luni/src/main/java/java/util/concurrent/atomic/AtomicIntegerArray.java @@ -146,14 +146,14 @@ public class AtomicIntegerArray 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. * - *

      May fail spuriously - * and does not provide ordering guarantees, so is only rarely an - * appropriate alternative to {@code compareAndSet}. + *

      May fail + * spuriously and does not provide ordering guarantees, so is + * only rarely an appropriate alternative to {@code compareAndSet}. * * @param i the index * @param expect the expected value * @param update the new value - * @return true if successful. + * @return true if successful */ public final boolean weakCompareAndSet(int i, int expect, int update) { return compareAndSet(i, expect, update); diff --git a/luni/src/main/java/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java b/luni/src/main/java/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java index c7ed158..6067152 100644 --- a/luni/src/main/java/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java +++ b/luni/src/main/java/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java @@ -8,7 +8,8 @@ package java.util.concurrent.atomic; import dalvik.system.VMStack; // android-added import sun.misc.Unsafe; -import java.lang.reflect.*; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; /** * A reflection-based utility that enables atomic updates to @@ -28,7 +29,7 @@ import java.lang.reflect.*; * @author Doug Lea * @param The type of the object holding the updatable field */ -public abstract class AtomicIntegerFieldUpdater { +public abstract class AtomicIntegerFieldUpdater { /** * Creates and returns an updater for objects with the given field. * The Class argument is needed to check that reflective types and @@ -40,7 +41,9 @@ public abstract class AtomicIntegerFieldUpdater { * @throws IllegalArgumentException if the field is not a * volatile integer type * @throws RuntimeException with a nested reflection-based - * exception if the class does not hold field or is the wrong type + * exception if the class does not hold field or is the wrong type, + * or the field is inaccessible to the caller according to Java language + * access control */ public static AtomicIntegerFieldUpdater newUpdater(Class tclass, String fieldName) { return new AtomicIntegerFieldUpdaterImpl(tclass, fieldName); @@ -75,9 +78,9 @@ public abstract class AtomicIntegerFieldUpdater { * other calls to {@code compareAndSet} and {@code set}, but not * necessarily with respect to other changes in the field. * - *

      May fail spuriously - * and does not provide ordering guarantees, so is only rarely an - * appropriate alternative to {@code compareAndSet}. + *

      May fail + * spuriously and does not provide ordering guarantees, so is + * only rarely an appropriate alternative to {@code compareAndSet}. * * @param obj An object whose field to conditionally set * @param expect the expected value @@ -108,7 +111,6 @@ public abstract class AtomicIntegerFieldUpdater { */ public abstract void lazySet(T obj, int newValue); - /** * Gets the current value held in the field of the given object managed * by this updater. @@ -242,19 +244,28 @@ public abstract class AtomicIntegerFieldUpdater { private final Class cclass; AtomicIntegerFieldUpdaterImpl(Class tclass, String fieldName) { - Field field = null; - Class caller = null; - int modifiers = 0; + final Field field; + final Class caller; + final int modifiers; try { - field = tclass.getDeclaredField(fieldName); + field = tclass.getDeclaredField(fieldName); // android-changed caller = VMStack.getStackClass2(); // android-changed - modifiers = field.getModifiers(); + modifiers = field.getModifiers(); // BEGIN android-removed // sun.reflect.misc.ReflectUtil.ensureMemberAccess( // caller, tclass, null, modifiers); - // sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass); + // ClassLoader cl = tclass.getClassLoader(); + // ClassLoader ccl = caller.getClassLoader(); + // if ((ccl != null) && (ccl != cl) && + // ((cl == null) || !isAncestor(cl, ccl))) { + // sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass); + // } // END android-removed + // BEGIN android-removed + // } catch (PrivilegedActionException pae) { + // throw new RuntimeException(pae.getException()); + // END android-removed } catch (Exception ex) { throw new RuntimeException(ex); } @@ -272,6 +283,23 @@ public abstract class AtomicIntegerFieldUpdater { offset = unsafe.objectFieldOffset(field); } + // BEGIN android-removed + // /** + // * Returns true if the second classloader can be found in the first + // * classloader's delegation chain. + // * Equivalent to the inaccessible: first.isAncestor(second). + // */ + // private static boolean isAncestor(ClassLoader first, ClassLoader second) { + // ClassLoader acl = first; + // do { + // acl = acl.getParent(); + // if (second == acl) { + // return true; + // } + // } while (acl != null); + // return false; + // } + // END android-removed private void fullCheck(T obj) { if (!tclass.isInstance(obj)) throw new ClassCastException(); diff --git a/luni/src/main/java/java/util/concurrent/atomic/AtomicLong.java b/luni/src/main/java/java/util/concurrent/atomic/AtomicLong.java index 5e799f7..278c5b5 100644 --- a/luni/src/main/java/java/util/concurrent/atomic/AtomicLong.java +++ b/luni/src/main/java/java/util/concurrent/atomic/AtomicLong.java @@ -124,13 +124,13 @@ public class AtomicLong extends Number implements java.io.Serializable { * Atomically sets the value to the given updated value * if the current value {@code ==} the expected value. * - *

      May fail spuriously - * and does not provide ordering guarantees, so is only rarely an - * appropriate alternative to {@code compareAndSet}. + *

      May fail + * spuriously and does not provide ordering guarantees, so is + * only rarely an appropriate alternative to {@code compareAndSet}. * * @param expect the expected value * @param update the new value - * @return true if successful. + * @return true if successful */ public final boolean weakCompareAndSet(long expect, long update) { return unsafe.compareAndSwapLong(this, valueOffset, expect, update); @@ -224,13 +224,12 @@ public class AtomicLong extends Number implements java.io.Serializable { /** * Returns the String representation of the current value. - * @return the String representation of the current value. + * @return the String representation of the current value */ public String toString() { return Long.toString(get()); } - /** * Returns the value of this {@code AtomicLong} as an {@code int} * after a narrowing primitive conversion. diff --git a/luni/src/main/java/java/util/concurrent/atomic/AtomicLongArray.java b/luni/src/main/java/java/util/concurrent/atomic/AtomicLongArray.java index 22edb3f..2e8c2b7 100644 --- a/luni/src/main/java/java/util/concurrent/atomic/AtomicLongArray.java +++ b/luni/src/main/java/java/util/concurrent/atomic/AtomicLongArray.java @@ -106,7 +106,6 @@ public class AtomicLongArray implements java.io.Serializable { unsafe.putOrderedLong(array, checkedByteOffset(i), newValue); } - /** * Atomically sets the element at position {@code i} to the given value * and returns the old value. @@ -146,14 +145,14 @@ public class AtomicLongArray 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. * - *

      May fail spuriously - * and does not provide ordering guarantees, so is only rarely an - * appropriate alternative to {@code compareAndSet}. + *

      May fail + * spuriously and does not provide ordering guarantees, so is + * only rarely an appropriate alternative to {@code compareAndSet}. * * @param i the index * @param expect the expected value * @param update the new value - * @return true if successful. + * @return true if successful */ public final boolean weakCompareAndSet(int i, long expect, long update) { return compareAndSet(i, expect, update); diff --git a/luni/src/main/java/java/util/concurrent/atomic/AtomicLongFieldUpdater.java b/luni/src/main/java/java/util/concurrent/atomic/AtomicLongFieldUpdater.java index 748ae69..0096a6b 100644 --- a/luni/src/main/java/java/util/concurrent/atomic/AtomicLongFieldUpdater.java +++ b/luni/src/main/java/java/util/concurrent/atomic/AtomicLongFieldUpdater.java @@ -8,7 +8,8 @@ package java.util.concurrent.atomic; import dalvik.system.VMStack; // android-added import sun.misc.Unsafe; -import java.lang.reflect.*; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; /** * A reflection-based utility that enables atomic updates to @@ -28,19 +29,21 @@ import java.lang.reflect.*; * @author Doug Lea * @param The type of the object holding the updatable field */ -public abstract class AtomicLongFieldUpdater { +public abstract class AtomicLongFieldUpdater { /** * Creates and returns an updater for objects with the given field. * The Class argument is needed to check that reflective types and * generic types match. * * @param tclass the class of the objects holding the field - * @param fieldName the name of the field to be updated. + * @param fieldName the name of the field to be updated * @return the updater * @throws IllegalArgumentException if the field is not a - * volatile long type. + * volatile long type * @throws RuntimeException with a nested reflection-based - * exception if the class does not hold field or is the wrong type. + * exception if the class does not hold field or is the wrong type, + * or the field is inaccessible to the caller according to Java language + * access control */ public static AtomicLongFieldUpdater newUpdater(Class tclass, String fieldName) { if (AtomicLong.VM_SUPPORTS_LONG_CAS) @@ -65,9 +68,9 @@ public abstract class AtomicLongFieldUpdater { * @param obj An object whose field to conditionally set * @param expect the expected value * @param update the new value - * @return true if successful. + * @return true if successful * @throws ClassCastException if {@code obj} is not an instance - * of the class possessing the field established in the constructor. + * of the class possessing the field established in the constructor */ public abstract boolean compareAndSet(T obj, long expect, long update); @@ -78,16 +81,16 @@ public abstract class AtomicLongFieldUpdater { * other calls to {@code compareAndSet} and {@code set}, but not * necessarily with respect to other changes in the field. * - *

      May fail spuriously - * and does not provide ordering guarantees, so is only rarely an - * appropriate alternative to {@code compareAndSet}. + *

      May fail + * spuriously and does not provide ordering guarantees, so is + * only rarely an appropriate alternative to {@code compareAndSet}. * * @param obj An object whose field to conditionally set * @param expect the expected value * @param update the new value - * @return true if successful. + * @return true if successful * @throws ClassCastException if {@code obj} is not an instance - * of the class possessing the field established in the constructor. + * of the class possessing the field established in the constructor */ public abstract boolean weakCompareAndSet(T obj, long expect, long update); @@ -241,18 +244,27 @@ public abstract class AtomicLongFieldUpdater { private final Class cclass; CASUpdater(Class tclass, String fieldName) { - Field field = null; - Class caller = null; - int modifiers = 0; + final Field field; + final Class caller; + final int modifiers; try { - field = tclass.getDeclaredField(fieldName); + field = tclass.getDeclaredField(fieldName); // android-changed caller = VMStack.getStackClass2(); // android-changed modifiers = field.getModifiers(); // BEGIN android-removed // sun.reflect.misc.ReflectUtil.ensureMemberAccess( // caller, tclass, null, modifiers); - // sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass); + // ClassLoader cl = tclass.getClassLoader(); + // ClassLoader ccl = caller.getClassLoader(); + // if ((ccl != null) && (ccl != cl) && + // ((cl == null) || !isAncestor(cl, ccl))) { + // sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass); + // } // END android-removed + // BEGIN android-removed + // } catch (PrivilegedActionException pae) { + // throw new RuntimeException(pae.getException()); + // END android-removed } catch (Exception ex) { throw new RuntimeException(ex); } @@ -330,14 +342,23 @@ public abstract class AtomicLongFieldUpdater { Class caller = null; int modifiers = 0; try { - field = tclass.getDeclaredField(fieldName); + field = tclass.getDeclaredField(fieldName); // android-changed caller = VMStack.getStackClass2(); // android-changed modifiers = field.getModifiers(); // BEGIN android-removed // sun.reflect.misc.ReflectUtil.ensureMemberAccess( // caller, tclass, null, modifiers); - // sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass); + // ClassLoader cl = tclass.getClassLoader(); + // ClassLoader ccl = caller.getClassLoader(); + // if ((ccl != null) && (ccl != cl) && + // ((cl == null) || !isAncestor(cl, ccl))) { + // sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass); + // } // END android-removed + // BEGIN android-removed + // } catch (PrivilegedActionException pae) { + // throw new RuntimeException(pae.getException()); + // END android-removed } catch (Exception ex) { throw new RuntimeException(ex); } @@ -410,4 +431,22 @@ public abstract class AtomicLongFieldUpdater { ); } } + + // BEGIN android-removed + // /** + // * Returns true if the second classloader can be found in the first + // * classloader's delegation chain. + // * Equivalent to the inaccessible: first.isAncestor(second). + // */ + // private static boolean isAncestor(ClassLoader first, ClassLoader second) { + // ClassLoader acl = first; + // do { + // acl = acl.getParent(); + // if (second == acl) { + // return true; + // } + // } while (acl != null); + // return false; + // } + // END android-removed } diff --git a/luni/src/main/java/java/util/concurrent/atomic/AtomicMarkableReference.java b/luni/src/main/java/java/util/concurrent/atomic/AtomicMarkableReference.java index eaf700c..1257be0 100644 --- a/luni/src/main/java/java/util/concurrent/atomic/AtomicMarkableReference.java +++ b/luni/src/main/java/java/util/concurrent/atomic/AtomicMarkableReference.java @@ -83,9 +83,9 @@ public class AtomicMarkableReference { * current reference is {@code ==} to the expected reference * and the current mark is equal to the expected mark. * - *

      May fail spuriously - * and does not provide ordering guarantees, so is only rarely an - * appropriate alternative to {@code compareAndSet}. + *

      May fail + * spuriously and does not provide ordering guarantees, so is + * only rarely an appropriate alternative to {@code compareAndSet}. * * @param expectedReference the expected value of the reference * @param newReference the new value for the reference diff --git a/luni/src/main/java/java/util/concurrent/atomic/AtomicReference.java b/luni/src/main/java/java/util/concurrent/atomic/AtomicReference.java index b21e9b6..98b402a 100644 --- a/luni/src/main/java/java/util/concurrent/atomic/AtomicReference.java +++ b/luni/src/main/java/java/util/concurrent/atomic/AtomicReference.java @@ -15,7 +15,7 @@ import sun.misc.Unsafe; * @author Doug Lea * @param The type of object referred to by this reference */ -public class AtomicReference implements java.io.Serializable { +public class AtomicReference implements java.io.Serializable { private static final long serialVersionUID = -1848883965231344442L; private static final Unsafe unsafe = Unsafe.getUnsafe(); @@ -89,13 +89,13 @@ public class AtomicReference implements java.io.Serializable { * Atomically sets the value to the given updated value * if the current value {@code ==} the expected value. * - *

      May fail spuriously - * and does not provide ordering guarantees, so is only rarely an - * appropriate alternative to {@code compareAndSet}. + *

      May fail + * spuriously and does not provide ordering guarantees, so is + * only rarely an appropriate alternative to {@code compareAndSet}. * * @param expect the expected value * @param update the new value - * @return true if successful. + * @return true if successful */ public final boolean weakCompareAndSet(V expect, V update) { return unsafe.compareAndSwapObject(this, valueOffset, expect, update); @@ -117,7 +117,7 @@ public class AtomicReference implements java.io.Serializable { /** * Returns the String representation of the current value. - * @return the String representation of the current value. + * @return the String representation of the current value */ public String toString() { return String.valueOf(get()); diff --git a/luni/src/main/java/java/util/concurrent/atomic/AtomicReferenceArray.java b/luni/src/main/java/java/util/concurrent/atomic/AtomicReferenceArray.java index c47728d..052b839 100644 --- a/luni/src/main/java/java/util/concurrent/atomic/AtomicReferenceArray.java +++ b/luni/src/main/java/java/util/concurrent/atomic/AtomicReferenceArray.java @@ -29,19 +29,18 @@ public class AtomicReferenceArray implements java.io.Serializable { private final Object[] array; // must have exact type Object[] static { - int scale; try { unsafe = Unsafe.getUnsafe(); arrayFieldOffset = unsafe.objectFieldOffset (AtomicReferenceArray.class.getDeclaredField("array")); base = unsafe.arrayBaseOffset(Object[].class); - scale = unsafe.arrayIndexScale(Object[].class); + int scale = unsafe.arrayIndexScale(Object[].class); + if ((scale & (scale - 1)) != 0) + throw new Error("data type scale not a power of two"); + shift = 31 - Integer.numberOfLeadingZeros(scale); } catch (Exception e) { throw new Error(e); } - if ((scale & (scale - 1)) != 0) - throw new Error("data type scale not a power of two"); - shift = 31 - Integer.numberOfLeadingZeros(scale); } private long checkedByteOffset(int i) { @@ -96,6 +95,7 @@ public class AtomicReferenceArray implements java.io.Serializable { return getRaw(checkedByteOffset(i)); } + @SuppressWarnings("unchecked") private E getRaw(long offset) { return (E) unsafe.getObjectVolatile(array, offset); } @@ -121,7 +121,6 @@ public class AtomicReferenceArray implements java.io.Serializable { unsafe.putOrderedObject(array, checkedByteOffset(i), newValue); } - /** * Atomically sets the element at position {@code i} to the given * value and returns the old value. @@ -161,14 +160,14 @@ public class AtomicReferenceArray 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. * - *

      May fail spuriously - * and does not provide ordering guarantees, so is only rarely an - * appropriate alternative to {@code compareAndSet}. + *

      May fail + * spuriously and does not provide ordering guarantees, so is + * only rarely an appropriate alternative to {@code compareAndSet}. * * @param i the index * @param expect the expected value * @param update the new value - * @return true if successful. + * @return true if successful */ public final boolean weakCompareAndSet(int i, E expect, E update) { return compareAndSet(i, expect, update); @@ -195,7 +194,6 @@ public class AtomicReferenceArray implements java.io.Serializable { /** * Reconstitutes the instance from a stream (that is, deserializes it). - * @param s the stream */ private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException, diff --git a/luni/src/main/java/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java b/luni/src/main/java/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java index d23d766..eb2d73e 100644 --- a/luni/src/main/java/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java +++ b/luni/src/main/java/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java @@ -7,7 +7,8 @@ package java.util.concurrent.atomic; import dalvik.system.VMStack; // android-added import sun.misc.Unsafe; -import java.lang.reflect.*; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; /** * A reflection-based utility that enables atomic updates to @@ -45,20 +46,22 @@ import java.lang.reflect.*; * @param The type of the object holding the updatable field * @param The type of the field */ -public abstract class AtomicReferenceFieldUpdater { +public abstract class AtomicReferenceFieldUpdater { /** * Creates and returns an updater for objects with the given field. * The Class arguments are needed to check that reflective types and * generic types match. * - * @param tclass the class of the objects holding the field. + * @param tclass the class of the objects holding the field * @param vclass the class of the field - * @param fieldName the name of the field to be updated. + * @param fieldName the name of the field to be updated * @return the updater - * @throws IllegalArgumentException if the field is not a volatile reference type. + * @throws IllegalArgumentException if the field is not a volatile reference type * @throws RuntimeException with a nested reflection-based - * exception if the class does not hold field or is the wrong type. + * exception if the class does not hold field or is the wrong type, + * or the field is inaccessible to the caller according to Java language + * access control */ public static AtomicReferenceFieldUpdater newUpdater(Class tclass, Class vclass, String fieldName) { return new AtomicReferenceFieldUpdaterImpl(tclass, @@ -82,7 +85,7 @@ public abstract class AtomicReferenceFieldUpdater { * @param obj An object whose field to conditionally set * @param expect the expected value * @param update the new value - * @return true if successful. + * @return true if successful */ public abstract boolean compareAndSet(T obj, V expect, V update); @@ -93,14 +96,14 @@ public abstract class AtomicReferenceFieldUpdater { * other calls to {@code compareAndSet} and {@code set}, but not * necessarily with respect to other changes in the field. * - *

      May fail spuriously - * and does not provide ordering guarantees, so is only rarely an - * appropriate alternative to {@code compareAndSet}. + *

      May fail + * spuriously and does not provide ordering guarantees, so is + * only rarely an appropriate alternative to {@code compareAndSet}. * * @param obj An object whose field to conditionally set * @param expect the expected value * @param update the new value - * @return true if successful. + * @return true if successful */ public abstract boolean weakCompareAndSet(T obj, V expect, V update); @@ -169,23 +172,32 @@ public abstract class AtomicReferenceFieldUpdater { * screenings fail. */ - AtomicReferenceFieldUpdaterImpl(Class tclass, + AtomicReferenceFieldUpdaterImpl(final Class tclass, Class vclass, - String fieldName) { - Field field = null; - Class fieldClass = null; - Class caller = null; - int modifiers = 0; + final String fieldName) { + final Field field; + final Class fieldClass; + final Class caller; + final int modifiers; try { - field = tclass.getDeclaredField(fieldName); + field = tclass.getDeclaredField(fieldName); // android-changed caller = VMStack.getStackClass2(); // android-changed modifiers = field.getModifiers(); - // BEGIN android-removed - // sun.reflect.misc.ReflectUtil.ensureMemberAccess( - // caller, tclass, null, modifiers); - // sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass); - // END android-removed + // BEGIN android-removed + // sun.reflect.misc.ReflectUtil.ensureMemberAccess( + // caller, tclass, null, modifiers); + // ClassLoader cl = tclass.getClassLoader(); + // ClassLoader ccl = caller.getClassLoader(); + // if ((ccl != null) && (ccl != cl) && + // ((cl == null) || !isAncestor(cl, ccl))) { + // sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass); + // } + // END android-removed fieldClass = field.getType(); + // BEGIN android-removed + // } catch (PrivilegedActionException pae) { + // throw new RuntimeException(pae.getException()); + // END android-removed } catch (Exception ex) { throw new RuntimeException(ex); } @@ -206,6 +218,25 @@ public abstract class AtomicReferenceFieldUpdater { offset = unsafe.objectFieldOffset(field); } + // BEGIN android-removed + // /** + // * Returns true if the second classloader can be found in the first + // * classloader's delegation chain. + // * Equivalent to the inaccessible: first.isAncestor(second). + // */ + // + // private static boolean isAncestor(ClassLoader first, ClassLoader second) { + // ClassLoader acl = first; + // do { + // acl = acl.getParent(); + // if (second == acl) { + // return true; + // } + // } while (acl != null); + // return false; + // } + // END android-removed + void targetCheck(T obj) { if (!tclass.isInstance(obj)) throw new ClassCastException(); @@ -254,6 +285,7 @@ public abstract class AtomicReferenceFieldUpdater { unsafe.putOrderedObject(obj, offset, newValue); } + @SuppressWarnings("unchecked") public V get(T obj) { if (obj == null || obj.getClass() != tclass || cclass != null) targetCheck(obj); diff --git a/luni/src/main/java/java/util/concurrent/atomic/AtomicStampedReference.java b/luni/src/main/java/java/util/concurrent/atomic/AtomicStampedReference.java index a0cb492..b93a6f3 100644 --- a/luni/src/main/java/java/util/concurrent/atomic/AtomicStampedReference.java +++ b/luni/src/main/java/java/util/concurrent/atomic/AtomicStampedReference.java @@ -83,9 +83,9 @@ public class AtomicStampedReference { * current reference is {@code ==} to the expected reference * and the current stamp is equal to the expected stamp. * - *

      May fail spuriously - * and does not provide ordering guarantees, so is only rarely an - * appropriate alternative to {@code compareAndSet}. + *

      May fail + * spuriously and does not provide ordering guarantees, so is + * only rarely an appropriate alternative to {@code compareAndSet}. * * @param expectedReference the expected value of the reference * @param newReference the new value for the reference @@ -126,7 +126,6 @@ public class AtomicStampedReference { casPair(current, Pair.of(newReference, newStamp))); } - /** * Unconditionally sets the value of both the reference and stamp. * diff --git a/luni/src/main/java/java/util/concurrent/atomic/package-info.java b/luni/src/main/java/java/util/concurrent/atomic/package-info.java index efbb413..568d2c6 100644 --- a/luni/src/main/java/java/util/concurrent/atomic/package-info.java +++ b/luni/src/main/java/java/util/concurrent/atomic/package-info.java @@ -54,19 +54,20 @@ * * write your utility method as follows: *

       {@code
      - * boolean getAndTransform(AtomicLong var) {
      + * long getAndTransform(AtomicLong var) {
        *   while (true) {
        *     long current = var.get();
        *     long next = transform(current);
        *     if (var.compareAndSet(current, next))
        *         return current;
      + *         // return next; for transformAndGet
        *   }
        * }}
      * *

      The memory effects for accesses and updates of atomics generally * follow the rules for volatiles, as stated in - * The Java Language - * Specification, Third Edition (17.4 Memory Model): + * + * The Java Language Specification (17.4 Memory Model): * *

        * @@ -122,13 +123,12 @@ * semantics for their array elements, which is not supported for * ordinary arrays. * - * - *

        The atomic classes also support method {@code weakCompareAndSet}, - * which has limited applicability. On some platforms, the weak version - * may be more efficient than {@code compareAndSet} in the normal case, - * but differs in that any given invocation of the - * {@code weakCompareAndSet} method may return {@code false} - * spuriously (that is, for no apparent reason). A + *

        The atomic classes also support method + * {@code weakCompareAndSet}, which has limited applicability. On some + * platforms, the weak version may be more efficient than {@code + * compareAndSet} in the normal case, but differs in that any given + * invocation of the {@code weakCompareAndSet} method may return {@code + * false} spuriously (that is, for no apparent reason). A * {@code false} return means only that the operation may be retried if * desired, relying on the guarantee that repeated invocation when the * variable holds {@code expectedValue} and no other thread is also @@ -164,7 +164,7 @@ * *

        Atomic classes are not general purpose replacements for * {@code java.lang.Integer} and related classes. They do not - * define methods such as {@code hashCode} and + * define methods such as {@code equals}, {@code hashCode} and * {@code compareTo}. (Because atomic variables are expected to be * mutated, they are poor choices for hash table keys.) Additionally, * classes are provided only for those types that are commonly useful in diff --git a/luni/src/main/java/java/util/concurrent/locks/AbstractOwnableSynchronizer.java b/luni/src/main/java/java/util/concurrent/locks/AbstractOwnableSynchronizer.java index 4bec0cf..fa01824 100644 --- a/luni/src/main/java/java/util/concurrent/locks/AbstractOwnableSynchronizer.java +++ b/luni/src/main/java/java/util/concurrent/locks/AbstractOwnableSynchronizer.java @@ -10,7 +10,7 @@ package java.util.concurrent.locks; * A synchronizer that may be exclusively owned by a thread. This * class provides a basis for creating locks and related synchronizers * that may entail a notion of ownership. The - * AbstractOwnableSynchronizer class itself does not manage or + * {@code AbstractOwnableSynchronizer} class itself does not manage or * use this information. However, subclasses and tools may use * appropriately maintained values to help control and monitor access * and provide diagnostics. @@ -36,9 +36,9 @@ public abstract class AbstractOwnableSynchronizer /** * Sets the thread that currently owns exclusive access. A - * null argument indicates that no thread owns access. + * {@code null} argument indicates that no thread owns access. * This method does not otherwise impose any synchronization or - * volatile field accesses. + * {@code volatile} field accesses. */ protected final void setExclusiveOwnerThread(Thread t) { exclusiveOwnerThread = t; @@ -46,9 +46,9 @@ public abstract class AbstractOwnableSynchronizer /** * Returns the thread last set by - * setExclusiveOwnerThread, or null if never + * {@code setExclusiveOwnerThread}, or {@code null} if never * set. This method does not otherwise impose any synchronization - * or volatile field accesses. + * or {@code volatile} field accesses. * @return the owner thread */ protected final Thread getExclusiveOwnerThread() { diff --git a/luni/src/main/java/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java b/luni/src/main/java/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java index 7b36460..4c5e280 100644 --- a/luni/src/main/java/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java +++ b/luni/src/main/java/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java @@ -5,17 +5,19 @@ */ package java.util.concurrent.locks; -import java.util.*; -import java.util.concurrent.*; +import java.util.concurrent.TimeUnit; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; import sun.misc.Unsafe; /** * A version of {@link AbstractQueuedSynchronizer} in - * which synchronization state is maintained as a long. + * which synchronization state is maintained as a {@code long}. * This class has exactly the same structure, properties, and methods - * as AbstractQueuedSynchronizer with the exception + * as {@code AbstractQueuedSynchronizer} with the exception * that all state-related parameters and results are defined - * as long rather than int. This class + * as {@code long} rather than {@code int}. This class * may be useful when creating synchronizers such as * multilevel locks and barriers that require * 64 bits of state. @@ -40,7 +42,7 @@ public abstract class AbstractQueuedLongSynchronizer */ /** - * Creates a new AbstractQueuedLongSynchronizer instance + * Creates a new {@code AbstractQueuedLongSynchronizer} instance * with initial synchronization state of zero. */ protected AbstractQueuedLongSynchronizer() { } @@ -73,7 +75,7 @@ public abstract class AbstractQueuedLongSynchronizer * *

        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 + * demarcation from unqueued to queued. Similarly, dequeuing * 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 @@ -180,7 +182,7 @@ public abstract class AbstractQueuedLongSynchronizer /** * Link to predecessor node that current node/thread relies on - * for checking waitStatus. Assigned during enqueing, and nulled + * for checking waitStatus. Assigned during enqueuing, 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 @@ -225,7 +227,7 @@ public abstract class AbstractQueuedLongSynchronizer Node nextWaiter; /** - * Returns true if node is waiting in shared mode + * @return true if node is waiting in shared mode */ final boolean isShared() { return nextWaiter == SHARED; @@ -281,7 +283,7 @@ public abstract class AbstractQueuedLongSynchronizer /** * Returns the current value of synchronization state. - * This operation has memory semantics of a volatile read. + * This operation has memory semantics of a {@code volatile} read. * @return current state value */ protected final long getState() { @@ -290,7 +292,7 @@ public abstract class AbstractQueuedLongSynchronizer /** * Sets the value of synchronization state. - * This operation has memory semantics of a volatile write. + * This operation has memory semantics of a {@code volatile} write. * @param newState the new state value */ protected final void setState(long newState) { @@ -300,7 +302,7 @@ public abstract class AbstractQueuedLongSynchronizer /** * Atomically sets synchronization state to the given updated * value if the current state value equals the expected value. - * This operation has memory semantics of a volatile read + * This operation has memory semantics of a {@code volatile} read * and write. * * @param expect the expected value @@ -410,7 +412,7 @@ public abstract class AbstractQueuedLongSynchronizer } /** - * Release action for shared mode -- signal successor and ensure + * Release action for shared mode -- signals successor and ensures * propagation. (Note: For exclusive mode, release just amounts * to calling unparkSuccessor of head if it needs signal.) */ @@ -531,7 +533,7 @@ public abstract class AbstractQueuedLongSynchronizer /** * 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 + * control in all acquire loops. Requires that pred == node.prev. * * @param pred node's predecessor holding status * @param node the node @@ -656,8 +658,10 @@ public abstract class AbstractQueuedLongSynchronizer * @return {@code true} if acquired */ private boolean doAcquireNanos(long arg, long nanosTimeout) - throws InterruptedException { - long lastTime = System.nanoTime(); + throws InterruptedException { + if (nanosTimeout <= 0L) + return false; + final long deadline = System.nanoTime() + nanosTimeout; final Node node = addWaiter(Node.EXCLUSIVE); boolean failed = true; try { @@ -669,14 +673,12 @@ public abstract class AbstractQueuedLongSynchronizer failed = false; return true; } - if (nanosTimeout <= 0) + nanosTimeout = deadline - System.nanoTime(); + if (nanosTimeout <= 0L) 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(); } @@ -756,9 +758,10 @@ public abstract class AbstractQueuedLongSynchronizer * @return {@code true} if acquired */ private boolean doAcquireSharedNanos(long arg, long nanosTimeout) - throws InterruptedException { - - long lastTime = System.nanoTime(); + throws InterruptedException { + if (nanosTimeout <= 0L) + return false; + final long deadline = System.nanoTime() + nanosTimeout; final Node node = addWaiter(Node.SHARED); boolean failed = true; try { @@ -773,14 +776,12 @@ public abstract class AbstractQueuedLongSynchronizer return true; } } - if (nanosTimeout <= 0) + nanosTimeout = deadline - System.nanoTime(); + if (nanosTimeout <= 0L) 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(); } @@ -1036,7 +1037,7 @@ public abstract class AbstractQueuedLongSynchronizer * thread is queued, possibly repeatedly blocking and unblocking, * invoking {@link #tryAcquireShared} until success or the thread * is interrupted. - * @param arg the acquire argument + * @param arg the acquire argument. * This value is conveyed to {@link #tryAcquireShared} but is * otherwise uninterpreted and can represent anything * you like. @@ -1254,8 +1255,9 @@ public abstract class AbstractQueuedLongSynchronizer * 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 */ - /*public*/ final boolean hasQueuedPredecessors() { // android-changed + 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. @@ -1411,7 +1413,7 @@ public abstract class AbstractQueuedLongSynchronizer * Returns true if successful. * @param node the node * @return true if successfully transferred (else the node was - * cancelled before signal). + * cancelled before signal) */ final boolean transferForSignal(Node node) { /* @@ -1434,10 +1436,10 @@ public abstract class AbstractQueuedLongSynchronizer } /** - * Transfers node, if necessary, to sync queue after a cancelled - * wait. Returns true if thread was cancelled before being - * signalled. - * @param node its node + * Transfers node, if necessary, to sync queue after a cancelled wait. + * Returns true if thread was cancelled before being signalled. + * + * @param node the node * @return true if cancelled before the node was signalled */ final boolean transferAfterCancelledWait(Node node) { @@ -1485,25 +1487,23 @@ public abstract class AbstractQueuedLongSynchronizer * uses this synchronizer as its lock. * * @param condition the condition - * @return true if owned + * @return {@code true} if owned * @throws NullPointerException if the condition is null */ public final boolean owns(ConditionObject condition) { - if (condition == null) - throw new NullPointerException(); return condition.isOwnedBy(this); } /** * Queries whether any threads are waiting on the given condition * associated with this synchronizer. Note that because timeouts - * and interrupts may occur at any time, a true return - * does not guarantee that a future signal will awaken + * and interrupts may occur at any time, a {@code true} return + * does not guarantee that a future {@code signal} will awaken * any threads. This method is designed primarily for use in * monitoring of the system state. * * @param condition the condition - * @return true if there are any waiting threads + * @return {@code true} if there are any waiting threads * @throws IllegalMonitorStateException if exclusive synchronization * is not held * @throws IllegalArgumentException if the given condition is @@ -1570,7 +1570,7 @@ public abstract class AbstractQueuedLongSynchronizer * and Condition users. Exported versions of this class will in * general need to be accompanied by documentation describing * condition semantics that rely on those of the associated - * AbstractQueuedLongSynchronizer. + * {@code AbstractQueuedLongSynchronizer}. * *

        This class is Serializable, but all fields are transient, * so deserialized conditions have no waiters. @@ -1585,7 +1585,7 @@ public abstract class AbstractQueuedLongSynchronizer private transient Node lastWaiter; /** - * Creates a new ConditionObject instance. + * Creates a new {@code ConditionObject} instance. */ public ConditionObject() { } @@ -1711,9 +1711,8 @@ public abstract class AbstractQueuedLongSynchronizer * Implements uninterruptible condition wait. *

          *
        1. Save lock state returned by {@link #getState}. - *
        2. Invoke {@link #release} with - * saved state as argument, throwing - * IllegalMonitorStateException if it fails. + *
        3. Invoke {@link #release} with saved state as argument, + * throwing IllegalMonitorStateException if it fails. *
        4. Block until signalled. *
        5. Reacquire by invoking specialized version of * {@link #acquire} with saved state as argument. @@ -1772,9 +1771,8 @@ public abstract class AbstractQueuedLongSynchronizer *
            *
          1. If current thread is interrupted, throw InterruptedException. *
          2. Save lock state returned by {@link #getState}. - *
          3. Invoke {@link #release} with - * saved state as argument, throwing - * IllegalMonitorStateException if it fails. + *
          4. Invoke {@link #release} with saved state as argument, + * throwing IllegalMonitorStateException if it fails. *
          5. Block until signalled or interrupted. *
          6. Reacquire by invoking specialized version of * {@link #acquire} with saved state as argument. @@ -1805,9 +1803,8 @@ public abstract class AbstractQueuedLongSynchronizer *
              *
            1. If current thread is interrupted, throw InterruptedException. *
            2. Save lock state returned by {@link #getState}. - *
            3. Invoke {@link #release} with - * saved state as argument, throwing - * IllegalMonitorStateException if it fails. + *
            4. Invoke {@link #release} with saved state as argument, + * throwing IllegalMonitorStateException if it fails. *
            5. Block until signalled, interrupted, or timed out. *
            6. Reacquire by invoking specialized version of * {@link #acquire} with saved state as argument. @@ -1820,20 +1817,18 @@ public abstract class AbstractQueuedLongSynchronizer throw new InterruptedException(); Node node = addConditionWaiter(); long savedState = fullyRelease(node); - long lastTime = System.nanoTime(); + final long deadline = System.nanoTime() + nanosTimeout; int interruptMode = 0; while (!isOnSyncQueue(node)) { if (nanosTimeout <= 0L) { transferAfterCancelledWait(node); break; } - LockSupport.parkNanos(this, nanosTimeout); + if (nanosTimeout >= spinForTimeoutThreshold) + LockSupport.parkNanos(this, nanosTimeout); if ((interruptMode = checkInterruptWhileWaiting(node)) != 0) break; - - long now = System.nanoTime(); - nanosTimeout -= now - lastTime; - lastTime = now; + nanosTimeout = deadline - System.nanoTime(); } if (acquireQueued(node, savedState) && interruptMode != THROW_IE) interruptMode = REINTERRUPT; @@ -1841,7 +1836,7 @@ public abstract class AbstractQueuedLongSynchronizer unlinkCancelledWaiters(); if (interruptMode != 0) reportInterruptAfterWait(interruptMode); - return nanosTimeout - (System.nanoTime() - lastTime); + return deadline - System.nanoTime(); } /** @@ -1849,9 +1844,8 @@ public abstract class AbstractQueuedLongSynchronizer *
                *
              1. If current thread is interrupted, throw InterruptedException. *
              2. Save lock state returned by {@link #getState}. - *
              3. Invoke {@link #release} with - * saved state as argument, throwing - * IllegalMonitorStateException if it fails. + *
              4. Invoke {@link #release} with saved state as argument, + * throwing IllegalMonitorStateException if it fails. *
              5. Block until signalled, interrupted, or timed out. *
              6. Reacquire by invoking specialized version of * {@link #acquire} with saved state as argument. @@ -1861,8 +1855,6 @@ public abstract class AbstractQueuedLongSynchronizer */ public final boolean awaitUntil(Date deadline) throws InterruptedException { - if (deadline == null) - throw new NullPointerException(); long abstime = deadline.getTime(); if (Thread.interrupted()) throw new InterruptedException(); @@ -1893,9 +1885,8 @@ public abstract class AbstractQueuedLongSynchronizer *
                  *
                1. If current thread is interrupted, throw InterruptedException. *
                2. Save lock state returned by {@link #getState}. - *
                3. Invoke {@link #release} with - * saved state as argument, throwing - * IllegalMonitorStateException if it fails. + *
                4. Invoke {@link #release} with saved state as argument, + * throwing IllegalMonitorStateException if it fails. *
                5. Block until signalled, interrupted, or timed out. *
                6. Reacquire by invoking specialized version of * {@link #acquire} with saved state as argument. @@ -1905,14 +1896,12 @@ public abstract class AbstractQueuedLongSynchronizer */ 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(); + final long deadline = System.nanoTime() + nanosTimeout; boolean timedout = false; int interruptMode = 0; while (!isOnSyncQueue(node)) { @@ -1924,9 +1913,7 @@ public abstract class AbstractQueuedLongSynchronizer LockSupport.parkNanos(this, nanosTimeout); if ((interruptMode = checkInterruptWhileWaiting(node)) != 0) break; - long now = System.nanoTime(); - nanosTimeout -= now - lastTime; - lastTime = now; + nanosTimeout = deadline - System.nanoTime(); } if (acquireQueued(node, savedState) && interruptMode != THROW_IE) interruptMode = REINTERRUPT; diff --git a/luni/src/main/java/java/util/concurrent/locks/AbstractQueuedSynchronizer.java b/luni/src/main/java/java/util/concurrent/locks/AbstractQueuedSynchronizer.java index 42029f0..0350060 100644 --- a/luni/src/main/java/java/util/concurrent/locks/AbstractQueuedSynchronizer.java +++ b/luni/src/main/java/java/util/concurrent/locks/AbstractQueuedSynchronizer.java @@ -5,8 +5,10 @@ */ package java.util.concurrent.locks; -import java.util.*; -import java.util.concurrent.*; +import java.util.concurrent.TimeUnit; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; import sun.misc.Unsafe; // BEGIN android-note @@ -18,12 +20,12 @@ import sun.misc.Unsafe; * synchronizers (semaphores, events, etc) that rely on * first-in-first-out (FIFO) wait queues. This class is designed to * be a useful basis for most kinds of synchronizers that rely on a - * single atomic int value to represent state. Subclasses + * single atomic {@code int} value to represent state. Subclasses * must define the protected methods that change this state, and which * define what that state means in terms of this object being acquired * or released. Given these, the other methods in this class carry * out all queuing and blocking mechanics. Subclasses can maintain - * other state fields, but only the atomically updated int + * other state fields, but only the atomically updated {@code int} * value manipulated using methods {@link #getState}, {@link * #setState} and {@link #compareAndSetState} is tracked with respect * to synchronization. @@ -31,7 +33,7 @@ import sun.misc.Unsafe; *

                  Subclasses should be defined as non-public internal helper * classes that are used to implement the synchronization properties * of their enclosing class. Class - * AbstractQueuedSynchronizer does not implement any + * {@code AbstractQueuedSynchronizer} does not implement any * synchronization interface. Instead it defines methods such as * {@link #acquireInterruptibly} that can be invoked as * appropriate by concrete locks and related synchronizers to @@ -58,7 +60,7 @@ import sun.misc.Unsafe; * invoked with the current {@link #getState} value fully releases * this object, and {@link #acquire}, given this saved state value, * eventually restores this object to its previous acquired state. No - * AbstractQueuedSynchronizer method otherwise creates such a + * {@code AbstractQueuedSynchronizer} method otherwise creates such a * condition, so if this constraint cannot be met, do not use it. The * behavior of {@link ConditionObject} depends of course on the * semantics of its synchronizer implementation. @@ -66,13 +68,13 @@ import sun.misc.Unsafe; *

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

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

                  Usage

                  @@ -88,14 +90,14 @@ import sun.misc.Unsafe; *
                7. {@link #tryAcquireShared} *
                8. {@link #tryReleaseShared} *
                9. {@link #isHeldExclusively} - *
      + * * * Each of these methods by default throws {@link * UnsupportedOperationException}. Implementations of these methods * must be internally thread-safe, and should in general be short and * not block. Defining these methods is the only supported * means of using this class. All other methods are declared - * final because they cannot be independently varied. + * {@code final} because they cannot be independently varied. * *

      You may also find the inherited methods from {@link * AbstractOwnableSynchronizer} useful to keep track of the thread @@ -121,19 +123,19 @@ import sun.misc.Unsafe; * * (Shared mode is similar but may involve cascading signals.) * - *

      Because checks in acquire are invoked before + *

      Because checks in acquire are invoked before * enqueuing, a newly acquiring thread may barge ahead of - * others that are blocked and queued. However, you can, if desired, - * define tryAcquire and/or tryAcquireShared to + * others that are blocked and queued. However, you can, if desired, + * define {@code tryAcquire} and/or {@code tryAcquireShared} to * disable barging by internally invoking one or more of the inspection * methods. In particular, a strict FIFO lock can define - * tryAcquire to immediately return false if {@link + * {@code tryAcquire} to immediately return {@code false} if {@link * #getFirstQueuedThread} does not return the current thread. A * normally preferable non-strict fair version can immediately return - * false only if {@link #hasQueuedThreads} returns - * true and getFirstQueuedThread is not the current - * thread; or equivalently, that getFirstQueuedThread is both - * non-null and not the current thread. Further variations are + * {@code false} only if {@link #hasQueuedThreads} returns + * {@code true} and {@code getFirstQueuedThread} is not the current + * thread; or equivalently, that {@code getFirstQueuedThread} is both + * non-null and not the current thread. Further variations are * possible. * *

      Throughput and scalability are generally highest for the @@ -144,7 +146,7 @@ import sun.misc.Unsafe; * threads, and each recontention has an unbiased chance to succeed * against incoming threads. Also, while acquires do not * "spin" in the usual sense, they may perform multiple - * invocations of tryAcquire interspersed with other + * invocations of {@code tryAcquire} interspersed with other * computations before blocking. This gives most of the benefits of * spins when exclusive synchronization is only briefly held, without * most of the liabilities when it isn't. If so desired, you can @@ -155,7 +157,7 @@ import sun.misc.Unsafe; * *

      This class provides an efficient and scalable basis for * synchronization in part by specializing its range of use to - * synchronizers that can rely on int state, acquire, and + * synchronizers that can rely on {@code int} state, acquire, and * release parameters, and an internal FIFO wait queue. When this does * not suffice, you can build synchronizers from a lower level using * {@link java.util.concurrent.atomic atomic} classes, your own custom @@ -177,12 +179,12 @@ import sun.misc.Unsafe; * * // Our internal helper class * private static class Sync extends AbstractQueuedSynchronizer { - * // Report whether in locked state + * // Reports whether in locked state * protected boolean isHeldExclusively() { * return getState() == 1; * } * - * // Acquire the lock if state is zero + * // Acquires the lock if state is zero * public boolean tryAcquire(int acquires) { * assert acquires == 1; // Otherwise unused * if (compareAndSetState(0, 1)) { @@ -192,7 +194,7 @@ import sun.misc.Unsafe; * return false; * } * - * // Release the lock by setting state to zero + * // Releases the lock by setting state to zero * protected boolean tryRelease(int releases) { * assert releases == 1; // Otherwise unused * if (getState() == 0) throw new IllegalMonitorStateException(); @@ -201,10 +203,10 @@ import sun.misc.Unsafe; * return true; * } * - * // Provide a Condition + * // Provides a Condition * Condition newCondition() { return new ConditionObject(); } * - * // Deserialize properly + * // Deserializes properly * private void readObject(ObjectInputStream s) * throws IOException, ClassNotFoundException { * s.defaultReadObject(); @@ -230,9 +232,10 @@ import sun.misc.Unsafe; * } * }} * - *

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

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

       {@code
      @@ -269,7 +272,7 @@ public abstract class AbstractQueuedSynchronizer
           private static final long serialVersionUID = 7373984972572414691L;
       
           /**
      -     * Creates a new AbstractQueuedSynchronizer instance
      +     * Creates a new {@code AbstractQueuedSynchronizer} instance
            * with initial synchronization state of zero.
            */
           protected AbstractQueuedSynchronizer() { }
      @@ -302,7 +305,7 @@ public abstract class AbstractQueuedSynchronizer
            *
            * 

      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 + * demarcation from unqueued to queued. Similarly, dequeuing * 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 @@ -409,7 +412,7 @@ public abstract class AbstractQueuedSynchronizer /** * Link to predecessor node that current node/thread relies on - * for checking waitStatus. Assigned during enqueing, and nulled + * for checking waitStatus. Assigned during enqueuing, 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 @@ -454,7 +457,7 @@ public abstract class AbstractQueuedSynchronizer Node nextWaiter; /** - * Returns true if node is waiting in shared mode + * Returns true if node is waiting in shared mode. */ final boolean isShared() { return nextWaiter == SHARED; @@ -510,7 +513,7 @@ public abstract class AbstractQueuedSynchronizer /** * Returns the current value of synchronization state. - * This operation has memory semantics of a volatile read. + * This operation has memory semantics of a {@code volatile} read. * @return current state value */ protected final int getState() { @@ -519,7 +522,7 @@ public abstract class AbstractQueuedSynchronizer /** * Sets the value of synchronization state. - * This operation has memory semantics of a volatile write. + * This operation has memory semantics of a {@code volatile} write. * @param newState the new state value */ protected final void setState(int newState) { @@ -529,7 +532,7 @@ public abstract class AbstractQueuedSynchronizer /** * Atomically sets synchronization state to the given updated * value if the current state value equals the expected value. - * This operation has memory semantics of a volatile read + * This operation has memory semantics of a {@code volatile} read * and write. * * @param expect the expected value @@ -639,7 +642,7 @@ public abstract class AbstractQueuedSynchronizer } /** - * Release action for shared mode -- signal successor and ensure + * Release action for shared mode -- signals successor and ensures * propagation. (Note: For exclusive mode, release just amounts * to calling unparkSuccessor of head if it needs signal.) */ @@ -760,7 +763,7 @@ public abstract class AbstractQueuedSynchronizer /** * 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 + * control in all acquire loops. Requires that pred == node.prev. * * @param pred node's predecessor holding status * @param node the node @@ -885,8 +888,10 @@ public abstract class AbstractQueuedSynchronizer * @return {@code true} if acquired */ private boolean doAcquireNanos(int arg, long nanosTimeout) - throws InterruptedException { - long lastTime = System.nanoTime(); + throws InterruptedException { + if (nanosTimeout <= 0L) + return false; + final long deadline = System.nanoTime() + nanosTimeout; final Node node = addWaiter(Node.EXCLUSIVE); boolean failed = true; try { @@ -898,14 +903,12 @@ public abstract class AbstractQueuedSynchronizer failed = false; return true; } - if (nanosTimeout <= 0) + nanosTimeout = deadline - System.nanoTime(); + if (nanosTimeout <= 0L) 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(); } @@ -985,9 +988,10 @@ public abstract class AbstractQueuedSynchronizer * @return {@code true} if acquired */ private boolean doAcquireSharedNanos(int arg, long nanosTimeout) - throws InterruptedException { - - long lastTime = System.nanoTime(); + throws InterruptedException { + if (nanosTimeout <= 0L) + return false; + final long deadline = System.nanoTime() + nanosTimeout; final Node node = addWaiter(Node.SHARED); boolean failed = true; try { @@ -1002,14 +1006,12 @@ public abstract class AbstractQueuedSynchronizer return true; } } - if (nanosTimeout <= 0) + nanosTimeout = deadline - System.nanoTime(); + if (nanosTimeout <= 0L) 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(); } @@ -1265,7 +1267,7 @@ public abstract class AbstractQueuedSynchronizer * thread is queued, possibly repeatedly blocking and unblocking, * invoking {@link #tryAcquireShared} until success or the thread * is interrupted. - * @param arg the acquire argument + * @param arg the acquire argument. * This value is conveyed to {@link #tryAcquireShared} but is * otherwise uninterpreted and can represent anything * you like. @@ -1641,7 +1643,7 @@ public abstract class AbstractQueuedSynchronizer * Returns true if successful. * @param node the node * @return true if successfully transferred (else the node was - * cancelled before signal). + * cancelled before signal) */ final boolean transferForSignal(Node node) { /* @@ -1664,10 +1666,10 @@ public abstract class AbstractQueuedSynchronizer } /** - * Transfers node, if necessary, to sync queue after a cancelled - * wait. Returns true if thread was cancelled before being - * signalled. - * @param node its node + * Transfers node, if necessary, to sync queue after a cancelled wait. + * Returns true if thread was cancelled before being signalled. + * + * @param node the node * @return true if cancelled before the node was signalled */ final boolean transferAfterCancelledWait(Node node) { @@ -1715,25 +1717,23 @@ public abstract class AbstractQueuedSynchronizer * uses this synchronizer as its lock. * * @param condition the condition - * @return true if owned + * @return {@code true} if owned * @throws NullPointerException if the condition is null */ public final boolean owns(ConditionObject condition) { - if (condition == null) - throw new NullPointerException(); return condition.isOwnedBy(this); } /** * Queries whether any threads are waiting on the given condition * associated with this synchronizer. Note that because timeouts - * and interrupts may occur at any time, a true return - * does not guarantee that a future signal will awaken + * and interrupts may occur at any time, a {@code true} return + * does not guarantee that a future {@code signal} will awaken * any threads. This method is designed primarily for use in * monitoring of the system state. * * @param condition the condition - * @return true if there are any waiting threads + * @return {@code true} if there are any waiting threads * @throws IllegalMonitorStateException if exclusive synchronization * is not held * @throws IllegalArgumentException if the given condition is @@ -1800,7 +1800,7 @@ public abstract class AbstractQueuedSynchronizer * and Condition users. Exported versions of this class will in * general need to be accompanied by documentation describing * condition semantics that rely on those of the associated - * AbstractQueuedSynchronizer. + * {@code AbstractQueuedSynchronizer}. * *

      This class is Serializable, but all fields are transient, * so deserialized conditions have no waiters. @@ -1813,7 +1813,7 @@ public abstract class AbstractQueuedSynchronizer private transient Node lastWaiter; /** - * Creates a new ConditionObject instance. + * Creates a new {@code ConditionObject} instance. */ public ConditionObject() { } @@ -1939,9 +1939,8 @@ public abstract class AbstractQueuedSynchronizer * Implements uninterruptible condition wait. *

        *
      1. Save lock state returned by {@link #getState}. - *
      2. Invoke {@link #release} with - * saved state as argument, throwing - * IllegalMonitorStateException if it fails. + *
      3. Invoke {@link #release} with saved state as argument, + * throwing IllegalMonitorStateException if it fails. *
      4. Block until signalled. *
      5. Reacquire by invoking specialized version of * {@link #acquire} with saved state as argument. @@ -2000,9 +1999,8 @@ public abstract class AbstractQueuedSynchronizer *
          *
        1. If current thread is interrupted, throw InterruptedException. *
        2. Save lock state returned by {@link #getState}. - *
        3. Invoke {@link #release} with - * saved state as argument, throwing - * IllegalMonitorStateException if it fails. + *
        4. Invoke {@link #release} with saved state as argument, + * throwing IllegalMonitorStateException if it fails. *
        5. Block until signalled or interrupted. *
        6. Reacquire by invoking specialized version of * {@link #acquire} with saved state as argument. @@ -2033,9 +2031,8 @@ public abstract class AbstractQueuedSynchronizer *
            *
          1. If current thread is interrupted, throw InterruptedException. *
          2. Save lock state returned by {@link #getState}. - *
          3. Invoke {@link #release} with - * saved state as argument, throwing - * IllegalMonitorStateException if it fails. + *
          4. Invoke {@link #release} with saved state as argument, + * throwing IllegalMonitorStateException if it fails. *
          5. Block until signalled, interrupted, or timed out. *
          6. Reacquire by invoking specialized version of * {@link #acquire} with saved state as argument. @@ -2048,20 +2045,18 @@ public abstract class AbstractQueuedSynchronizer throw new InterruptedException(); Node node = addConditionWaiter(); int savedState = fullyRelease(node); - long lastTime = System.nanoTime(); + final long deadline = System.nanoTime() + nanosTimeout; int interruptMode = 0; while (!isOnSyncQueue(node)) { if (nanosTimeout <= 0L) { transferAfterCancelledWait(node); break; } - LockSupport.parkNanos(this, nanosTimeout); + if (nanosTimeout >= spinForTimeoutThreshold) + LockSupport.parkNanos(this, nanosTimeout); if ((interruptMode = checkInterruptWhileWaiting(node)) != 0) break; - - long now = System.nanoTime(); - nanosTimeout -= now - lastTime; - lastTime = now; + nanosTimeout = deadline - System.nanoTime(); } if (acquireQueued(node, savedState) && interruptMode != THROW_IE) interruptMode = REINTERRUPT; @@ -2069,7 +2064,7 @@ public abstract class AbstractQueuedSynchronizer unlinkCancelledWaiters(); if (interruptMode != 0) reportInterruptAfterWait(interruptMode); - return nanosTimeout - (System.nanoTime() - lastTime); + return deadline - System.nanoTime(); } /** @@ -2077,9 +2072,8 @@ public abstract class AbstractQueuedSynchronizer *
              *
            1. If current thread is interrupted, throw InterruptedException. *
            2. Save lock state returned by {@link #getState}. - *
            3. Invoke {@link #release} with - * saved state as argument, throwing - * IllegalMonitorStateException if it fails. + *
            4. Invoke {@link #release} with saved state as argument, + * throwing IllegalMonitorStateException if it fails. *
            5. Block until signalled, interrupted, or timed out. *
            6. Reacquire by invoking specialized version of * {@link #acquire} with saved state as argument. @@ -2089,8 +2083,6 @@ public abstract class AbstractQueuedSynchronizer */ public final boolean awaitUntil(Date deadline) throws InterruptedException { - if (deadline == null) - throw new NullPointerException(); long abstime = deadline.getTime(); if (Thread.interrupted()) throw new InterruptedException(); @@ -2121,9 +2113,8 @@ public abstract class AbstractQueuedSynchronizer *
                *
              1. If current thread is interrupted, throw InterruptedException. *
              2. Save lock state returned by {@link #getState}. - *
              3. Invoke {@link #release} with - * saved state as argument, throwing - * IllegalMonitorStateException if it fails. + *
              4. Invoke {@link #release} with saved state as argument, + * throwing IllegalMonitorStateException if it fails. *
              5. Block until signalled, interrupted, or timed out. *
              6. Reacquire by invoking specialized version of * {@link #acquire} with saved state as argument. @@ -2133,14 +2124,12 @@ public abstract class AbstractQueuedSynchronizer */ public final boolean await(long time, TimeUnit unit) throws InterruptedException { - if (unit == null) - throw new NullPointerException(); long nanosTimeout = unit.toNanos(time); if (Thread.interrupted()) throw new InterruptedException(); Node node = addConditionWaiter(); int savedState = fullyRelease(node); - long lastTime = System.nanoTime(); + final long deadline = System.nanoTime() + nanosTimeout; boolean timedout = false; int interruptMode = 0; while (!isOnSyncQueue(node)) { @@ -2152,9 +2141,7 @@ public abstract class AbstractQueuedSynchronizer LockSupport.parkNanos(this, nanosTimeout); if ((interruptMode = checkInterruptWhileWaiting(node)) != 0) break; - long now = System.nanoTime(); - nanosTimeout -= now - lastTime; - lastTime = now; + nanosTimeout = deadline - System.nanoTime(); } if (acquireQueued(node, savedState) && interruptMode != THROW_IE) interruptMode = REINTERRUPT; diff --git a/luni/src/main/java/java/util/concurrent/locks/Condition.java b/luni/src/main/java/java/util/concurrent/locks/Condition.java index 7050df9..522e9e2 100644 --- a/luni/src/main/java/java/util/concurrent/locks/Condition.java +++ b/luni/src/main/java/java/util/concurrent/locks/Condition.java @@ -5,7 +5,7 @@ */ package java.util.concurrent.locks; -import java.util.concurrent.*; +import java.util.concurrent.TimeUnit; import java.util.Date; /** @@ -295,7 +295,7 @@ public interface Condition { * } * }}
      * - *

      Design note: This method requires a nanosecond argument so + *

      Design note: This method requires a nanosecond argument so * as to avoid truncation errors in reporting remaining times. * Such precision loss would make it difficult for programmers to * ensure that total waiting times are not systematically shorter diff --git a/luni/src/main/java/java/util/concurrent/locks/Lock.java b/luni/src/main/java/java/util/concurrent/locks/Lock.java index d5c6294..6eeb236 100644 --- a/luni/src/main/java/java/util/concurrent/locks/Lock.java +++ b/luni/src/main/java/java/util/concurrent/locks/Lock.java @@ -91,8 +91,9 @@ import java.util.concurrent.TimeUnit; * *

      All {@code Lock} implementations must enforce the same * memory synchronization semantics as provided by the built-in monitor - * lock, as described in - * The Java Language Specification, Third Edition (17.4 Memory Model): + * lock, as described in + * + * The Java Language Specification (17.4 Memory Model): *

        *
      • A successful {@code lock} operation has the same memory * synchronization effects as a successful Lock action. @@ -106,7 +107,7 @@ import java.util.concurrent.TimeUnit; * *

        Implementation Considerations

        * - *

        The three forms of lock acquisition (interruptible, + *

        The three forms of lock acquisition (interruptible, * non-interruptible, and timed) may differ in their performance * characteristics, ordering guarantees, or other implementation * qualities. Further, the ability to interrupt the ongoing @@ -197,7 +198,7 @@ public interface Lock { * * @throws InterruptedException if the current thread is * interrupted while acquiring the lock (and interruption - * of lock acquisition is supported). + * of lock acquisition is supported) */ void lockInterruptibly() throws InterruptedException; diff --git a/luni/src/main/java/java/util/concurrent/locks/LockSupport.java b/luni/src/main/java/java/util/concurrent/locks/LockSupport.java index 422e428..875b2bf 100644 --- a/luni/src/main/java/java/util/concurrent/locks/LockSupport.java +++ b/luni/src/main/java/java/util/concurrent/locks/LockSupport.java @@ -7,7 +7,6 @@ package java.util.concurrent.locks; import sun.misc.Unsafe; - /** * Basic thread blocking primitives for creating locks and other * synchronization classes. @@ -73,14 +72,14 @@ import sun.misc.Unsafe; * // Block while not first in queue or cannot acquire lock * while (waiters.peek() != current || * !locked.compareAndSet(false, true)) { - * LockSupport.park(this); - * if (Thread.interrupted()) // ignore interrupts while waiting - * wasInterrupted = true; + * LockSupport.park(this); + * if (Thread.interrupted()) // ignore interrupts while waiting + * wasInterrupted = true; * } * * waiters.remove(); * if (wasInterrupted) // reassert interrupt status on exit - * current.interrupt(); + * current.interrupt(); * } * * public void unlock() { @@ -89,7 +88,6 @@ import sun.misc.Unsafe; * } * }} */ - public class LockSupport { private LockSupport() {} // Cannot be instantiated. diff --git a/luni/src/main/java/java/util/concurrent/locks/ReadWriteLock.java b/luni/src/main/java/java/util/concurrent/locks/ReadWriteLock.java index bb7b388..8690355 100644 --- a/luni/src/main/java/java/util/concurrent/locks/ReadWriteLock.java +++ b/luni/src/main/java/java/util/concurrent/locks/ReadWriteLock.java @@ -7,16 +7,16 @@ package java.util.concurrent.locks; /** - * A ReadWriteLock maintains a pair of associated {@link + * A {@code ReadWriteLock} maintains a pair of associated {@link * Lock locks}, one for read-only operations and one for writing. * The {@link #readLock read lock} may be held simultaneously by * multiple reader threads, so long as there are no writers. The * {@link #writeLock write lock} is exclusive. * - *

        All ReadWriteLock implementations must guarantee that - * the memory synchronization effects of writeLock operations + *

        All {@code ReadWriteLock} implementations must guarantee that + * the memory synchronization effects of {@code writeLock} operations * (as specified in the {@link Lock} interface) also hold with respect - * to the associated readLock. That is, a thread successfully + * to the associated {@code readLock}. That is, a thread successfully * acquiring the read lock will see all updates made upon previous * release of the write lock. * @@ -91,14 +91,14 @@ public interface ReadWriteLock { /** * Returns the lock used for reading. * - * @return the lock used for reading. + * @return the lock used for reading */ Lock readLock(); /** * Returns the lock used for writing. * - * @return the lock used for writing. + * @return the lock used for writing */ Lock writeLock(); } diff --git a/luni/src/main/java/java/util/concurrent/locks/ReentrantLock.java b/luni/src/main/java/java/util/concurrent/locks/ReentrantLock.java index 07baf41..bde4741 100644 --- a/luni/src/main/java/java/util/concurrent/locks/ReentrantLock.java +++ b/luni/src/main/java/java/util/concurrent/locks/ReentrantLock.java @@ -5,8 +5,8 @@ */ package java.util.concurrent.locks; -import java.util.*; -import java.util.concurrent.*; +import java.util.concurrent.TimeUnit; +import java.util.Collection; /** * A reentrant mutual exclusion {@link Lock} with the same basic @@ -35,7 +35,7 @@ import java.util.concurrent.*; * fair lock may obtain it multiple times in succession while other * active threads are not progressing and not currently holding the * lock. - * Also note that the untimed {@link #tryLock() tryLock} method does not + * Also note that the untimed {@link #tryLock()} method does not * honor the fairness setting. It will succeed if the lock * is available even if other threads are waiting. * @@ -59,10 +59,9 @@ import java.util.concurrent.*; * }} * *

        In addition to implementing the {@link Lock} interface, this - * class defines methods {@code isLocked} and - * {@code getLockQueueLength}, as well as some associated - * {@code protected} access methods that may be useful for - * instrumentation and monitoring. + * class defines a number of {@code public} and {@code protected} + * methods for inspecting the state of the lock. Some of these + * methods are only useful for instrumentation and monitoring. * *

        Serialization of this class behaves in the same way as built-in * locks: a deserialized lock is in the unlocked state, regardless of @@ -95,9 +94,8 @@ public class ReentrantLock implements Lock, java.io.Serializable { abstract void lock(); /** - * Performs non-fair tryLock. tryAcquire is - * implemented in subclasses, but both need nonfair - * try for trylock method. + * Performs non-fair tryLock. tryAcquire is implemented in + * subclasses, but both need nonfair try for trylock method. */ final boolean nonfairTryAcquire(int acquires) { final Thread current = Thread.currentThread(); @@ -156,8 +154,7 @@ public class ReentrantLock implements Lock, java.io.Serializable { } /** - * Reconstitutes this lock instance from a stream. - * @param s the stream + * Reconstitutes the instance from a stream (that is, deserializes it). */ private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { @@ -325,7 +322,7 @@ public class ReentrantLock implements Lock, java.io.Serializable { * {@link #tryLock(long, TimeUnit) tryLock(0, TimeUnit.SECONDS) } * which is almost equivalent (it also detects interruption). * - *

        If the current thread already holds this lock then the hold + *

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

        If the lock is held by another thread then this method will return @@ -410,7 +407,6 @@ public class ReentrantLock implements Lock, java.io.Serializable { * the lock could be acquired * @throws InterruptedException if the current thread is interrupted * @throws NullPointerException if the time unit is null - * */ public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException { @@ -605,7 +601,6 @@ public class ReentrantLock implements Lock, java.io.Serializable { return sync.hasQueuedThreads(); } - /** * Queries whether the given thread is waiting to acquire this * lock. Note that because cancellations may occur at any time, a @@ -621,7 +616,6 @@ public class ReentrantLock implements Lock, java.io.Serializable { return sync.isQueued(thread); } - /** * Returns an estimate of the number of threads waiting to * acquire this lock. The value is only an estimate because the number of diff --git a/luni/src/main/java/java/util/concurrent/locks/ReentrantReadWriteLock.java b/luni/src/main/java/java/util/concurrent/locks/ReentrantReadWriteLock.java index 244a4a7..2d3c65d 100644 --- a/luni/src/main/java/java/util/concurrent/locks/ReentrantReadWriteLock.java +++ b/luni/src/main/java/java/util/concurrent/locks/ReentrantReadWriteLock.java @@ -5,8 +5,8 @@ */ package java.util.concurrent.locks; -import java.util.concurrent.*; -import java.util.*; +import java.util.concurrent.TimeUnit; +import java.util.Collection; /** * An implementation of {@link ReadWriteLock} supporting similar @@ -16,7 +16,7 @@ import java.util.*; *

          *
        • Acquisition order * - *

          This class does not impose a reader or writer preference + *

          This class does not impose a reader or writer preference * ordering for lock access. However, it does support an optional * fairness policy. * @@ -30,7 +30,7 @@ import java.util.*; *

          * *

          Fair mode - *
          When constructed as fair, threads contend for entry using an + *
          When constructed as fair, threads contend for entry using an * approximately arrival-order policy. When the currently held lock * is released, either the longest-waiting single writer thread will * be assigned the write lock, or if there is a group of reader threads @@ -183,7 +183,6 @@ import java.util.*; * * @since 1.5 * @author Doug Lea - * */ public class ReentrantReadWriteLock implements ReadWriteLock, java.io.Serializable { @@ -624,10 +623,7 @@ public class ReentrantReadWriteLock } /** - * Reconstitutes this lock instance from a stream (that is, - * deserializes it). - * - * @param s the stream + * Reconstitutes the instance from a stream (that is, deserializes it). */ private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { @@ -771,7 +767,7 @@ public class ReentrantReadWriteLock * * @return {@code true} if the read lock was acquired */ - public boolean tryLock() { + public boolean tryLock() { return sync.tryReadLock(); } @@ -841,7 +837,6 @@ public class ReentrantReadWriteLock * @return {@code true} if the read lock was acquired * @throws InterruptedException if the current thread is interrupted * @throws NullPointerException if the time unit is null - * */ public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException { @@ -851,10 +846,10 @@ public class ReentrantReadWriteLock /** * Attempts to release this lock. * - *

          If the number of readers is now zero then the lock + *

          If the number of readers is now zero then the lock * is made available for write lock attempts. */ - public void unlock() { + public void unlock() { sync.releaseShared(1); } @@ -993,7 +988,7 @@ public class ReentrantReadWriteLock * #tryLock(long, TimeUnit) tryLock(0, TimeUnit.SECONDS) } * which is almost equivalent (it also detects interruption). * - *

          If the current thread already holds this lock then the + *

          If the current thread already holds this lock then the * hold count is incremented by one and the method returns * {@code true}. * @@ -1086,7 +1081,6 @@ public class ReentrantReadWriteLock * * @throws InterruptedException if the current thread is interrupted * @throws NullPointerException if the time unit is null - * */ public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException { @@ -1103,7 +1097,7 @@ public class ReentrantReadWriteLock * IllegalMonitorStateException} is thrown. * * @throws IllegalMonitorStateException if the current thread does not - * hold this lock. + * hold this lock */ public void unlock() { sync.release(1); @@ -1231,7 +1225,7 @@ public class ReentrantReadWriteLock * Queries the number of read locks held for this lock. This * method is designed for use in monitoring system state, not for * synchronization control. - * @return the number of read locks held. + * @return the number of read locks held */ public int getReadLockCount() { return sync.getReadLockCount(); diff --git a/luni/src/main/java/java/util/concurrent/package-info.java b/luni/src/main/java/java/util/concurrent/package-info.java index 155d1b8..51a29e8 100644 --- a/luni/src/main/java/java/util/concurrent/package-info.java +++ b/luni/src/main/java/java/util/concurrent/package-info.java @@ -5,7 +5,7 @@ */ // BEGIN android-note -// omit links to ForkJoinPool, ForkJoinTask, LinkedTransferQueue, PHaser, TransferQueue +// omit links to ForkJoinPool, ForkJoinTask, LinkedTransferQueue, Phaser, TransferQueue // END android-note /** @@ -23,7 +23,7 @@ * * {@link java.util.concurrent.Executor} is a simple standardized * interface for defining custom thread-like subsystems, including - * thread pools, asynchronous IO, and lightweight task frameworks. + * thread pools, asynchronous I/O, and lightweight task frameworks. * Depending on which concrete Executor class is being used, tasks may * execute in a newly created thread, an existing task-execution thread, * or the thread calling {@link java.util.concurrent.Executor#execute @@ -174,7 +174,7 @@ * it may (or may not) reflect any updates since the iterator was * created. * - *

          Memory Consistency Properties

          + *

          Memory Consistency Properties

          * * * Chapter 17 of the Java Language Specification defines the @@ -243,8 +243,7 @@ * in each thread happen-before those subsequent to the * corresponding {@code exchange()} in another thread. * - *
        • Actions prior to calling {@code CyclicBarrier.await} and - * {@code Phaser.awaitAdvance} (as well as its variants) + *
        • Actions prior to calling {@code CyclicBarrier.await} * happen-before actions performed by the barrier action, and * actions performed by the barrier action happen-before actions * subsequent to a successful return from the corresponding {@code await} -- cgit v1.1