You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: java-25/README.md
+133Lines changed: 133 additions & 0 deletions
Original file line number
Diff line number
Diff line change
@@ -26,6 +26,139 @@ To run each example use: `java --enable-preview --source 25 <FileName.java>`
26
26
27
27
***Primitive Types in Patterns, instance of and switch**
28
28
* re-preview without change
29
+
***Structured Concurrency**
30
+
* re-preview with several API changes
31
+
* previous changes in [JDK 19](../java-19/README.md) and [JDK 21](../java-21/README.md)
32
+
* Joiners
33
+
* introduce the concept of execution policy with `Joiner`
34
+
* Joiner object handles subtask completion and produces the outcome for the `join()` method
35
+
* depending on the joiner, the `join()` method may return a result, a stream of elements, or some other object
36
+
* the result of `join()` is useful when we don't handle each subtask individually, rather we want to wait for all subtasks to finish and then process the results (first result or all)
37
+
* a joiner instance should never be reused, always create a new instance
38
+
*`StructuredTaskScope` is open using static factory methods:
39
+
*`StructuredTaskScope.open()`: creates a scope with joiner strategy default of `StructuredTaskScope.Joiner.allSuccessfulOrThrow()` but `join()` will return null
40
+
*`StructuredTaskScope.open(StructuredTaskScope.Joiner)`: creates a scope with the specified joiner strategy
41
+
*`StructuredTaskScope.open(StructuredTaskScope.Joiner, Function)`: creates a scope with the specified joiner strategy and a function to customize the default configuration of the execution (name, thread factory and timeout)
42
+
* the scope can now be configured with a instace of [`Config`](https://download.java.net/java/early_access/loom/docs/api/java.base/java/util/concurrent/StructuredTaskScope.Config.html)
43
+
*`withName(String)`: sets the name of the scope to be monitored and managed
44
+
*`withThreadFactory(ThreadFactory)`: sets the thread factory to use for each subtask
45
+
*`withTimeout(Duration)`: sets the timeout for the scope, should use `Instant` to calculates the deadline (`Duration.between(Instant.now(), deadline)`)
46
+
*`Joiner` interface declares factory methods to create joiners for some common cases
47
+
* interface:
48
+
```java
49
+
public interface Joiner<T, R> {
50
+
public default boolean onFork(Subtask<? extends T> subtask);
51
+
public default boolean onComplete(Subtask<? extends T> subtask);
52
+
public R result() throws Throwable;
53
+
}
54
+
```
55
+
* factory methods for default policies:
56
+
*`allSuccessfulOrThrow`:
57
+
* waits for all tasks to complete successfully or throws an exception if any subtask fails
58
+
* `join()` will return a stream of `Subtask` that yields the subtask results in the order they are completed
59
+
* useful when all subtasks return a result of same type and we want to process them all
60
+
*`anySuccessfulResultOrThrow`:
61
+
* waits for any subtask to complete successfully or throws an exception if all tasks fail
62
+
*`join()` will return the result of a successful subtask
63
+
* useful when we want to process the result of the first successful subtask
64
+
*`awaitAllSuccessfulOrThrow()`:
65
+
* waits for all tasks to complete successfully or throws an exception if any subtask fails
66
+
*`join()` returns `Void`
67
+
* useful when the subtasks return a result of different types and we process each subtask submitted with `fork` method individually
68
+
*`awaitAll`:
69
+
* waits for all tasks to complete, regardless of success or failure
70
+
*`join()` returns `Void`
71
+
* useful when the subtasks make use of side effects operations and don't return a result or exception
72
+
* each subtask will yield the result or exception of its execution
73
+
*`allUntil(Predicate)`
74
+
* waits all subtasks are completed or the predicate is satisfied to cancel the scope
75
+
*`join()` returns stream of all subtasks in the order they were forked
76
+
* each subtask can have the following states: `SUCCESS`, `FAILURE` or `UNAVAILABLE` (if the scope has been cancelled before it were forked or completed)
77
+
* predicate is of type [`Predicate<StructuredTaskScope.Subtask<? extends T>>`](https://download.java.net/java/early_access/loom/docs/api/java.base/java/util/function/Predicate.html)
78
+
* each subtask that is completed successfully or failed will be passed to the predicate
79
+
* if the predicate returns true, the scope will be cancelled
80
+
* if throws an exception, `Thread.UncaughtExceptionHandler.uncaughtException` will be called
81
+
* we can implement our own joiner by implementing the interface `StructuredTaskScope.Joiner`
82
+
* we can implement the method `join` to return a result of type `R` and the method `onCompletion` to handle the completion of each subtask
83
+
* change in thread-dump to show virtual threads used by a `StructuredTaskScope`
* `ScopedValue.orElse` method no longer accepts null as its argument
88
+
* enable the sharing of immutable data within a thread and its child threads
89
+
* it were inspired by the way that Lisp dialects provide support for dyanamically scoped free variables
90
+
* they are preferred to thread-local variables (specially when using virtual threads)
91
+
* goals:
92
+
* provide a programming model to share data both within a thread and with child threads
93
+
* make the lifetime of shared data visible from structure of code
94
+
* ensure that data shared by a caller can be retrieved only by legitimate callees
95
+
* thread shared data as immuatable so as to allow sharing by a large number of threads and to enable runtime otimiziations
96
+
* problems with thread-local variables:
97
+
* mutability: any object can update the variable if it has access to it
98
+
* unbounded lifetime: it is stored until the thread is destroyed, if is used in a pool it can take a long time
99
+
* expensive inheritance: a child thread must allocate memory for every variable stored in the parent thread
100
+
* a scoped value allows data to be safely and efficiently shared between threads within same hierarchy
101
+
*`scoped value is a container object that allows a data value to be safely and efficiently shared by a method with its direct and indirect callees within the same thread, and with child threads, without resorting to method parameters`
102
+
* ScopedValue API works by executing a method with a `ScopedValue` object bound to some value for the bounded period of execution of a method
103
+
* we use an attribute of type [`ScopedValue`](https://download.java.net/java/early_access/loom/docs/api/java.base/java/lang/ScopedValue.html) declared as final static
104
+
* scoped value has multiple values associated with it, one per thread
105
+
* once the value is written to scoped value it becomes immutable and is available only for a bounded period during execution of that thread insided that scope
106
+
* we can create another scope when inside a scope with another variable to create a new scope
107
+
* we can create nested scope with rebinded value when using the same `ScopedValue` to create a new scope
108
+
* the created scope will have the new value binded
109
+
* the current scope will still have its original value
110
+
* usage:
111
+
* first we need to create a scope key
112
+
* `private static final ScopedValue<String> SCOPE_KEY = ScopedValue.newInstance();`
113
+
* then we use `ScopedValue.where` to bind a value to the scope key
114
+
*`ScopedValue.where(SCOPE_KEY, "my-value")`
115
+
* if we bind a value to a scope key that is already bound, the new value will be used in the current scope (rebinding)
116
+
* we can set multiples values to the same scope by using the same `ScopedValue` in multiple calls to `where`
var userRole =ScopedValue.where(PRINCIPAL, "guest")
142
+
.call(() -> {
143
+
return"Value: "+PRINCIPAL.get();
144
+
});
145
+
```
146
+
* ex.:
147
+
*
148
+
```java
149
+
var universeAnswer =ScopedValue.where(SUBJECT, "Deep Thought")
150
+
.call(() -> {
151
+
// some magic
152
+
return42;
153
+
});
154
+
```
155
+
* virtual thread and cross-thread sharing
156
+
* to share data between a thread and its child thread we need to make the scoped values inherited by child thread
157
+
* we can use the StructuredConcurrencyAPI
158
+
* the class `StructuredTaskScope` automatically make the scoped value inherited by child thread
159
+
* the fork must occurrs inside the `ScopedValue` method `run`/`call`
160
+
* the binding will remains until the child thread are finished and we can use `StructuredTaskScoped.join` to ensure that the child threads will terminate before `run`/`call`
161
+
* when we try to access a scoped value not shared with current thread an exception `NoSuchElementException` will be thrown
0 commit comments