changeset 13136:6a2c215751ae

8143087: Miscellaneous changes imported from jsr166 CVS 2015-11 Reviewed-by: martin, psandoz, chegar, shade, plevart
author dl
date Wed, 25 Nov 2015 19:45:15 -0800
parents 2103ed2d51f5
children ced6e999c11b
files src/java.base/share/classes/java/util/concurrent/CountedCompleter.java src/java.base/share/classes/java/util/concurrent/ScheduledThreadPoolExecutor.java src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedSynchronizer.java src/java.base/share/classes/java/util/concurrent/locks/LockSupport.java
diffstat 5 files changed, 67 insertions(+), 62 deletions(-) [+]
line wrap: on
line diff
--- a/src/java.base/share/classes/java/util/concurrent/CountedCompleter.java	Wed Nov 25 18:56:44 2015 -0800
+++ b/src/java.base/share/classes/java/util/concurrent/CountedCompleter.java	Wed Nov 25 19:45:15 2015 -0800
@@ -185,7 +185,7 @@
  *   }
  * }}</pre>
  *
- * As a further improvement, notice that the left task need not even exist.
+ * As a further optimization, 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(CountedCompleter)} method,
@@ -208,7 +208,7 @@
  *   }
  * }}</pre>
  *
- * Additional improvements of such classes might entail precomputing
+ * Additional optimizations 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
@@ -260,9 +260,9 @@
  * }}</pre>
  *
  * 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();})
+ * effects except to {@code 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.
  *
@@ -624,7 +624,7 @@
      * 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();}.
+     * more simply using {@link #quietlyCompleteRoot()}.
      *
      * @param rawResult the raw result
      */
@@ -639,9 +639,9 @@
 
     /**
      * 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.
+     * 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}
      */
--- a/src/java.base/share/classes/java/util/concurrent/ScheduledThreadPoolExecutor.java	Wed Nov 25 18:56:44 2015 -0800
+++ b/src/java.base/share/classes/java/util/concurrent/ScheduledThreadPoolExecutor.java	Wed Nov 25 19:45:15 2015 -0800
@@ -132,11 +132,10 @@
     /*
      * This class specializes ThreadPoolExecutor implementation by
      *
-     * 1. Using a custom task type, ScheduledFutureTask for
-     *    tasks, even those that don't require scheduling (i.e.,
-     *    those submitted using ExecutorService execute, not
-     *    ScheduledExecutorService methods) which are treated as
-     *    delayed tasks with a delay of zero.
+     * 1. Using a custom task type ScheduledFutureTask, even for tasks
+     *    that don't require scheduling because they are submitted
+     *    using ExecutorService rather than ScheduledExecutorService
+     *    methods, which are treated as tasks with a delay of zero.
      *
      * 2. Using a custom queue (DelayedWorkQueue), a variant of
      *    unbounded DelayQueue. The lack of capacity constraint and
@@ -177,24 +176,17 @@
      */
     private static final AtomicLong sequencer = new AtomicLong();
 
-    /**
-     * Returns current nanosecond time.
-     */
-    static final long now() {
-        return System.nanoTime();
-    }
-
     private class ScheduledFutureTask<V>
             extends FutureTask<V> implements RunnableScheduledFuture<V> {
 
         /** Sequence number to break ties FIFO */
         private final long sequenceNumber;
 
-        /** The time the task is enabled to execute in nanoTime units */
+        /** The nanoTime-based time when the task is enabled to execute. */
         private volatile long time;
 
         /**
-         * Period in nanoseconds for repeating tasks.
+         * Period for repeating tasks, in nanoseconds.
          * A positive value indicates fixed-rate execution.
          * A negative value indicates fixed-delay execution.
          * A value of 0 indicates a non-repeating (one-shot) task.
@@ -244,7 +236,7 @@
         }
 
         public long getDelay(TimeUnit unit) {
-            return unit.convert(time - now(), NANOSECONDS);
+            return unit.convert(time - System.nanoTime(), NANOSECONDS);
         }
 
         public int compareTo(Delayed other) {
@@ -287,6 +279,9 @@
         }
 
         public boolean cancel(boolean mayInterruptIfRunning) {
+            // The racy read of heapIndex below is benign:
+            // if heapIndex < 0, then OOTA guarantees that we have surely
+            // been removed; else we recheck under lock in remove()
             boolean cancelled = super.cancel(mayInterruptIfRunning);
             if (cancelled && removeOnCancel && heapIndex >= 0)
                 remove(this);
@@ -528,7 +523,7 @@
      * Returns the nanoTime-based trigger time of a delayed action.
      */
     long triggerTime(long delay) {
-        return now() +
+        return System.nanoTime() +
             ((delay < (Long.MAX_VALUE >> 1)) ? delay : overflowFree(delay));
     }
 
--- a/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java	Wed Nov 25 18:56:44 2015 -0800
+++ b/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java	Wed Nov 25 19:45:15 2015 -0800
@@ -922,7 +922,7 @@
 
     /**
      * Queries whether any threads have ever contended to acquire this
-     * synchronizer; that is if an acquire method has ever blocked.
+     * synchronizer; that is, if an acquire method has ever blocked.
      *
      * <p>In this implementation, this operation returns in
      * constant time.
@@ -977,13 +977,11 @@
          * guaranteeing termination.
          */
 
-        Node t = tail;
         Thread firstThread = null;
-        while (t != null && t != head) {
-            Thread tt = t.thread;
-            if (tt != null)
-                firstThread = tt;
-            t = t.prev;
+        for (Node p = tail; p != null && p != head; p = p.prev) {
+            Thread t = p.thread;
+            if (t != null)
+                firstThread = t;
         }
         return firstThread;
     }
@@ -1031,8 +1029,8 @@
      * <p>An invocation of this method is equivalent to (but may be
      * more efficient than):
      * <pre> {@code
-     * getFirstQueuedThread() != Thread.currentThread() &&
-     * hasQueuedThreads()}</pre>
+     * getFirstQueuedThread() != Thread.currentThread()
+     *   && hasQueuedThreads()}</pre>
      *
      * <p>Note that because cancellations due to interrupts and
      * timeouts may occur at any time, a {@code true} return does not
@@ -1635,7 +1633,7 @@
                     transferAfterCancelledWait(node);
                     break;
                 }
