< prev index next >

src/java.base/share/classes/java/lang/ScopedValue.java

Print this page

141  * structured cases where child threads are started and terminate within the bounded
142  * period of execution by a parent thread. When using a {@link StructuredTaskScope},
143  * scoped value bindings are <em>captured</em> when creating a {@code StructuredTaskScope}
144  * and inherited by all threads started in that task scope with the
145  * {@link StructuredTaskScope#fork(java.util.concurrent.Callable) fork} method.
146  *
147  * <p> A {@code ScopedValue} that is shared across threads requires that the value be an
148  * immutable object or for all access to the value to be appropriately synchronized.
149  *
150  * <p> In the following example, the {@code ScopedValue} {@code NAME} is bound to the
151  * value "{@code duke}" for the execution of a runnable operation. The code in the {@code
152  * run} method creates a {@code StructuredTaskScope} that forks three tasks. Code executed
153  * directly or indirectly by these threads running {@code childTask1()}, {@code childTask2()},
154  * and {@code childTask3()} that invokes {@code NAME.get()} will read the value
155  * "{@code duke}".
156  *
157  * {@snippet lang=java :
158  *     private static final ScopedValue<String> NAME = ScopedValue.newInstance();
159 
160  *     ScopedValue.runWhere(NAME, "duke", () -> {
161  *         try (var scope = new StructuredTaskScope<String>()) {

162  *

163  *             scope.fork(() -> childTask1());
164  *             scope.fork(() -> childTask2());
165  *             scope.fork(() -> childTask3());
166  *
167  *             ...



168  *          }
169  *     });
170  * }
171  *
172  * <p> Unless otherwise specified, passing a {@code null} argument to a method in this
173  * class will cause a {@link NullPointerException} to be thrown.
174  *
175  * @apiNote
176  * A {@code ScopedValue} should be preferred over a {@link ThreadLocal} for cases where
177  * the goal is "one-way transmission" of data without using method parameters.  While a
178  * {@code ThreadLocal} can be used to pass data to a method without using method parameters,
179  * it does suffer from a number of issues:
180  * <ol>
181  *   <li> {@code ThreadLocal} does not prevent code in a faraway callee from {@linkplain
182  *   ThreadLocal#set(Object) setting} a new value.
183  *   <li> A {@code ThreadLocal} has an unbounded lifetime and thus continues to have a value
184  *   after a method completes, unless explicitly {@linkplain ThreadLocal#remove() removed}.
185  *   <li> {@linkplain InheritableThreadLocal Inheritance} is expensive - the map of
186  *   thread-locals to values must be copied when creating each child thread.
187  * </ol>

141  * structured cases where child threads are started and terminate within the bounded
142  * period of execution by a parent thread. When using a {@link StructuredTaskScope},
143  * scoped value bindings are <em>captured</em> when creating a {@code StructuredTaskScope}
144  * and inherited by all threads started in that task scope with the
145  * {@link StructuredTaskScope#fork(java.util.concurrent.Callable) fork} method.
146  *
147  * <p> A {@code ScopedValue} that is shared across threads requires that the value be an
148  * immutable object or for all access to the value to be appropriately synchronized.
149  *
150  * <p> In the following example, the {@code ScopedValue} {@code NAME} is bound to the
151  * value "{@code duke}" for the execution of a runnable operation. The code in the {@code
152  * run} method creates a {@code StructuredTaskScope} that forks three tasks. Code executed
153  * directly or indirectly by these threads running {@code childTask1()}, {@code childTask2()},
154  * and {@code childTask3()} that invokes {@code NAME.get()} will read the value
155  * "{@code duke}".
156  *
157  * {@snippet lang=java :
158  *     private static final ScopedValue<String> NAME = ScopedValue.newInstance();
159 
160  *     ScopedValue.runWhere(NAME, "duke", () -> {
161  *         // @link substring="open" target="StructuredTaskScope#open(Policy)" :
162  *         try (var scope = StructuredTaskScope.open(policy)) {
163  *
164  *             // @link substring="fork" target="StructuredTaskScope#fork(java.util.concurrent.Callable)" :
165  *             scope.fork(() -> childTask1());
166  *             scope.fork(() -> childTask2());
167  *             scope.fork(() -> childTask3());
168  *
169  *             ...
170  *
171  *             // @link substring="join" target="StructuredTaskScope#join()" :
172  *             var result = scope.join();
173  *          }
174  *     });
175  * }
176  *
177  * <p> Unless otherwise specified, passing a {@code null} argument to a method in this
178  * class will cause a {@link NullPointerException} to be thrown.
179  *
180  * @apiNote
181  * A {@code ScopedValue} should be preferred over a {@link ThreadLocal} for cases where
182  * the goal is "one-way transmission" of data without using method parameters.  While a
183  * {@code ThreadLocal} can be used to pass data to a method without using method parameters,
184  * it does suffer from a number of issues:
185  * <ol>
186  *   <li> {@code ThreadLocal} does not prevent code in a faraway callee from {@linkplain
187  *   ThreadLocal#set(Object) setting} a new value.
188  *   <li> A {@code ThreadLocal} has an unbounded lifetime and thus continues to have a value
189  *   after a method completes, unless explicitly {@linkplain ThreadLocal#remove() removed}.
190  *   <li> {@linkplain InheritableThreadLocal Inheritance} is expensive - the map of
191  *   thread-locals to values must be copied when creating each child thread.
192  * </ol>
< prev index next >