8341903: Implementation of Scoped Values (Fourth Preview)
Reviewed-by: alanb
This commit is contained in:
parent
839de82c31
commit
3fab8e37bb
@ -75,34 +75,34 @@ import sun.security.action.GetPropertyAction;
|
|||||||
* // @link substring="newInstance" target="#newInstance" :
|
* // @link substring="newInstance" target="#newInstance" :
|
||||||
* private static final ScopedValue<String> NAME = ScopedValue.newInstance();
|
* private static final ScopedValue<String> NAME = ScopedValue.newInstance();
|
||||||
*
|
*
|
||||||
* // @link substring="runWhere" target="#runWhere(ScopedValue, Object, Runnable)" :
|
* // @link substring="run" target="Carrier#run(Runnable)" :
|
||||||
* ScopedValue.runWhere(NAME, "duke", () -> doSomething());
|
* ScopedValue.where(NAME, "duke").run(() -> doSomething());
|
||||||
* }
|
* }
|
||||||
* Code executed directly or indirectly by {@code doSomething}, with access to the field
|
* Code executed directly or indirectly by {@code doSomething}, with access to the field
|
||||||
* {@code NAME}, can invoke {@code NAME.get()} to read the value "{@code duke}". {@code
|
* {@code NAME}, can invoke {@code NAME.get()} to read the value "{@code duke}". {@code
|
||||||
* NAME} is bound while executing the {@code run} method. It reverts to being unbound when
|
* NAME} is bound while executing the {@code run} method. It reverts to being unbound when
|
||||||
* the {@code run} method completes.
|
* the {@code run} method completes.
|
||||||
*
|
*
|
||||||
* <p> The example using {@code runWhere} invokes a method that does not return a result.
|
* <p> The example using {@code run} invokes a method that does not return a result.
|
||||||
* The {@link #callWhere(ScopedValue, Object, CallableOp) callWhere} method can be used
|
* The {@link Carrier#call(CallableOp) call} method can be used
|
||||||
* to invoke a method that returns a result.
|
* to invoke a method that returns a result.
|
||||||
* In addition, {@code ScopedValue} defines the {@link #where(ScopedValue, Object)} method
|
* {@code ScopedValue} defines the {@link #where(ScopedValue, Object)} method
|
||||||
* for cases where multiple mappings (of {@code ScopedValue} to value) are accumulated
|
* for cases where multiple mappings (of {@code ScopedValue} to value) are accumulated
|
||||||
* in advance of calling a method with all {@code ScopedValue}s bound to their value.
|
* in advance of calling a method with all {@code ScopedValue}s bound to their value.
|
||||||
*
|
*
|
||||||
* <h2>Bindings are per-thread</h2>
|
* <h2>Bindings are per-thread</h2>
|
||||||
*
|
*
|
||||||
* A {@code ScopedValue} binding to a value is per-thread. Invoking {@code xxxWhere}
|
* A {@code ScopedValue} binding to a value is per-thread. Invoking {@code run}
|
||||||
* executes a method with a {@code ScopedValue} bound to a value for the current thread.
|
* executes a method with a {@code ScopedValue} bound to a value for the current thread.
|
||||||
* The {@link #get() get} method returns the value bound for the current thread.
|
* The {@link #get() get} method returns the value bound for the current thread.
|
||||||
*
|
*
|
||||||
* <p> In the example, if code executed by one thread invokes this:
|
* <p> In the example, if code executed by one thread invokes this:
|
||||||
* {@snippet lang=java :
|
* {@snippet lang=java :
|
||||||
* ScopedValue.runWhere(NAME, "duke1", () -> doSomething());
|
* ScopedValue.where(NAME, "duke1").run(() -> doSomething());
|
||||||
* }
|
* }
|
||||||
* and code executed by another thread invokes:
|
* and code executed by another thread invokes:
|
||||||
* {@snippet lang=java :
|
* {@snippet lang=java :
|
||||||
* ScopedValue.runWhere(NAME, "duke2", () -> doSomething());
|
* ScopedValue.where(NAME, "duke2").run(() -> doSomething());
|
||||||
* }
|
* }
|
||||||
* then code in {@code doSomething} (or any method that it calls) invoking {@code NAME.get()}
|
* then code in {@code doSomething} (or any method that it calls) invoking {@code NAME.get()}
|
||||||
* will read the value "{@code duke1}" or "{@code duke2}", depending on which thread is
|
* will read the value "{@code duke1}" or "{@code duke2}", depending on which thread is
|
||||||
@ -129,7 +129,7 @@ import sun.security.action.GetPropertyAction;
|
|||||||
* <p> In the above example, suppose that code executed by {@code doSomething} binds
|
* <p> In the above example, suppose that code executed by {@code doSomething} binds
|
||||||
* {@code NAME} to a new value with:
|
* {@code NAME} to a new value with:
|
||||||
* {@snippet lang=java :
|
* {@snippet lang=java :
|
||||||
* ScopedValue.runWhere(NAME, "duchess", () -> doMore());
|
* ScopedValue.where(NAME, "duchess").run(() -> doMore());
|
||||||
* }
|
* }
|
||||||
* Code executed directly or indirectly by {@code doMore()} that invokes {@code
|
* Code executed directly or indirectly by {@code doMore()} that invokes {@code
|
||||||
* NAME.get()} will read the value "{@code duchess}". When {@code doMore()} completes
|
* NAME.get()} will read the value "{@code duchess}". When {@code doMore()} completes
|
||||||
@ -157,14 +157,18 @@ import sun.security.action.GetPropertyAction;
|
|||||||
* {@snippet lang=java :
|
* {@snippet lang=java :
|
||||||
* private static final ScopedValue<String> NAME = ScopedValue.newInstance();
|
* private static final ScopedValue<String> NAME = ScopedValue.newInstance();
|
||||||
|
|
||||||
* ScopedValue.runWhere(NAME, "duke", () -> {
|
* ScopedValue.where(NAME, "duke").run(() -> {
|
||||||
* try (var scope = new StructuredTaskScope<String>()) {
|
* try (var scope = new StructuredTaskScope<String>()) {
|
||||||
*
|
*
|
||||||
* scope.fork(() -> childTask1());
|
* // @link substring="fork" target="StructuredTaskScope#fork(java.util.concurrent.Callable)" :
|
||||||
* scope.fork(() -> childTask2());
|
* scope.fork(() -> childTask1());
|
||||||
* scope.fork(() -> childTask3());
|
* scope.fork(() -> childTask2());
|
||||||
|
* scope.fork(() -> childTask3());
|
||||||
*
|
*
|
||||||
* ...
|
* // @link substring="join" target="StructuredTaskScope#join()" :
|
||||||
|
* scope.join();
|
||||||
|
*
|
||||||
|
* ..
|
||||||
* }
|
* }
|
||||||
* });
|
* });
|
||||||
* }
|
* }
|
||||||
@ -310,7 +314,7 @@ public final class ScopedValue<T> {
|
|||||||
*/
|
*/
|
||||||
@PreviewFeature(feature = PreviewFeature.Feature.SCOPED_VALUES)
|
@PreviewFeature(feature = PreviewFeature.Feature.SCOPED_VALUES)
|
||||||
public static final class Carrier {
|
public static final class Carrier {
|
||||||
// Bit masks: a 1 in postion n indicates that this set of bound values
|
// Bit masks: a 1 in position n indicates that this set of bound values
|
||||||
// hits that slot in the cache.
|
// hits that slot in the cache.
|
||||||
final int bitmask;
|
final int bitmask;
|
||||||
final ScopedValue<?> key;
|
final ScopedValue<?> key;
|
||||||
@ -385,7 +389,7 @@ public final class ScopedValue<T> {
|
|||||||
return (T) value;
|
return (T) value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw new NoSuchElementException();
|
throw new NoSuchElementException("No mapping present");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -409,7 +413,6 @@ public final class ScopedValue<T> {
|
|||||||
* @return the result
|
* @return the result
|
||||||
* @throws StructureViolationException if a structure violation is detected
|
* @throws StructureViolationException if a structure violation is detected
|
||||||
* @throws X if {@code op} completes with an exception
|
* @throws X if {@code op} completes with an exception
|
||||||
* @see ScopedValue#callWhere(ScopedValue, Object, CallableOp)
|
|
||||||
* @since 23
|
* @since 23
|
||||||
*/
|
*/
|
||||||
public <R, X extends Throwable> R call(CallableOp<? extends R, X> op) throws X {
|
public <R, X extends Throwable> R call(CallableOp<? extends R, X> op) throws X {
|
||||||
@ -458,7 +461,6 @@ public final class ScopedValue<T> {
|
|||||||
*
|
*
|
||||||
* @param op the operation to run
|
* @param op the operation to run
|
||||||
* @throws StructureViolationException if a structure violation is detected
|
* @throws StructureViolationException if a structure violation is detected
|
||||||
* @see ScopedValue#runWhere(ScopedValue, Object, Runnable)
|
|
||||||
*/
|
*/
|
||||||
public void run(Runnable op) {
|
public void run(Runnable op) {
|
||||||
Objects.requireNonNull(op);
|
Objects.requireNonNull(op);
|
||||||
@ -528,77 +530,6 @@ public final class ScopedValue<T> {
|
|||||||
return Carrier.of(key, value);
|
return Carrier.of(key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Calls a value-returning operation with a {@code ScopedValue} bound to a value
|
|
||||||
* in the current thread. When the operation completes (normally or with an
|
|
||||||
* exception), the {@code ScopedValue} will revert to being unbound, or revert to
|
|
||||||
* its previous value when previously bound, in the current thread. If {@code op}
|
|
||||||
* completes with an exception then it propagated by this method.
|
|
||||||
*
|
|
||||||
* <p> Scoped values are intended to be used in a <em>structured manner</em>. If code
|
|
||||||
* invoked directly or indirectly by the operation creates a {@link StructuredTaskScope}
|
|
||||||
* but does not {@linkplain StructuredTaskScope#close() close} it, then it is detected
|
|
||||||
* as a <em>structure violation</em> when the operation completes (normally or with an
|
|
||||||
* exception). In that case, the underlying construct of the {@code StructuredTaskScope}
|
|
||||||
* is closed and {@link StructureViolationException} is thrown.
|
|
||||||
*
|
|
||||||
* @implNote
|
|
||||||
* This method is implemented to be equivalent to:
|
|
||||||
* {@snippet lang=java :
|
|
||||||
* // @link substring="call" target="Carrier#call(CallableOp)" :
|
|
||||||
* ScopedValue.where(key, value).call(op);
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param key the {@code ScopedValue} key
|
|
||||||
* @param value the value, can be {@code null}
|
|
||||||
* @param <T> the type of the value
|
|
||||||
* @param <R> the result type
|
|
||||||
* @param <X> type of the exception thrown by the operation
|
|
||||||
* @param op the operation to call
|
|
||||||
* @return the result
|
|
||||||
* @throws StructureViolationException if a structure violation is detected
|
|
||||||
* @throws X if the operation completes with an exception
|
|
||||||
* @since 23
|
|
||||||
*/
|
|
||||||
public static <T, R, X extends Throwable> R callWhere(ScopedValue<T> key,
|
|
||||||
T value,
|
|
||||||
CallableOp<? extends R, X> op) throws X {
|
|
||||||
return where(key, value).call(op);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Run an operation with a {@code ScopedValue} bound to a value in the current
|
|
||||||
* thread. When the operation completes (normally or with an exception), the
|
|
||||||
* {@code ScopedValue} will revert to being unbound, or revert to its previous value
|
|
||||||
* when previously bound, in the current thread. If {@code op} completes with an
|
|
||||||
* exception then it propagated by this method.
|
|
||||||
*
|
|
||||||
* <p> Scoped values are intended to be used in a <em>structured manner</em>. If code
|
|
||||||
* invoked directly or indirectly by the operation creates a {@link StructuredTaskScope}
|
|
||||||
* but does not {@linkplain StructuredTaskScope#close() close} it, then it is detected
|
|
||||||
* as a <em>structure violation</em> when the operation completes (normally or with an
|
|
||||||
* exception). In that case, the underlying construct of the {@code StructuredTaskScope}
|
|
||||||
* is closed and {@link StructureViolationException} is thrown.
|
|
||||||
*
|
|
||||||
* @implNote
|
|
||||||
* This method is implemented to be equivalent to:
|
|
||||||
* {@snippet lang=java :
|
|
||||||
* // @link substring="run" target="Carrier#run(Runnable)" :
|
|
||||||
* ScopedValue.where(key, value).run(op);
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* @param key the {@code ScopedValue} key
|
|
||||||
* @param value the value, can be {@code null}
|
|
||||||
* @param <T> the type of the value
|
|
||||||
* @param op the operation to call
|
|
||||||
* @throws StructureViolationException if a structure violation is detected
|
|
||||||
*/
|
|
||||||
public static <T> void runWhere(ScopedValue<T> key, T value, Runnable op) {
|
|
||||||
where(key, value).run(op);
|
|
||||||
}
|
|
||||||
|
|
||||||
private ScopedValue() {
|
private ScopedValue() {
|
||||||
this.hash = generateKey();
|
this.hash = generateKey();
|
||||||
}
|
}
|
||||||
@ -642,7 +573,7 @@ public final class ScopedValue<T> {
|
|||||||
private T slowGet() {
|
private T slowGet() {
|
||||||
var value = findBinding();
|
var value = findBinding();
|
||||||
if (value == Snapshot.NIL) {
|
if (value == Snapshot.NIL) {
|
||||||
throw new NoSuchElementException();
|
throw new NoSuchElementException("ScopedValue not bound");
|
||||||
}
|
}
|
||||||
Cache.put(this, value);
|
Cache.put(this, value);
|
||||||
return (T)value;
|
return (T)value;
|
||||||
|
@ -261,8 +261,8 @@ import jdk.internal.invoke.MhUtil;
|
|||||||
* {@snippet lang=java :
|
* {@snippet lang=java :
|
||||||
* private static final ScopedValue<String> USERNAME = ScopedValue.newInstance();
|
* private static final ScopedValue<String> USERNAME = ScopedValue.newInstance();
|
||||||
*
|
*
|
||||||
* // @link substring="runWhere" target="ScopedValue#runWhere(ScopedValue, Object, Runnable)" :
|
* // @link substring="run" target="ScopedValue.Carrier#run(Runnable)" :
|
||||||
* ScopedValue.runWhere(USERNAME, "duke", () -> {
|
* ScopedValue.where(USERNAME, "duke").run(() -> {
|
||||||
* try (var scope = new StructuredTaskScope<String>()) {
|
* try (var scope = new StructuredTaskScope<String>()) {
|
||||||
*
|
*
|
||||||
* scope.fork(() -> childTask()); // @highlight substring="fork"
|
* scope.fork(() -> childTask()); // @highlight substring="fork"
|
||||||
|
@ -436,7 +436,7 @@ public final class Subject implements java.io.Serializable {
|
|||||||
Objects.requireNonNull(action);
|
Objects.requireNonNull(action);
|
||||||
if (!SharedSecrets.getJavaLangAccess().allowSecurityManager()) {
|
if (!SharedSecrets.getJavaLangAccess().allowSecurityManager()) {
|
||||||
try {
|
try {
|
||||||
return ScopedValue.callWhere(SCOPED_SUBJECT, subject, action::call);
|
return ScopedValue.where(SCOPED_SUBJECT, subject).call(action::call);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new CompletionException(e);
|
throw new CompletionException(e);
|
||||||
}
|
}
|
||||||
|
@ -70,7 +70,7 @@ public @interface PreviewFeature {
|
|||||||
//---
|
//---
|
||||||
@JEP(number=477, title="Implicitly Declared Classes and Instance Main Methods", status="Third Preview")
|
@JEP(number=477, title="Implicitly Declared Classes and Instance Main Methods", status="Third Preview")
|
||||||
IMPLICIT_CLASSES,
|
IMPLICIT_CLASSES,
|
||||||
@JEP(number=481, title="Scoped Values", status="Third Preview")
|
@JEP(number=487, title="Scoped Values", status="Fourth Preview")
|
||||||
SCOPED_VALUES,
|
SCOPED_VALUES,
|
||||||
@JEP(number=480, title="Structured Concurrency", status="Third Preview")
|
@JEP(number=480, title="Structured Concurrency", status="Third Preview")
|
||||||
STRUCTURED_CONCURRENCY,
|
STRUCTURED_CONCURRENCY,
|
||||||
|
@ -48,7 +48,7 @@ class ScopedValueAPI {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test that runWhere invokes the Runnable's run method.
|
* Test that where invokes the Runnable's run method.
|
||||||
*/
|
*/
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
@MethodSource("factories")
|
@MethodSource("factories")
|
||||||
@ -56,13 +56,13 @@ class ScopedValueAPI {
|
|||||||
test(factory, () -> {
|
test(factory, () -> {
|
||||||
class Box { static boolean executed; }
|
class Box { static boolean executed; }
|
||||||
ScopedValue<String> name = ScopedValue.newInstance();
|
ScopedValue<String> name = ScopedValue.newInstance();
|
||||||
ScopedValue.runWhere(name, "duke", () -> { Box.executed = true; });
|
ScopedValue.where(name, "duke").run(() -> { Box.executed = true; });
|
||||||
assertTrue(Box.executed);
|
assertTrue(Box.executed);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test runWhere when the run method throws an exception.
|
* Test where when the run method throws an exception.
|
||||||
*/
|
*/
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
@MethodSource("factories")
|
@MethodSource("factories")
|
||||||
@ -71,7 +71,7 @@ class ScopedValueAPI {
|
|||||||
class FooException extends RuntimeException { }
|
class FooException extends RuntimeException { }
|
||||||
ScopedValue<String> name = ScopedValue.newInstance();
|
ScopedValue<String> name = ScopedValue.newInstance();
|
||||||
Runnable op = () -> { throw new FooException(); };
|
Runnable op = () -> { throw new FooException(); };
|
||||||
assertThrows(FooException.class, () -> ScopedValue.runWhere(name, "duke", op));
|
assertThrows(FooException.class, () -> ScopedValue.where(name, "duke").run(op));
|
||||||
assertFalse(name.isBound());
|
assertFalse(name.isBound());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -84,7 +84,7 @@ class ScopedValueAPI {
|
|||||||
void testCallWhere(ThreadFactory factory) throws Exception {
|
void testCallWhere(ThreadFactory factory) throws Exception {
|
||||||
test(factory, () -> {
|
test(factory, () -> {
|
||||||
ScopedValue<String> name = ScopedValue.newInstance();
|
ScopedValue<String> name = ScopedValue.newInstance();
|
||||||
String result = ScopedValue.callWhere(name, "duke", name::get);
|
String result = ScopedValue.where(name, "duke").call(name::get);
|
||||||
assertEquals("duke", result);
|
assertEquals("duke", result);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -99,7 +99,7 @@ class ScopedValueAPI {
|
|||||||
class FooException extends RuntimeException { }
|
class FooException extends RuntimeException { }
|
||||||
ScopedValue<String> name = ScopedValue.newInstance();
|
ScopedValue<String> name = ScopedValue.newInstance();
|
||||||
CallableOp<Void, RuntimeException> op = () -> { throw new FooException(); };
|
CallableOp<Void, RuntimeException> op = () -> { throw new FooException(); };
|
||||||
assertThrows(FooException.class, () -> ScopedValue.callWhere(name, "duke", op));
|
assertThrows(FooException.class, () -> ScopedValue.where(name, "duke").call(op));
|
||||||
assertFalse(name.isBound());
|
assertFalse(name.isBound());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -116,8 +116,8 @@ class ScopedValueAPI {
|
|||||||
assertThrows(NoSuchElementException.class, name1::get);
|
assertThrows(NoSuchElementException.class, name1::get);
|
||||||
assertThrows(NoSuchElementException.class, name2::get);
|
assertThrows(NoSuchElementException.class, name2::get);
|
||||||
|
|
||||||
// runWhere
|
// where
|
||||||
ScopedValue.runWhere(name1, "duke", () -> {
|
ScopedValue.where(name1, "duke").run(() -> {
|
||||||
assertEquals("duke", name1.get());
|
assertEquals("duke", name1.get());
|
||||||
assertThrows(NoSuchElementException.class, name2::get);
|
assertThrows(NoSuchElementException.class, name2::get);
|
||||||
|
|
||||||
@ -126,7 +126,7 @@ class ScopedValueAPI {
|
|||||||
assertThrows(NoSuchElementException.class, name2::get);
|
assertThrows(NoSuchElementException.class, name2::get);
|
||||||
|
|
||||||
// callWhere
|
// callWhere
|
||||||
ScopedValue.callWhere(name1, "duke", () -> {
|
ScopedValue.where(name1, "duke").call(() -> {
|
||||||
assertEquals("duke", name1.get());
|
assertEquals("duke", name1.get());
|
||||||
assertThrows(NoSuchElementException.class, name2::get);
|
assertThrows(NoSuchElementException.class, name2::get);
|
||||||
return null;
|
return null;
|
||||||
@ -148,8 +148,8 @@ class ScopedValueAPI {
|
|||||||
assertFalse(name1.isBound());
|
assertFalse(name1.isBound());
|
||||||
assertFalse(name2.isBound());
|
assertFalse(name2.isBound());
|
||||||
|
|
||||||
// runWhere
|
// where
|
||||||
ScopedValue.runWhere(name1, "duke", () -> {
|
ScopedValue.where(name1, "duke").run(() -> {
|
||||||
assertTrue(name1.isBound());
|
assertTrue(name1.isBound());
|
||||||
assertFalse(name2.isBound());
|
assertFalse(name2.isBound());
|
||||||
});
|
});
|
||||||
@ -157,7 +157,7 @@ class ScopedValueAPI {
|
|||||||
assertFalse(name2.isBound());
|
assertFalse(name2.isBound());
|
||||||
|
|
||||||
// callWhere
|
// callWhere
|
||||||
ScopedValue.callWhere(name1, "duke", () -> {
|
ScopedValue.where(name1, "duke").call(() -> {
|
||||||
assertTrue(name1.isBound());
|
assertTrue(name1.isBound());
|
||||||
assertFalse(name2.isBound());
|
assertFalse(name2.isBound());
|
||||||
return null;
|
return null;
|
||||||
@ -178,14 +178,14 @@ class ScopedValueAPI {
|
|||||||
assertNull(name.orElse(null));
|
assertNull(name.orElse(null));
|
||||||
assertEquals("default", name.orElse("default"));
|
assertEquals("default", name.orElse("default"));
|
||||||
|
|
||||||
// runWhere
|
// where
|
||||||
ScopedValue.runWhere(name, "duke", () -> {
|
ScopedValue.where(name, "duke").run(() -> {
|
||||||
assertEquals("duke", name.orElse(null));
|
assertEquals("duke", name.orElse(null));
|
||||||
assertEquals("duke", name.orElse("default"));
|
assertEquals("duke", name.orElse("default"));
|
||||||
});
|
});
|
||||||
|
|
||||||
// callWhere
|
// callWhere
|
||||||
ScopedValue.callWhere(name, "duke", () -> {
|
ScopedValue.where(name, "duke").call(() -> {
|
||||||
assertEquals("duke", name.orElse(null));
|
assertEquals("duke", name.orElse(null));
|
||||||
assertEquals("duke", name.orElse("default"));
|
assertEquals("duke", name.orElse("default"));
|
||||||
return null;
|
return null;
|
||||||
@ -204,13 +204,13 @@ class ScopedValueAPI {
|
|||||||
ScopedValue<String> name = ScopedValue.newInstance();
|
ScopedValue<String> name = ScopedValue.newInstance();
|
||||||
assertThrows(FooException.class, () -> name.orElseThrow(FooException::new));
|
assertThrows(FooException.class, () -> name.orElseThrow(FooException::new));
|
||||||
|
|
||||||
// runWhere
|
// where
|
||||||
ScopedValue.runWhere(name, "duke", () -> {
|
ScopedValue.where(name, "duke").run(() -> {
|
||||||
assertEquals("duke", name.orElseThrow(FooException::new));
|
assertEquals("duke", name.orElseThrow(FooException::new));
|
||||||
});
|
});
|
||||||
|
|
||||||
// callWhere
|
// callWhere
|
||||||
ScopedValue.callWhere(name, "duke", () -> {
|
ScopedValue.where(name, "duke").call(() -> {
|
||||||
assertEquals("duke", name.orElseThrow(FooException::new));
|
assertEquals("duke", name.orElseThrow(FooException::new));
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
@ -259,12 +259,12 @@ class ScopedValueAPI {
|
|||||||
test(factory, () -> {
|
test(factory, () -> {
|
||||||
ScopedValue<String> name = ScopedValue.newInstance();
|
ScopedValue<String> name = ScopedValue.newInstance();
|
||||||
|
|
||||||
// runWhere
|
// where
|
||||||
ScopedValue.runWhere(name, "duke", () -> {
|
ScopedValue.where(name, "duke").run(() -> {
|
||||||
assertTrue(name.isBound());
|
assertTrue(name.isBound());
|
||||||
assertEquals("duke", name.get());
|
assertEquals("duke", name.get());
|
||||||
|
|
||||||
ScopedValue.runWhere(name, "duchess", () -> {
|
ScopedValue.where(name, "duchess").run(() -> {
|
||||||
assertTrue(name.isBound());
|
assertTrue(name.isBound());
|
||||||
assertEquals("duchess", name.get());
|
assertEquals("duchess", name.get());
|
||||||
});
|
});
|
||||||
@ -275,11 +275,11 @@ class ScopedValueAPI {
|
|||||||
assertFalse(name.isBound());
|
assertFalse(name.isBound());
|
||||||
|
|
||||||
// callWhere
|
// callWhere
|
||||||
ScopedValue.callWhere(name, "duke", () -> {
|
ScopedValue.where(name, "duke").call(() -> {
|
||||||
assertTrue(name.isBound());
|
assertTrue(name.isBound());
|
||||||
assertEquals("duke", name.get());
|
assertEquals("duke", name.get());
|
||||||
|
|
||||||
ScopedValue.callWhere(name, "duchess", () -> {
|
ScopedValue.where(name, "duchess").call(() -> {
|
||||||
assertTrue(name.isBound());
|
assertTrue(name.isBound());
|
||||||
assertEquals("duchess", name.get());
|
assertEquals("duchess", name.get());
|
||||||
return null;
|
return null;
|
||||||
@ -302,12 +302,12 @@ class ScopedValueAPI {
|
|||||||
test(factory, () -> {
|
test(factory, () -> {
|
||||||
ScopedValue<String> name = ScopedValue.newInstance();
|
ScopedValue<String> name = ScopedValue.newInstance();
|
||||||
|
|
||||||
// runWhere
|
// where
|
||||||
ScopedValue.runWhere(name, null, () -> {
|
ScopedValue.where(name, null).run(() -> {
|
||||||
assertTrue(name.isBound());
|
assertTrue(name.isBound());
|
||||||
assertNull(name.get());
|
assertNull(name.get());
|
||||||
|
|
||||||
ScopedValue.runWhere(name, "duchess", () -> {
|
ScopedValue.where(name, "duchess").run(() -> {
|
||||||
assertTrue(name.isBound());
|
assertTrue(name.isBound());
|
||||||
assertTrue("duchess".equals(name.get()));
|
assertTrue("duchess".equals(name.get()));
|
||||||
});
|
});
|
||||||
@ -318,11 +318,11 @@ class ScopedValueAPI {
|
|||||||
assertFalse(name.isBound());
|
assertFalse(name.isBound());
|
||||||
|
|
||||||
// callWhere
|
// callWhere
|
||||||
ScopedValue.callWhere(name, null, () -> {
|
ScopedValue.where(name, null).call(() -> {
|
||||||
assertTrue(name.isBound());
|
assertTrue(name.isBound());
|
||||||
assertNull(name.get());
|
assertNull(name.get());
|
||||||
|
|
||||||
ScopedValue.callWhere(name, "duchess", () -> {
|
ScopedValue.where(name, "duchess").call(() -> {
|
||||||
assertTrue(name.isBound());
|
assertTrue(name.isBound());
|
||||||
assertTrue("duchess".equals(name.get()));
|
assertTrue("duchess".equals(name.get()));
|
||||||
return null;
|
return null;
|
||||||
@ -345,12 +345,12 @@ class ScopedValueAPI {
|
|||||||
test(factory, () -> {
|
test(factory, () -> {
|
||||||
ScopedValue<String> name = ScopedValue.newInstance();
|
ScopedValue<String> name = ScopedValue.newInstance();
|
||||||
|
|
||||||
// runWhere
|
// where
|
||||||
ScopedValue.runWhere(name, "duke", () -> {
|
ScopedValue.where(name, "duke").run(() -> {
|
||||||
assertTrue(name.isBound());
|
assertTrue(name.isBound());
|
||||||
assertEquals("duke", name.get());
|
assertEquals("duke", name.get());
|
||||||
|
|
||||||
ScopedValue.runWhere(name, null, () -> {
|
ScopedValue.where(name, null).run(() -> {
|
||||||
assertTrue(name.isBound());
|
assertTrue(name.isBound());
|
||||||
assertNull(name.get());
|
assertNull(name.get());
|
||||||
});
|
});
|
||||||
@ -361,11 +361,11 @@ class ScopedValueAPI {
|
|||||||
assertFalse(name.isBound());
|
assertFalse(name.isBound());
|
||||||
|
|
||||||
// callWhere
|
// callWhere
|
||||||
ScopedValue.callWhere(name, "duke", () -> {
|
ScopedValue.where(name, "duke").call(() -> {
|
||||||
assertTrue(name.isBound());
|
assertTrue(name.isBound());
|
||||||
assertEquals("duke", name.get());
|
assertEquals("duke", name.get());
|
||||||
|
|
||||||
ScopedValue.callWhere(name, null, () -> {
|
ScopedValue.where(name, null).call(() -> {
|
||||||
assertTrue(name.isBound());
|
assertTrue(name.isBound());
|
||||||
assertNull(name.get());
|
assertNull(name.get());
|
||||||
return null;
|
return null;
|
||||||
@ -410,11 +410,11 @@ class ScopedValueAPI {
|
|||||||
|
|
||||||
assertThrows(NullPointerException.class, () -> ScopedValue.where(null, "duke"));
|
assertThrows(NullPointerException.class, () -> ScopedValue.where(null, "duke"));
|
||||||
|
|
||||||
assertThrows(NullPointerException.class, () -> ScopedValue.runWhere(null, "duke", () -> { }));
|
assertThrows(NullPointerException.class, () -> ScopedValue.where(null, "duke").run(() -> { }));
|
||||||
assertThrows(NullPointerException.class, () -> ScopedValue.runWhere(name, "duke", null));
|
assertThrows(NullPointerException.class, () -> ScopedValue.where(name, "duke").run(null));
|
||||||
|
|
||||||
assertThrows(NullPointerException.class, () -> ScopedValue.callWhere(null, "duke", () -> ""));
|
assertThrows(NullPointerException.class, () -> ScopedValue.where(null, "duke").call(() -> ""));
|
||||||
assertThrows(NullPointerException.class, () -> ScopedValue.callWhere(name, "duke", null));
|
assertThrows(NullPointerException.class, () -> ScopedValue.where(name, "duke").call(null));
|
||||||
|
|
||||||
assertThrows(NullPointerException.class, () -> name.orElseThrow(null));
|
assertThrows(NullPointerException.class, () -> name.orElseThrow(null));
|
||||||
|
|
||||||
|
@ -54,7 +54,7 @@ class WithScopedValue {
|
|||||||
@MethodSource("factories")
|
@MethodSource("factories")
|
||||||
void testForkInheritsScopedValue1(ThreadFactory factory) throws Exception {
|
void testForkInheritsScopedValue1(ThreadFactory factory) throws Exception {
|
||||||
ScopedValue<String> name = ScopedValue.newInstance();
|
ScopedValue<String> name = ScopedValue.newInstance();
|
||||||
String value = ScopedValue.callWhere(name, "x", () -> {
|
String value = ScopedValue.where(name, "x").call(() -> {
|
||||||
try (var scope = new StructuredTaskScope<String>(null, factory)) {
|
try (var scope = new StructuredTaskScope<String>(null, factory)) {
|
||||||
Subtask<String> subtask = scope.fork(() -> {
|
Subtask<String> subtask = scope.fork(() -> {
|
||||||
return name.get(); // child should read "x"
|
return name.get(); // child should read "x"
|
||||||
@ -73,7 +73,7 @@ class WithScopedValue {
|
|||||||
@MethodSource("factories")
|
@MethodSource("factories")
|
||||||
void testForkInheritsScopedValue2(ThreadFactory factory) throws Exception {
|
void testForkInheritsScopedValue2(ThreadFactory factory) throws Exception {
|
||||||
ScopedValue<String> name = ScopedValue.newInstance();
|
ScopedValue<String> name = ScopedValue.newInstance();
|
||||||
String value = ScopedValue.callWhere(name, "x", () -> {
|
String value = ScopedValue.where(name, "x").call(() -> {
|
||||||
try (var scope1 = new StructuredTaskScope<String>(null, factory)) {
|
try (var scope1 = new StructuredTaskScope<String>(null, factory)) {
|
||||||
Subtask<String> subtask1 = scope1.fork(() -> {
|
Subtask<String> subtask1 = scope1.fork(() -> {
|
||||||
try (var scope2 = new StructuredTaskScope<String>(null, factory)) {
|
try (var scope2 = new StructuredTaskScope<String>(null, factory)) {
|
||||||
@ -98,13 +98,13 @@ class WithScopedValue {
|
|||||||
@MethodSource("factories")
|
@MethodSource("factories")
|
||||||
void testForkInheritsScopedValue3(ThreadFactory factory) throws Exception {
|
void testForkInheritsScopedValue3(ThreadFactory factory) throws Exception {
|
||||||
ScopedValue<String> name = ScopedValue.newInstance();
|
ScopedValue<String> name = ScopedValue.newInstance();
|
||||||
String value = ScopedValue.callWhere(name, "x", () -> {
|
String value = ScopedValue.where(name, "x").call(() -> {
|
||||||
try (var scope1 = new StructuredTaskScope<String>(null, factory)) {
|
try (var scope1 = new StructuredTaskScope<String>(null, factory)) {
|
||||||
Subtask<String> subtask1 = scope1.fork(() -> {
|
Subtask<String> subtask1 = scope1.fork(() -> {
|
||||||
assertEquals(name.get(), "x"); // child should read "x"
|
assertEquals(name.get(), "x"); // child should read "x"
|
||||||
|
|
||||||
// rebind name to "y"
|
// rebind name to "y"
|
||||||
String grandchildValue = ScopedValue.callWhere(name, "y", () -> {
|
String grandchildValue = ScopedValue.where(name, "y").call(() -> {
|
||||||
try (var scope2 = new StructuredTaskScope<String>(null, factory)) {
|
try (var scope2 = new StructuredTaskScope<String>(null, factory)) {
|
||||||
Subtask<String> subtask2 = scope2.fork(() -> {
|
Subtask<String> subtask2 = scope2.fork(() -> {
|
||||||
return name.get(); // grandchild should read "y"
|
return name.get(); // grandchild should read "y"
|
||||||
@ -136,7 +136,7 @@ class WithScopedValue {
|
|||||||
var box = new Box();
|
var box = new Box();
|
||||||
try {
|
try {
|
||||||
try {
|
try {
|
||||||
ScopedValue.runWhere(name, "x", () -> {
|
ScopedValue.where(name, "x").run(() -> {
|
||||||
box.scope = new StructuredTaskScope<Object>();
|
box.scope = new StructuredTaskScope<Object>();
|
||||||
});
|
});
|
||||||
fail();
|
fail();
|
||||||
@ -167,7 +167,7 @@ class WithScopedValue {
|
|||||||
void testStructureViolation2() throws Exception {
|
void testStructureViolation2() throws Exception {
|
||||||
ScopedValue<String> name = ScopedValue.newInstance();
|
ScopedValue<String> name = ScopedValue.newInstance();
|
||||||
try (var scope = new StructuredTaskScope<String>()) {
|
try (var scope = new StructuredTaskScope<String>()) {
|
||||||
ScopedValue.runWhere(name, "x", () -> {
|
ScopedValue.where(name, "x").run(() -> {
|
||||||
assertThrows(StructureViolationException.class, scope::close);
|
assertThrows(StructureViolationException.class, scope::close);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -180,7 +180,7 @@ class WithScopedValue {
|
|||||||
void testStructureViolation3() throws Exception {
|
void testStructureViolation3() throws Exception {
|
||||||
ScopedValue<String> name = ScopedValue.newInstance();
|
ScopedValue<String> name = ScopedValue.newInstance();
|
||||||
try (var scope = new StructuredTaskScope<String>()) {
|
try (var scope = new StructuredTaskScope<String>()) {
|
||||||
ScopedValue.runWhere(name, "x", () -> {
|
ScopedValue.where(name, "x").run(() -> {
|
||||||
assertThrows(StructureViolationException.class,
|
assertThrows(StructureViolationException.class,
|
||||||
() -> scope.fork(() -> "foo"));
|
() -> scope.fork(() -> "foo"));
|
||||||
});
|
});
|
||||||
@ -196,9 +196,9 @@ class WithScopedValue {
|
|||||||
ScopedValue<String> name2 = ScopedValue.newInstance();
|
ScopedValue<String> name2 = ScopedValue.newInstance();
|
||||||
|
|
||||||
// rebind
|
// rebind
|
||||||
ScopedValue.runWhere(name1, "x", () -> {
|
ScopedValue.where(name1, "x").run(() -> {
|
||||||
try (var scope = new StructuredTaskScope<String>()) {
|
try (var scope = new StructuredTaskScope<String>()) {
|
||||||
ScopedValue.runWhere(name1, "y", () -> {
|
ScopedValue.where(name1, "y").run(() -> {
|
||||||
assertThrows(StructureViolationException.class,
|
assertThrows(StructureViolationException.class,
|
||||||
() -> scope.fork(() -> "foo"));
|
() -> scope.fork(() -> "foo"));
|
||||||
});
|
});
|
||||||
@ -206,9 +206,9 @@ class WithScopedValue {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// new binding
|
// new binding
|
||||||
ScopedValue.runWhere(name1, "x", () -> {
|
ScopedValue.where(name1, "x").run(() -> {
|
||||||
try (var scope = new StructuredTaskScope<String>()) {
|
try (var scope = new StructuredTaskScope<String>()) {
|
||||||
ScopedValue.runWhere(name2, "y", () -> {
|
ScopedValue.where(name2, "y").run(() -> {
|
||||||
assertThrows(StructureViolationException.class,
|
assertThrows(StructureViolationException.class,
|
||||||
() -> scope.fork(() -> "foo"));
|
() -> scope.fork(() -> "foo"));
|
||||||
});
|
});
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -53,7 +53,7 @@ class WithScopedValue {
|
|||||||
@MethodSource("factories")
|
@MethodSource("factories")
|
||||||
void testInheritsScopedValue(ThreadFactory factory) throws Exception {
|
void testInheritsScopedValue(ThreadFactory factory) throws Exception {
|
||||||
ScopedValue<String> name = ScopedValue.newInstance();
|
ScopedValue<String> name = ScopedValue.newInstance();
|
||||||
String value = ScopedValue.callWhere(name, "duke", () -> {
|
String value = ScopedValue.where(name, "duke").call(() -> {
|
||||||
var result = new AtomicReference<String>();
|
var result = new AtomicReference<String>();
|
||||||
try (var flock = ThreadFlock.open(null)) {
|
try (var flock = ThreadFlock.open(null)) {
|
||||||
Thread thread = factory.newThread(() -> {
|
Thread thread = factory.newThread(() -> {
|
||||||
@ -79,7 +79,7 @@ class WithScopedValue {
|
|||||||
}
|
}
|
||||||
var box = new Box();
|
var box = new Box();
|
||||||
try {
|
try {
|
||||||
ScopedValue.runWhere(name, "x1", () -> {
|
ScopedValue.where(name, "x1").run(() -> {
|
||||||
box.flock1 = ThreadFlock.open(null);
|
box.flock1 = ThreadFlock.open(null);
|
||||||
box.flock2 = ThreadFlock.open(null);
|
box.flock2 = ThreadFlock.open(null);
|
||||||
});
|
});
|
||||||
@ -97,11 +97,11 @@ class WithScopedValue {
|
|||||||
void testStructureViolation2() {
|
void testStructureViolation2() {
|
||||||
ScopedValue<String> name = ScopedValue.newInstance();
|
ScopedValue<String> name = ScopedValue.newInstance();
|
||||||
try (var flock1 = ThreadFlock.open("flock1")) {
|
try (var flock1 = ThreadFlock.open("flock1")) {
|
||||||
ScopedValue.runWhere(name, "x1", () -> {
|
ScopedValue.where(name, "x1").run(() -> {
|
||||||
try (var flock2 = ThreadFlock.open("flock2")) {
|
try (var flock2 = ThreadFlock.open("flock2")) {
|
||||||
ScopedValue.runWhere(name, "x2", () -> {
|
ScopedValue.where(name, "x2").run(() -> {
|
||||||
try (var flock3 = ThreadFlock.open("flock3")) {
|
try (var flock3 = ThreadFlock.open("flock3")) {
|
||||||
ScopedValue.runWhere(name, "x3", () -> {
|
ScopedValue.where(name, "x3").run(() -> {
|
||||||
var flock4 = ThreadFlock.open("flock4");
|
var flock4 = ThreadFlock.open("flock4");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -129,11 +129,11 @@ class WithScopedValue {
|
|||||||
void testStructureViolation3() {
|
void testStructureViolation3() {
|
||||||
ScopedValue<String> name = ScopedValue.newInstance();
|
ScopedValue<String> name = ScopedValue.newInstance();
|
||||||
try (var flock1 = ThreadFlock.open("flock1")) {
|
try (var flock1 = ThreadFlock.open("flock1")) {
|
||||||
ScopedValue.runWhere(name, "x1", () -> {
|
ScopedValue.where(name, "x1").run(() -> {
|
||||||
try (var flock2 = ThreadFlock.open("flock2")) {
|
try (var flock2 = ThreadFlock.open("flock2")) {
|
||||||
ScopedValue.runWhere(name, "x2", () -> {
|
ScopedValue.where(name, "x2").run(() -> {
|
||||||
try (var flock3 = ThreadFlock.open("flock3")) {
|
try (var flock3 = ThreadFlock.open("flock3")) {
|
||||||
ScopedValue.runWhere(name, "x3", () -> {
|
ScopedValue.where(name, "x3").run(() -> {
|
||||||
var flock4 = ThreadFlock.open("flock4");
|
var flock4 = ThreadFlock.open("flock4");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -161,11 +161,11 @@ class WithScopedValue {
|
|||||||
void testStructureViolation4() {
|
void testStructureViolation4() {
|
||||||
ScopedValue<String> name = ScopedValue.newInstance();
|
ScopedValue<String> name = ScopedValue.newInstance();
|
||||||
try (var flock1 = ThreadFlock.open("flock1")) {
|
try (var flock1 = ThreadFlock.open("flock1")) {
|
||||||
ScopedValue.runWhere(name, "x1", () -> {
|
ScopedValue.where(name, "x1").run(() -> {
|
||||||
try (var flock2 = ThreadFlock.open("flock2")) {
|
try (var flock2 = ThreadFlock.open("flock2")) {
|
||||||
ScopedValue.runWhere(name, "x2", () -> {
|
ScopedValue.where(name, "x2").run(() -> {
|
||||||
try (var flock3 = ThreadFlock.open("flock3")) {
|
try (var flock3 = ThreadFlock.open("flock3")) {
|
||||||
ScopedValue.runWhere(name, "x3", () -> {
|
ScopedValue.where(name, "x3").run(() -> {
|
||||||
var flock4 = ThreadFlock.open("flock4");
|
var flock4 = ThreadFlock.open("flock4");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -193,7 +193,7 @@ class WithScopedValue {
|
|||||||
void testStructureViolation5(ThreadFactory factory) throws Exception {
|
void testStructureViolation5(ThreadFactory factory) throws Exception {
|
||||||
ScopedValue<String> name = ScopedValue.newInstance();
|
ScopedValue<String> name = ScopedValue.newInstance();
|
||||||
try (var flock = ThreadFlock.open(null)) {
|
try (var flock = ThreadFlock.open(null)) {
|
||||||
ScopedValue.runWhere(name, "duke", () -> {
|
ScopedValue.where(name, "duke").run(() -> {
|
||||||
Thread thread = factory.newThread(() -> { });
|
Thread thread = factory.newThread(() -> { });
|
||||||
assertThrows(StructureViolationException.class, () -> flock.start(thread));
|
assertThrows(StructureViolationException.class, () -> flock.start(thread));
|
||||||
});
|
});
|
||||||
@ -207,9 +207,9 @@ class WithScopedValue {
|
|||||||
@MethodSource("factories")
|
@MethodSource("factories")
|
||||||
void testStructureViolation6(ThreadFactory factory) throws Exception {
|
void testStructureViolation6(ThreadFactory factory) throws Exception {
|
||||||
ScopedValue<String> name = ScopedValue.newInstance();
|
ScopedValue<String> name = ScopedValue.newInstance();
|
||||||
ScopedValue.runWhere(name, "duke", () -> {
|
ScopedValue.where(name, "duke").run(() -> {
|
||||||
try (var flock = ThreadFlock.open(null)) {
|
try (var flock = ThreadFlock.open(null)) {
|
||||||
ScopedValue.runWhere(name, "duchess", () -> {
|
ScopedValue.where(name, "duchess").run(() -> {
|
||||||
Thread thread = factory.newThread(() -> { });
|
Thread thread = factory.newThread(() -> { });
|
||||||
assertThrows(StructureViolationException.class, () -> flock.start(thread));
|
assertThrows(StructureViolationException.class, () -> flock.start(thread));
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user