|
18 | 18 | - [Extension API call within a critical section](#non-open-call)
|
19 | 19 | - [Large critical section](#minimize-critical-sections)
|
20 | 20 | - [Waiting in a loop for some result](#justify-busy-wait)
|
21 |
| - - [`ThreadLocal`, especially when non-static](#threadlocal-design) |
| 21 | + - [Non-static `ThreadLocal`](#threadlocal-design) |
22 | 22 | - [`Thread.sleep()`](#no-sleep-schedule)
|
23 | 23 |
|
24 | 24 | Documentation
|
@@ -62,7 +62,7 @@ Race conditions
|
62 | 62 | ](#unsafe-concurrent-iteration)
|
63 | 63 | - [A non-thread-safe collection is *not* returned wrapped in `Collections.unmodifiable*()` from
|
64 | 64 | a getter in a thread-safe class?](#unsafe-concurrent-iteration)
|
65 |
| - - [Non-trivial object is *not* returned from a getter in a thread-safe class? |
| 65 | + - [Non-trivial mutable object is *not* returned from a getter in a thread-safe class? |
66 | 66 | ](#concurrent-mutation-race)
|
67 | 67 | - [No separate getters to an atomically updated state?](#moving-state-race)
|
68 | 68 | - [No *check-then-act* race conditions (state used inside a critical section is read outside of
|
@@ -250,11 +250,14 @@ https://en.wikipedia.org/wiki/Staged_event-driven_architecture).
|
250 | 250 | **Instance confinement.** Objects of some root type encapsulate some complex hierarchical child
|
251 | 251 | state. Root objects are solitarily responsible for the safety of accesses and modifications to the
|
252 | 252 | child state from multiple threads. In other words, composed objects are synchronized rather than
|
253 |
| -synchronized objects are composed. See [JCIP 4.2, 10.1.3, 10.1.4]. [TL.4](#tl-instance-chm) touches |
254 |
| -on instance confinement of thread-local state. |
| 253 | +synchronized objects are composed. See [JCIP 4.2, 10.1.3, 10.1.4]. |
| 254 | +[RC.3](#unsafe-concurrent-iteration), [RC.4](#concurrent-mutation-race), and |
| 255 | +[RC.5](#moving-state-race) describe race conditions that could happen to instance-confined state. |
| 256 | +[TL.4](#tl-instance-chm) touches on instance confinement of thread-local state. |
255 | 257 |
|
256 | 258 | **Thread/Task/Serial thread confinement.** Some state is made local to a thread using top-down
|
257 |
| -pass-through parameters or `ThreadLocal`. See [JCIP 3.3]. Task confinement is a variation of the |
| 259 | +pass-through parameters or `ThreadLocal`. See [JCIP 3.3] and [the checklist section about |
| 260 | +ThreadLocals](#threadlocal). Task confinement is a variation of the |
258 | 261 | idea of thread confinement that is used in conjunction with the divide-and-conquer pattern. It
|
259 | 262 | usually comes in the form of lambda-captured "context" parameters or fields in the per-thread task
|
260 | 263 | objects. Serial thread confinement is an extension of the idea of thread confinement for the
|
@@ -1395,7 +1398,9 @@ Future<Response> makeQuery(String query) {
|
1395 | 1398 | } catch (InvalidQueryException e) {
|
1396 | 1399 | // Explicit catch preserves the semantics of the original version of makeQuery() most closely.
|
1397 | 1400 | // If compile(query) is an expensive computation, it may be undesirable to schedule it to
|
1398 |
| - // someBlockingIoExecutor() by simply moving compile(query) into the lambda below. |
| 1401 | + // someBlockingIoExecutor() by simply moving compile(query) into the lambda below because if |
| 1402 | + // this pool has more threads than CPUs then too many compilations might be started in parallel, |
| 1403 | + // leading to excessive switches between threads running CPU-bound tasks. |
1399 | 1404 | // Another alternative is scheduling compile(query) to the common FJP:
|
1400 | 1405 | // CompletableFuture.supplyAsync(() -> compile(query))
|
1401 | 1406 | // .thenApplyAsync(service::remoteCall, someBlockingIoExecutor());
|
|
0 commit comments