From 1e1ba844616c376ad16cbacb07d8cb530aa87137 Mon Sep 17 00:00:00 2001 From: Doug Lea Date: Tue, 16 Feb 2016 09:49:14 -0800 Subject: [PATCH 1/2] 8139927: Improve documentation for CompletableFuture composition 8143089: CompletableFuture.whenComplete should use addSuppressed Reviewed-by: martin, psandoz, chegar, plevart --- .../util/concurrent/CompletableFuture.java | 17 +- .../java/util/concurrent/CompletionStage.java | 384 +++++++++++------- .../concurrent/tck/CompletableFutureTest.java | 9 +- 3 files changed, 249 insertions(+), 161 deletions(-) diff --git a/jdk/src/java.base/share/classes/java/util/concurrent/CompletableFuture.java b/jdk/src/java.base/share/classes/java/util/concurrent/CompletableFuture.java index dd24b82f2cc..b3fb80dcd37 100644 --- a/jdk/src/java.base/share/classes/java/util/concurrent/CompletableFuture.java +++ b/jdk/src/java.base/share/classes/java/util/concurrent/CompletableFuture.java @@ -234,14 +234,13 @@ public class CompletableFuture implements Future, CompletionStage { * Without precautions, CompletableFutures would be prone to * garbage accumulation as chains of Completions build up, each * pointing back to its sources. So we null out fields as soon as - * possible (see especially method Completion.detach). The - * screening checks needed anyway harmlessly ignore null arguments - * that may have been obtained during races with threads nulling - * out fields. We also try to unlink fired Completions from - * stacks that might never be popped (see method postFire). - * Completion fields need not be declared as final or volatile - * because they are only visible to other threads upon safe - * publication. + * possible. The screening checks needed anyway harmlessly ignore + * null arguments that may have been obtained during races with + * threads nulling out fields. We also try to unlink fired + * Completions from stacks that might never be popped (see method + * postFire). Completion fields need not be declared as final or + * volatile because they are only visible to other threads upon + * safe publication. */ volatile Object result; // Either the result or boxed AltResult @@ -800,6 +799,8 @@ public class CompletableFuture implements Future, CompletionStage { } catch (Throwable ex) { if (x == null) x = ex; + else if (x != ex) + x.addSuppressed(ex); } completeThrowable(x, r); } diff --git a/jdk/src/java.base/share/classes/java/util/concurrent/CompletionStage.java b/jdk/src/java.base/share/classes/java/util/concurrent/CompletionStage.java index 1d9d6f3141a..d855945b829 100644 --- a/jdk/src/java.base/share/classes/java/util/concurrent/CompletionStage.java +++ b/jdk/src/java.base/share/classes/java/util/concurrent/CompletionStage.java @@ -46,16 +46,25 @@ import java.util.function.Function; * A stage completes upon termination of its computation, but this may * in turn trigger other dependent stages. The functionality defined * in this interface takes only a few basic forms, which expand out to - * a larger set of methods to capture a range of usage styles:
    + * a larger set of methods to capture a range of usage styles: + * + *
      * *
    • The computation performed by a stage may be expressed as a * Function, Consumer, or Runnable (using methods with names including * apply, accept, or run, respectively) * depending on whether it requires arguments and/or produces results. - * For example, {@code stage.thenApply(x -> square(x)).thenAccept(x -> - * System.out.print(x)).thenRun(() -> System.out.println())}. An - * additional form (compose) applies functions of stages - * themselves, rather than their results. + * For example: + *
       {@code
      + * stage.thenApply(x -> square(x))
      + *      .thenAccept(x -> System.out.print(x))
      + *      .thenRun(() -> System.out.println());}
      + * + * An additional form (compose) allows the construction of + * computation pipelines from functions returning completion stages. + * + *

      Any argument to a stage's computation is the outcome of a + * triggering stage's computation. * *

    • One stage's execution may be triggered by completion of a * single stage, or both of two stages, or either of two stages. @@ -64,8 +73,7 @@ import java.util.function.Function; * both of two stages may combine their results or * effects, using correspondingly named methods. Those triggered by * either of two stages make no guarantees about which of the - * results or effects are used for the dependent stage's - * computation. + * results or effects are used for the dependent stage's computation. * *
    • Dependencies among stages control the triggering of * computations, but do not otherwise guarantee any particular @@ -80,26 +88,27 @@ import java.util.function.Function; * properties, and might not even support concurrent execution, but * are arranged for processing in a way that accommodates asynchrony. * - *
    • Two method forms support processing whether the triggering - * stage completed normally or exceptionally: Method {@link - * #whenComplete whenComplete} allows injection of an action - * regardless of outcome, otherwise preserving the outcome in its - * completion. Method {@link #handle handle} additionally allows the - * stage to compute a replacement result that may enable further - * processing by other dependent stages. In all other cases, if a - * stage's computation terminates abruptly with an (unchecked) - * exception or error, then all dependent stages requiring its - * completion complete exceptionally as well, with a {@link - * CompletionException} holding the exception as its cause. If a - * stage is dependent on both of two stages, and both + *
    • Two method forms ({@link #handle handle} and {@link + * #whenComplete whenComplete}) support unconditional computation + * whether the triggering stage completed normally or exceptionally. + * Method {@link #exceptionally exceptionally} supports computation + * only when the triggering stage completes exceptionally, computing a + * replacement result, similarly to the java {@code catch} keyword. + * In all other cases, if a stage's computation terminates abruptly + * with an (unchecked) exception or error, then all dependent stages + * requiring its completion complete exceptionally as well, with a + * {@link CompletionException} holding the exception as its cause. If + * a stage is dependent on both of two stages, and both * complete exceptionally, then the CompletionException may correspond * to either one of these exceptions. If a stage is dependent on * either of two others, and only one of them completes * exceptionally, no guarantees are made about whether the dependent * stage completes normally or exceptionally. In the case of method * {@code whenComplete}, when the supplied action itself encounters an - * exception, then the stage exceptionally completes with this - * exception if not already completed exceptionally. + * exception, then the stage completes exceptionally with this + * exception unless the source stage also completed exceptionally, in + * which case the exceptional completion from the source stage is + * given preference and propagated to the dependent stage. * *
    * @@ -111,6 +120,23 @@ import java.util.function.Function; * value for any other parameter will result in a {@link * NullPointerException} being thrown. * + *

    Method form {@link #handle handle} is the most general way of + * creating a continuation stage, unconditionally performing a + * computation that is given both the result and exception (if any) of + * the triggering CompletionStage, and computing an arbitrary result. + * Method {@link #whenComplete whenComplete} is similar, but preserves + * the result of the triggering stage instead of computing a new one. + * Because a stage's normal result may be {@code null}, both methods + * should have a computation structured thus: + * + *

    {@code (result, exception) -> {
    + *   if (exception == null) {
    + *     // triggering stage completed normally
    + *   } else {
    + *     // triggering stage completed exceptionally
    + *   }
    + * }}
    + * *

    This interface does not define methods for initially creating, * forcibly completing normally or exceptionally, probing completion * status or results, or awaiting completion of a stage. @@ -129,11 +155,15 @@ public interface CompletionStage { * normally, is executed with this stage's result as the argument * to the supplied function. * - * See the {@link CompletionStage} documentation for rules + *

    This method is analogous to + * {@link java.util.Optional#map Optional.map} and + * {@link java.util.stream.Stream#map Stream.map}. + * + *

    See the {@link CompletionStage} documentation for rules * covering exceptional completion. * - * @param fn the function to use to compute the value of - * the returned CompletionStage + * @param fn the function to use to compute the value of the + * returned CompletionStage * @param the function's return type * @return the new CompletionStage */ @@ -148,8 +178,8 @@ public interface CompletionStage { * See the {@link CompletionStage} documentation for rules * covering exceptional completion. * - * @param fn the function to use to compute the value of - * the returned CompletionStage + * @param fn the function to use to compute the value of the + * returned CompletionStage * @param the function's return type * @return the new CompletionStage */ @@ -164,8 +194,8 @@ public interface CompletionStage { * See the {@link CompletionStage} documentation for rules * covering exceptional completion. * - * @param fn the function to use to compute the value of - * the returned CompletionStage + * @param fn the function to use to compute the value of the + * returned CompletionStage * @param executor the executor to use for asynchronous execution * @param the function's return type * @return the new CompletionStage @@ -269,8 +299,8 @@ public interface CompletionStage { * covering exceptional completion. * * @param other the other CompletionStage - * @param fn the function to use to compute the value of - * the returned CompletionStage + * @param fn the function to use to compute the value of the + * returned CompletionStage * @param the type of the other CompletionStage's result * @param the function's return type * @return the new CompletionStage @@ -281,16 +311,16 @@ public interface CompletionStage { /** * Returns a new CompletionStage that, when this and the other - * given stage complete normally, is executed using this stage's - * default asynchronous execution facility, with the two results - * as arguments to the supplied function. + * given stage both complete normally, is executed using this + * stage's default asynchronous execution facility, with the two + * results as arguments to the supplied function. * * See the {@link CompletionStage} documentation for rules * covering exceptional completion. * * @param other the other CompletionStage - * @param fn the function to use to compute the value of - * the returned CompletionStage + * @param fn the function to use to compute the value of the + * returned CompletionStage * @param the type of the other CompletionStage's result * @param the function's return type * @return the new CompletionStage @@ -301,16 +331,16 @@ public interface CompletionStage { /** * Returns a new CompletionStage that, when this and the other - * given stage complete normally, is executed using the supplied - * executor, with the two results as arguments to the supplied - * function. + * given stage both complete normally, is executed using the + * supplied executor, with the two results as arguments to the + * supplied function. * * See the {@link CompletionStage} documentation for rules * covering exceptional completion. * * @param other the other CompletionStage - * @param fn the function to use to compute the value of - * the returned CompletionStage + * @param fn the function to use to compute the value of the + * returned CompletionStage * @param executor the executor to use for asynchronous execution * @param the type of the other CompletionStage's result * @param the function's return type @@ -341,9 +371,12 @@ public interface CompletionStage { /** * Returns a new CompletionStage that, when this and the other - * given stage complete normally, is executed using this stage's - * default asynchronous execution facility, with the two results - * as arguments to the supplied action. + * given stage both complete normally, is executed using this + * stage's default asynchronous execution facility, with the two + * results as arguments to the supplied action. + * + * See the {@link CompletionStage} documentation for rules + * covering exceptional completion. * * @param other the other CompletionStage * @param action the action to perform before completing the @@ -357,9 +390,12 @@ public interface CompletionStage { /** * Returns a new CompletionStage that, when this and the other - * given stage complete normally, is executed using the supplied - * executor, with the two results as arguments to the supplied - * function. + * given stage both complete normally, is executed using the + * supplied executor, with the two results as arguments to the + * supplied action. + * + * See the {@link CompletionStage} documentation for rules + * covering exceptional completion. * * @param other the other CompletionStage * @param action the action to perform before completing the @@ -389,8 +425,8 @@ public interface CompletionStage { Runnable action); /** * Returns a new CompletionStage that, when this and the other - * given stage complete normally, executes the given action using - * this stage's default asynchronous execution facility. + * given stage both complete normally, executes the given action + * using this stage's default asynchronous execution facility. * * See the {@link CompletionStage} documentation for rules * covering exceptional completion. @@ -405,8 +441,8 @@ public interface CompletionStage { /** * Returns a new CompletionStage that, when this and the other - * given stage complete normally, executes the given action using - * the supplied executor. + * given stage both complete normally, executes the given action + * using the supplied executor. * * See the {@link CompletionStage} documentation for rules * covering exceptional completion. @@ -429,8 +465,8 @@ public interface CompletionStage { * covering exceptional completion. * * @param other the other CompletionStage - * @param fn the function to use to compute the value of - * the returned CompletionStage + * @param fn the function to use to compute the value of the + * returned CompletionStage * @param the function's return type * @return the new CompletionStage */ @@ -448,8 +484,8 @@ public interface CompletionStage { * covering exceptional completion. * * @param other the other CompletionStage - * @param fn the function to use to compute the value of - * the returned CompletionStage + * @param fn the function to use to compute the value of the + * returned CompletionStage * @param the function's return type * @return the new CompletionStage */ @@ -467,8 +503,8 @@ public interface CompletionStage { * covering exceptional completion. * * @param other the other CompletionStage - * @param fn the function to use to compute the value of - * the returned CompletionStage + * @param fn the function to use to compute the value of the + * returned CompletionStage * @param executor the executor to use for asynchronous execution * @param the function's return type * @return the new CompletionStage @@ -517,7 +553,7 @@ public interface CompletionStage { * Returns a new CompletionStage that, when either this or the * other given stage complete normally, is executed using the * supplied executor, with the corresponding result as argument to - * the supplied function. + * the supplied action. * * See the {@link CompletionStage} documentation for rules * covering exceptional completion. @@ -585,125 +621,83 @@ public interface CompletionStage { Executor executor); /** - * Returns a new CompletionStage that, when this stage completes - * normally, is executed with this stage's result as the argument - * to the supplied function. + * Returns a new CompletionStage that is completed with the same + * value as the CompletionStage returned by the given function. * - * See the {@link CompletionStage} documentation for rules + *

    When this stage completes normally, the given function is + * invoked with this stage's result as the argument, returning + * another CompletionStage. When that stage completes normally, + * the CompletionStage returned by this method is completed with + * the same value. + * + *

    To ensure progress, the supplied function must arrange + * eventual completion of its result. + * + *

    This method is analogous to + * {@link java.util.Optional#flatMap Optional.flatMap} and + * {@link java.util.stream.Stream#flatMap Stream.flatMap}. + * + *

    See the {@link CompletionStage} documentation for rules * covering exceptional completion. * - * @param fn the function returning a new CompletionStage + * @param fn the function to use to compute another CompletionStage * @param the type of the returned CompletionStage's result - * @return the CompletionStage + * @return the new CompletionStage */ public CompletionStage thenCompose (Function> fn); /** - * Returns a new CompletionStage that, when this stage completes - * normally, is executed using this stage's default asynchronous - * execution facility, with this stage's result as the argument to the - * supplied function. + * Returns a new CompletionStage that is completed with the same + * value as the CompletionStage returned by the given function, + * executed using this stage's default asynchronous execution + * facility. * - * See the {@link CompletionStage} documentation for rules + *

    When this stage completes normally, the given function is + * invoked with this stage's result as the argument, returning + * another CompletionStage. When that stage completes normally, + * the CompletionStage returned by this method is completed with + * the same value. + * + *

    To ensure progress, the supplied function must arrange + * eventual completion of its result. + * + *

    See the {@link CompletionStage} documentation for rules * covering exceptional completion. * - * @param fn the function returning a new CompletionStage + * @param fn the function to use to compute another CompletionStage * @param the type of the returned CompletionStage's result - * @return the CompletionStage + * @return the new CompletionStage */ public CompletionStage thenComposeAsync (Function> fn); /** - * Returns a new CompletionStage that, when this stage completes - * normally, is executed using the supplied Executor, with this - * stage's result as the argument to the supplied function. + * Returns a new CompletionStage that is completed with the same + * value as the CompletionStage returned by the given function, + * executed using the supplied Executor. * - * See the {@link CompletionStage} documentation for rules + *

    When this stage completes normally, the given function is + * invoked with this stage's result as the argument, returning + * another CompletionStage. When that stage completes normally, + * the CompletionStage returned by this method is completed with + * the same value. + * + *

    To ensure progress, the supplied function must arrange + * eventual completion of its result. + * + *

    See the {@link CompletionStage} documentation for rules * covering exceptional completion. * - * @param fn the function returning a new CompletionStage + * @param fn the function to use to compute another CompletionStage * @param executor the executor to use for asynchronous execution * @param the type of the returned CompletionStage's result - * @return the CompletionStage + * @return the new CompletionStage */ public CompletionStage thenComposeAsync (Function> fn, Executor executor); - /** - * Returns a new CompletionStage that, when this stage completes - * exceptionally, is executed with this stage's exception as the - * argument to the supplied function. Otherwise, if this stage - * completes normally, then the returned stage also completes - * normally with the same value. - * - * @param fn the function to use to compute the value of the - * returned CompletionStage if this CompletionStage completed - * exceptionally - * @return the new CompletionStage - */ - public CompletionStage exceptionally - (Function fn); - - /** - * Returns a new CompletionStage with the same result or exception as - * this stage, that executes the given action when this stage completes. - * - *

    When this stage is complete, the given action is invoked - * with the result (or {@code null} if none) and the exception (or - * {@code null} if none) of this stage as arguments. The returned - * stage is completed when the action returns. If the supplied - * action itself encounters an exception, then the returned stage - * exceptionally completes with this exception unless this stage - * also completed exceptionally (in which case, the returned stage - * exceptionally completes with the original exception). - * - * @param action the action to perform - * @return the new CompletionStage - */ - public CompletionStage whenComplete - (BiConsumer action); - - /** - * Returns a new CompletionStage with the same result or exception as - * this stage, that executes the given action using this stage's - * default asynchronous execution facility when this stage completes. - * - *

    When this stage is complete, the given action is invoked with the - * result (or {@code null} if none) and the exception (or {@code null} - * if none) of this stage as arguments. The returned stage is completed - * when the action returns. If the supplied action itself encounters an - * exception, then the returned stage exceptionally completes with this - * exception unless this stage also completed exceptionally. - * - * @param action the action to perform - * @return the new CompletionStage - */ - public CompletionStage whenCompleteAsync - (BiConsumer action); - - /** - * Returns a new CompletionStage with the same result or exception as - * this stage, that executes the given action using the supplied - * Executor when this stage completes. - * - *

    When this stage is complete, the given action is invoked with the - * result (or {@code null} if none) and the exception (or {@code null} - * if none) of this stage as arguments. The returned stage is completed - * when the action returns. If the supplied action itself encounters an - * exception, then the returned stage exceptionally completes with this - * exception unless this stage also completed exceptionally. - * - * @param action the action to perform - * @param executor the executor to use for asynchronous execution - * @return the new CompletionStage - */ - public CompletionStage whenCompleteAsync - (BiConsumer action, - Executor executor); - /** * Returns a new CompletionStage that, when this stage completes * either normally or exceptionally, is executed with this stage's @@ -762,6 +756,100 @@ public interface CompletionStage { (BiFunction fn, Executor executor); + /** + * Returns a new CompletionStage with the same result or exception as + * this stage, that executes the given action when this stage completes. + * + *

    When this stage is complete, the given action is invoked + * with the result (or {@code null} if none) and the exception (or + * {@code null} if none) of this stage as arguments. The returned + * stage is completed when the action returns. + * + *

    Unlike method {@link #handle handle}, + * this method is not designed to translate completion outcomes, + * so the supplied action should not throw an exception. However, + * if it does, the following rules apply: if this stage completed + * normally but the supplied action throws an exception, then the + * returned stage completes exceptionally with the supplied + * action's exception. Or, if this stage completed exceptionally + * and the supplied action throws an exception, then the returned + * stage completes exceptionally with this stage's exception. + * + * @param action the action to perform + * @return the new CompletionStage + */ + public CompletionStage whenComplete + (BiConsumer action); + + /** + * Returns a new CompletionStage with the same result or exception as + * this stage, that executes the given action using this stage's + * default asynchronous execution facility when this stage completes. + * + *

    When this stage is complete, the given action is invoked with the + * result (or {@code null} if none) and the exception (or {@code null} + * if none) of this stage as arguments. The returned stage is completed + * when the action returns. + * + *

    Unlike method {@link #handleAsync(BiFunction) handleAsync}, + * this method is not designed to translate completion outcomes, + * so the supplied action should not throw an exception. However, + * if it does, the following rules apply: If this stage completed + * normally but the supplied action throws an exception, then the + * returned stage completes exceptionally with the supplied + * action's exception. Or, if this stage completed exceptionally + * and the supplied action throws an exception, then the returned + * stage completes exceptionally with this stage's exception. + * + * @param action the action to perform + * @return the new CompletionStage + */ + public CompletionStage whenCompleteAsync + (BiConsumer action); + + /** + * Returns a new CompletionStage with the same result or exception as + * this stage, that executes the given action using the supplied + * Executor when this stage completes. + * + *

    When this stage is complete, the given action is invoked with the + * result (or {@code null} if none) and the exception (or {@code null} + * if none) of this stage as arguments. The returned stage is completed + * when the action returns. + * + *

    Unlike method {@link #handleAsync(BiFunction,Executor) handleAsync}, + * this method is not designed to translate completion outcomes, + * so the supplied action should not throw an exception. However, + * if it does, the following rules apply: If this stage completed + * normally but the supplied action throws an exception, then the + * returned stage completes exceptionally with the supplied + * action's exception. Or, if this stage completed exceptionally + * and the supplied action throws an exception, then the returned + * stage completes exceptionally with this stage's exception. + * + * @param action the action to perform + * @param executor the executor to use for asynchronous execution + * @return the new CompletionStage + */ + public CompletionStage whenCompleteAsync + (BiConsumer action, + Executor executor); + + /** + * Returns a new CompletionStage that, when this stage completes + * exceptionally, is executed with this stage's exception as the + * argument to the supplied function. Otherwise, if this stage + * completes normally, then the returned stage also completes + * normally with the same value. + * + * @param fn the function to use to compute the value of the + * returned CompletionStage if this CompletionStage completed + * exceptionally + * @return the new CompletionStage + */ + public CompletionStage exceptionally + (Function fn); + /** * Returns a {@link CompletableFuture} maintaining the same * completion properties as this stage. If this stage is already a diff --git a/jdk/test/java/util/concurrent/tck/CompletableFutureTest.java b/jdk/test/java/util/concurrent/tck/CompletableFutureTest.java index a74a0403f2f..f814ef5d732 100644 --- a/jdk/test/java/util/concurrent/tck/CompletableFutureTest.java +++ b/jdk/test/java/util/concurrent/tck/CompletableFutureTest.java @@ -1067,11 +1067,10 @@ public class CompletableFutureTest extends JSR166TestCase { checkCompletedWithWrappedException(g, ex1); checkCompletedExceptionally(f, ex1); - // oops... temporarily disabled -// if (testImplementationDetails) { -// assertEquals(1, ex1.getSuppressed().length); -// assertSame(ex2, ex1.getSuppressed()[0]); -// } + if (testImplementationDetails) { + assertEquals(1, ex1.getSuppressed().length); + assertSame(ex2, ex1.getSuppressed()[0]); + } assertEquals(1, a.get()); }} From eb6ab98ebcbf837b1ed052b46b1c022a3d79e34e Mon Sep 17 00:00:00 2001 From: Doug Lea Date: Tue, 16 Feb 2016 09:52:49 -0800 Subject: [PATCH 2/2] 8145485: Miscellaneous changes imported from jsr166 CVS 2016-02 Reviewed-by: martin, psandoz, chegar --- .../classes/java/util/SplittableRandom.java | 11 +++-- .../java/util/concurrent/Exchanger.java | 7 ++-- .../java/util/concurrent/ForkJoinPool.java | 5 ++- .../java/util/concurrent/ForkJoinTask.java | 40 ++++++++----------- .../util/concurrent/ThreadLocalRandom.java | 11 +++-- .../util/concurrent/atomic/Striped64.java | 14 +++---- .../ConcurrentQueues/RemovePollRace.java | 12 ++++-- .../ExecutorCompletionServiceLoops.java | 4 +- 8 files changed, 50 insertions(+), 54 deletions(-) diff --git a/jdk/src/java.base/share/classes/java/util/SplittableRandom.java b/jdk/src/java.base/share/classes/java/util/SplittableRandom.java index 2e08a4ddb87..cf71c91e8da 100644 --- a/jdk/src/java.base/share/classes/java/util/SplittableRandom.java +++ b/jdk/src/java.base/share/classes/java/util/SplittableRandom.java @@ -225,14 +225,13 @@ public final class SplittableRandom { private static final AtomicLong defaultGen = new AtomicLong(initialSeed()); private static long initialSeed() { - String pp = java.security.AccessController.doPrivileged( - new sun.security.action.GetPropertyAction( - "java.util.secureRandomSeed")); - if (pp != null && pp.equalsIgnoreCase("true")) { + java.security.PrivilegedAction action = + () -> Boolean.getBoolean("java.util.secureRandomSeed"); + if (java.security.AccessController.doPrivileged(action)) { byte[] seedBytes = java.security.SecureRandom.getSeed(8); - long s = (long)(seedBytes[0]) & 0xffL; + long s = (long)seedBytes[0] & 0xffL; for (int i = 1; i < 8; ++i) - s = (s << 8) | ((long)(seedBytes[i]) & 0xffL); + s = (s << 8) | ((long)seedBytes[i] & 0xffL); return s; } return (mix64(System.currentTimeMillis()) ^ diff --git a/jdk/src/java.base/share/classes/java/util/concurrent/Exchanger.java b/jdk/src/java.base/share/classes/java/util/concurrent/Exchanger.java index b8260d7102b..3f5ce5e371d 100644 --- a/jdk/src/java.base/share/classes/java/util/concurrent/Exchanger.java +++ b/jdk/src/java.base/share/classes/java/util/concurrent/Exchanger.java @@ -155,8 +155,8 @@ public class Exchanger { * 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 (via - * jdk.internal.vm.annotation.Contended) to Nodes, embedding "bound" as an Exchanger - * field, and reworking some park/unpark mechanics compared to + * @Contended) to Nodes, embedding "bound" as an Exchanger field, + * and reworking some park/unpark mechanics compared to * LockSupport versions. * * The arena starts out with only one used slot. We expand the @@ -304,8 +304,7 @@ public class Exchanger { /** * Nodes hold partially exchanged data, plus other per-thread - * bookkeeping. Padded via @jdk.internal.vm.annotation.Contended to reduce memory - * contention. + * bookkeeping. Padded via @Contended to reduce memory contention. */ @jdk.internal.vm.annotation.Contended static final class Node { int index; // Arena index diff --git a/jdk/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java b/jdk/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java index 3dac70a4310..3a7c0ab4eb8 100644 --- a/jdk/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java +++ b/jdk/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java @@ -818,8 +818,9 @@ public class ForkJoinPool extends AbstractExecutorService { 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 - @jdk.internal.vm.annotation.Contended("group2") // separate from other fields + volatile ForkJoinTask currentJoin; // task being joined in awaitJoin + + @jdk.internal.vm.annotation.Contended("group2") // segregate volatile ForkJoinTask currentSteal; // nonnull when running some task WorkQueue(ForkJoinPool pool, ForkJoinWorkerThread owner) { diff --git a/jdk/src/java.base/share/classes/java/util/concurrent/ForkJoinTask.java b/jdk/src/java.base/share/classes/java/util/concurrent/ForkJoinTask.java index 888794e8e40..fa14cbf984a 100644 --- a/jdk/src/java.base/share/classes/java/util/concurrent/ForkJoinTask.java +++ b/jdk/src/java.base/share/classes/java/util/concurrent/ForkJoinTask.java @@ -541,16 +541,16 @@ public abstract class ForkJoinTask implements Future, Serializable { } /** - * Returns a rethrowable exception for the given task, if - * available. To provide accurate stack traces, if the exception - * was not thrown by the current thread, we try to create a new - * exception of the same type as the one thrown, but with the - * recorded exception as its cause. If there is no such - * constructor, we instead try to use a no-arg constructor, - * followed by initCause, to the same effect. If none of these - * apply, or any fail due to other exceptions, we return the - * recorded exception, which is still correct, although it may - * contain a misleading stack trace. + * Returns a rethrowable exception for this task, if available. + * To provide accurate stack traces, if the exception was not + * thrown by the current thread, we try to create a new exception + * of the same type as the one thrown, but with the recorded + * exception as its cause. If there is no such constructor, we + * instead try to use a no-arg constructor, followed by initCause, + * to the same effect. If none of these apply, or any fail due to + * other exceptions, we return the recorded exception, which is + * still correct, although it may contain a misleading stack + * trace. * * @return the exception, or null if none */ @@ -572,26 +572,20 @@ public abstract class ForkJoinTask implements Future, Serializable { if (e == null || (ex = e.ex) == null) return null; if (e.thrower != Thread.currentThread().getId()) { - Class ec = ex.getClass(); try { Constructor noArgCtor = null; - Constructor[] cs = ec.getConstructors();// public ctors only - for (int i = 0; i < cs.length; ++i) { - Constructor c = cs[i]; + // public ctors only + for (Constructor c : ex.getClass().getConstructors()) { Class[] ps = c.getParameterTypes(); if (ps.length == 0) noArgCtor = c; - else if (ps.length == 1 && ps[0] == Throwable.class) { - Throwable wx = (Throwable)c.newInstance(ex); - return (wx == null) ? ex : wx; - } + else if (ps.length == 1 && ps[0] == Throwable.class) + return (Throwable)c.newInstance(ex); } if (noArgCtor != null) { - Throwable wx = (Throwable)(noArgCtor.newInstance()); - if (wx != null) { - wx.initCause(ex); - return wx; - } + Throwable wx = (Throwable)noArgCtor.newInstance(); + wx.initCause(ex); + return wx; } } catch (Exception ignore) { } diff --git a/jdk/src/java.base/share/classes/java/util/concurrent/ThreadLocalRandom.java b/jdk/src/java.base/share/classes/java/util/concurrent/ThreadLocalRandom.java index f4bf5a4fef2..90fb6cf054f 100644 --- a/jdk/src/java.base/share/classes/java/util/concurrent/ThreadLocalRandom.java +++ b/jdk/src/java.base/share/classes/java/util/concurrent/ThreadLocalRandom.java @@ -134,14 +134,13 @@ public class ThreadLocalRandom extends Random { private static final AtomicLong seeder = new AtomicLong(initialSeed()); private static long initialSeed() { - String pp = java.security.AccessController.doPrivileged( - new sun.security.action.GetPropertyAction( - "java.util.secureRandomSeed")); - if (pp != null && pp.equalsIgnoreCase("true")) { + java.security.PrivilegedAction action = + () -> Boolean.getBoolean("java.util.secureRandomSeed"); + if (java.security.AccessController.doPrivileged(action)) { byte[] seedBytes = java.security.SecureRandom.getSeed(8); - long s = (long)(seedBytes[0]) & 0xffL; + long s = (long)seedBytes[0] & 0xffL; for (int i = 1; i < 8; ++i) - s = (s << 8) | ((long)(seedBytes[i]) & 0xffL); + s = (s << 8) | ((long)seedBytes[i] & 0xffL); return s; } return (mix64(System.currentTimeMillis()) ^ diff --git a/jdk/src/java.base/share/classes/java/util/concurrent/atomic/Striped64.java b/jdk/src/java.base/share/classes/java/util/concurrent/atomic/Striped64.java index dad7db6bd77..77ee89a614b 100644 --- a/jdk/src/java.base/share/classes/java/util/concurrent/atomic/Striped64.java +++ b/jdk/src/java.base/share/classes/java/util/concurrent/atomic/Striped64.java @@ -55,13 +55,13 @@ abstract class Striped64 extends Number { * accessed directly by subclasses. * * Table entries are of class Cell; a variant of AtomicLong padded - * (via @jdk.internal.vm.annotation.Contended) to reduce cache contention. Padding - * is overkill for most Atomics because they are usually - * irregularly scattered in memory and thus don't interfere much - * with each other. But Atomic objects residing in arrays will - * tend to be placed adjacent to each other, and so will most - * often share cache lines (with a huge negative performance - * impact) without this precaution. + * (via @Contended) to reduce cache contention. Padding is + * overkill for most Atomics because they are usually irregularly + * scattered in memory and thus don't interfere much with each + * other. But Atomic objects residing in arrays will tend to be + * placed adjacent to each other, and so will most often share + * cache lines (with a huge negative performance impact) without + * this precaution. * * In part because Cells are relatively large, we avoid creating * them until they are needed. When there is no contention, all diff --git a/jdk/test/java/util/concurrent/ConcurrentQueues/RemovePollRace.java b/jdk/test/java/util/concurrent/ConcurrentQueues/RemovePollRace.java index 4fe26337092..abcae1d398a 100644 --- a/jdk/test/java/util/concurrent/ConcurrentQueues/RemovePollRace.java +++ b/jdk/test/java/util/concurrent/ConcurrentQueues/RemovePollRace.java @@ -121,12 +121,16 @@ public class RemovePollRace { final int SPINS = 5; final AtomicLong removes = new AtomicLong(0); final AtomicLong polls = new AtomicLong(0); - final int adderCount = - Math.max(1, Runtime.getRuntime().availableProcessors() / 4); - final int removerCount = - Math.max(1, Runtime.getRuntime().availableProcessors() / 4); + + // We need at least 3 threads, but we don't want to use too + // many on massively multi-core systems. + final int cpus = Runtime.getRuntime().availableProcessors(); + final int threadsToUse = Math.max(3, Math.min(cpus, 16)); + final int adderCount = threadsToUse / 3; + final int removerCount = adderCount; final int pollerCount = removerCount; final int threadCount = adderCount + removerCount + pollerCount; + final CountDownLatch startingGate = new CountDownLatch(1); final CountDownLatch addersDone = new CountDownLatch(adderCount); final Runnable remover = new Runnable() { diff --git a/jdk/test/java/util/concurrent/ExecutorCompletionService/ExecutorCompletionServiceLoops.java b/jdk/test/java/util/concurrent/ExecutorCompletionService/ExecutorCompletionServiceLoops.java index e5afd0a4dfc..1da7f2335c7 100644 --- a/jdk/test/java/util/concurrent/ExecutorCompletionService/ExecutorCompletionServiceLoops.java +++ b/jdk/test/java/util/concurrent/ExecutorCompletionService/ExecutorCompletionServiceLoops.java @@ -61,13 +61,13 @@ public class ExecutorCompletionServiceLoops { max = Integer.parseInt(args[0]); System.out.println("Warmup..."); - oneTest( base ); + oneTest(base); Thread.sleep(100); print = true; for (int i = 1; i <= max; i += (i+1) >>> 1) { System.out.print("n: " + i * base); - oneTest(i * base ); + oneTest(i * base); Thread.sleep(100); } pool.shutdown();