-                if (nanosTimeout >= SPIN_FOR_TIMEOUT_THRESHOLD)
+                if (nanosTimeout > SPIN_FOR_TIMEOUT_THRESHOLD)
                     LockSupport.parkNanos(this, nanosTimeout);
                 if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
                     break;
@@ -1723,7 +1721,7 @@
                     timedout = transferAfterCancelledWait(node);
                     break;
                 }
-                if (nanosTimeout >= SPIN_FOR_TIMEOUT_THRESHOLD)
+                if (nanosTimeout > SPIN_FOR_TIMEOUT_THRESHOLD)
                     LockSupport.parkNanos(this, nanosTimeout);
                 if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
                     break;
@@ -1847,8 +1845,9 @@
      * Initializes head and tail fields on first contention.
      */
     private final void initializeSyncQueue() {
-        if (U.compareAndSwapObject(this, HEAD, null, new Node()))
-            tail = head;
+        Node h;
+        if (U.compareAndSwapObject(this, HEAD, null, (h = new Node())))
+            tail = h;
     }
 
     /**
--- a/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedSynchronizer.java	Wed Nov 25 18:56:44 2015 -0800
+++ b/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedSynchronizer.java	Wed Nov 25 19:45:15 2015 -0800
@@ -1388,7 +1388,7 @@
 
     /**
      * Queries whether any threads have ever contended to acquire this
-     * synchronizer; that is if an acquire method has ever blocked.
+     * synchronizer; that is, if an acquire method has ever blocked.
      *
      * <p>In this implementation, this operation returns in
      * constant time.
@@ -1443,13 +1443,11 @@
          * guaranteeing termination.
          */
 
-        Node t = tail;
         Thread firstThread = null;
-        while (t != null && t != head) {
-            Thread tt = t.thread;
-            if (tt != null)
-                firstThread = tt;
-            t = t.prev;
+        for (Node p = tail; p != null && p != head; p = p.prev) {
+            Thread t = p.thread;
+            if (t != null)
+                firstThread = t;
         }
         return firstThread;
     }
@@ -1497,8 +1495,8 @@
      * <p>An invocation of this method is equivalent to (but may be
      * more efficient than):
      * <pre> {@code
-     * getFirstQueuedThread() != Thread.currentThread() &&
-     * hasQueuedThreads()}</pre>
+     * getFirstQueuedThread() != Thread.currentThread()
+     *   && hasQueuedThreads()}</pre>
      *
      * <p>Note that because cancellations due to interrupts and
      * timeouts may occur at any time, a {@code true} return does not
@@ -2099,7 +2097,7 @@
                     transferAfterCancelledWait(node);
                     break;
                 }
-                if (nanosTimeout >= SPIN_FOR_TIMEOUT_THRESHOLD)
+                if (nanosTimeout > SPIN_FOR_TIMEOUT_THRESHOLD)
                     LockSupport.parkNanos(this, nanosTimeout);
                 if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
                     break;
@@ -2187,7 +2185,7 @@
                     timedout = transferAfterCancelledWait(node);
                     break;
                 }
-                if (nanosTimeout >= SPIN_FOR_TIMEOUT_THRESHOLD)
+                if (nanosTimeout > SPIN_FOR_TIMEOUT_THRESHOLD)
                     LockSupport.parkNanos(this, nanosTimeout);
                 if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
                     break;
@@ -2311,8 +2309,9 @@
      * Initializes head and tail fields on first contention.
      */
     private final void initializeSyncQueue() {
-        if (U.compareAndSwapObject(this, HEAD, null, new Node()))
-            tail = head;
+        Node h;
+        if (U.compareAndSwapObject(this, HEAD, null, (h = new Node())))
+            tail = h;
     }
 
     /**
--- a/src/java.base/share/classes/java/util/concurrent/locks/LockSupport.java	Wed Nov 25 18:56:44 2015 -0800
+++ b/src/java.base/share/classes/java/util/concurrent/locks/LockSupport.java	Wed Nov 25 19:45:15 2015 -0800
@@ -81,12 +81,17 @@
  * method is designed for use only in constructions of the form:
  *
  * <pre> {@code
- * while (!canProceed()) { ... LockSupport.park(this); }}</pre>
+ * while (!canProceed()) {
+ *   // ensure request to unpark is visible to other threads
+ *   ...
+ *   LockSupport.park(this);
+ * }}</pre>
  *
- * where neither {@code canProceed} nor any other actions prior to the
- * call to {@code park} entail locking or blocking.  Because only one
- * permit is associated with each thread, any intermediary uses of
- * {@code park} could interfere with its intended effects.
+ * where no actions by the thread publishing a request to unpark,
+ * prior to the call to {@code park}, entail locking or blocking.
+ * Because only one permit is associated with each thread, any
+ * intermediary uses of {@code park}, including implicitly via class
+ * loading, could lead to an unresponsive thread (a "lost unpark").
  *
  * <p><b>Sample Usage.</b> Here is a sketch of a first-in-first-out
  * non-reentrant lock class:
@@ -98,26 +103,33 @@
  *
  *   public void lock() {
  *     boolean wasInterrupted = false;
- *     Thread current = Thread.currentThread();
- *     waiters.add(current);
+ *     // publish current thread for unparkers
+ *     waiters.add(Thread.currentThread());
  *
  *     // Block while not first in queue or cannot acquire lock
- *     while (waiters.peek() != current ||
+ *     while (waiters.peek() != Thread.currentThread() ||
  *            !locked.compareAndSet(false, true)) {
  *       LockSupport.park(this);
- *       if (Thread.interrupted()) // ignore interrupts while waiting
+ *       // ignore interrupts while waiting
+ *       if (Thread.interrupted())
  *         wasInterrupted = true;
  *     }
  *
  *     waiters.remove();
- *     if (wasInterrupted)          // reassert interrupt status on exit
- *       current.interrupt();
+ *     // ensure correct interrupt status on return
+ *     if (wasInterrupted)
+ *       Thread.currentThread().interrupt();
  *   }
  *
  *   public void unlock() {
  *     locked.set(false);
  *     LockSupport.unpark(waiters.peek());
  *   }
+ *
+ *   static {
+ *     // Reduce the risk of "lost unpark" due to classloading
+ *     Class<?> ensureLoaded = LockSupport.class;
+ *   }
  * }}</pre>
  */
 public class LockSupport {