@@ -128,6 +128,8 @@ Non-blocking and partially blocking code
128128 ] ( #swap-state-atomically )
129129 - [ Boundaries of non-blocking or benignly racy code are identified with WARNING comments?
130130 ] ( #non-blocking-warning )
131+ - [ Busy waiting (spin loop), all calls to ` Thread.yield() ` and ` Thread.onSpinWait() ` are justified?
132+ ] ( #justify-busy-wait )
131133
132134Threads and Executors
133135 - [ Thread is named?] ( #name-threads )
@@ -145,7 +147,6 @@ Threads and Executors
145147 - the future is completed and the callback is attached from the same thread pool?
146148 - [ Adding a callback to a ` CompletableFuture ` (` SettableFuture ` ) in non-async mode is justified?
147149 ] ( #cf-beware-non-async )
148- - [ Is ` Thread.sleep() ` usage in spin-wait loop justified?] ( #thread-sleep )
149150
150151Parallel Streams
151152 - [ Parallel Stream computation takes more than 100us in total?] ( #justify-parallel-stream-use )
@@ -245,7 +246,8 @@ Wherever some logic is parallelized or the execution is delegated to another thr
245246comments explaining why it’s worse or inappropriate to execute the logic sequentially or in the same
246247thread? See [ PS.1] ( #justify-parallel-stream-use ) regarding this.
247248
248- See also [ NB.3] ( #non-blocking-warning ) regarding justification of non-blocking and racy code.
249+ See also [ NB.3] ( #non-blocking-warning ) and [ NB.4] ( #justify-busy-wait ) regarding justification of
250+ non-blocking code, racy code, and busy waiting.
249251
250252<a name =" threading-flow-model " ></a >
251253[ #] ( #threading-flow-model ) Dc.2. If the patch introduces a new subsystem that uses threads or thread
@@ -286,10 +288,10 @@ pattern](https://errorprone.info/bugpattern/Immutable)).
286288
287289<a name =" name-patterns " ></a >
288290[ #] ( #name-patterns ) Dc.4. For subsystems, classes, methods, and fields that use some concurrency
289- design patterns, either high-level ( such as those mentioned in [ Dn.2] ( #use-patterns ) ) or low-level
290- ( such as double-checked locking, see [ the relevant section ] ( #lazy-init ) ) : are the used ** concurrency
291- patterns pronounced in the design or implementation comments** for the respective subsystems,
292- classes, methods, and fields? This helps readers to make sense out of the code quicker.
291+ design patterns, either high-level, such as those mentioned in [ Dn.2] ( #use-patterns ) , or low-level,
292+ such as [ double-checked locking] ( #lazy-init ) or [ spin looping ] ( #justify-busy-wait ) : are the used
293+ ** concurrency patterns pronounced in the design or implementation comments** for the respective
294+ subsystems, classes, methods, and fields? This helps readers to make sense out of the code quicker.
293295
294296Pronouncing the used patterns in comments may be replaced with more succinct documentation
295297annotations, such as ` @Immutable ` ([ Dc.3] ( #immutable-thread-safe ) ), ` @GuardedBy `
@@ -417,6 +419,9 @@ The field should at least be `volatile` to ensure eventual visibility of concurr
417419https://wiki.sei.cmu.edu/confluence/display/java/VNA00-J.+Ensure+visibility+when+accessing+shared+primitive+variables )
418420for more details and examples.
419421
422+ Even if the respective field if ` volatile ` , busy waiting for a condition in a loop can be abused
423+ easily and therefore should be justified in a comment: see [ NB.4] ( #justify-busy-wait ) .
424+
420425[ Dc.10] ( #plain-field ) also demands adding explaining comments to mutable fields which are neither
421426` volatile ` nor annotated with ` @GuardedBy ` which should inevitably lead to the discovery of the
422427visibility issue.
@@ -1058,6 +1063,46 @@ blocking code, and benignly racy code (see [Dc.8](#document-benign-race) and
10581063 2 . ** Warn developers that changes in the following code should be made (and reviewed) extremely
10591064 carefully.**
10601065
1066+ <a name =" justify-busy-wait " ></a >
1067+ [ #] ( #justify-busy-wait ) NB.4. If some condition is awaited in a (busy) loop, like in the following
1068+ example:
1069+ ``` java
1070+ volatile boolean condition;
1071+
1072+ // in some method:
1073+ while (! condition) {
1074+ // Or Thread.sleep/yield/onSpinWait, or no statement, i. e. a pure spin wait
1075+ TimeUnit . SECONDS. sleep(1L );
1076+ }
1077+ // ... do something when condition is true
1078+ ```
1079+ ** Is it explained in a comment why busy waiting is needed in the specific case** , and why the
1080+ costs and potential problems associated with busy waiting (see [ JCIP 12.4.2] and [ JCIP 14.1.1] )
1081+ either don't apply in the specific case or are outweighed by the benefits?
1082+
1083+ If there is no good reason for spin waiting, it's preferable to synchronize explicitly using a tool
1084+ such as [ ` Semaphore ` ] (
1085+ https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/concurrent/Semaphore.html ),
1086+ [ ` CountDownLatch ` ] (
1087+ https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/concurrent/CountDownLatch.html
1088+ ), or [ ` Exchanger ` ] (
1089+ https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/concurrent/Exchanger.html ),
1090+ or if the logic for which the spin loop awaits is executed in some ` ExecutorService ` , it's better to
1091+ add a callback to the corresponding ` CompletableFuture ` or [ ` ListenableFuture ` ] (
1092+ https://github.com/google/guava/wiki/ListenableFutureExplained ) (check [ TE.7] ( #cf-beware-non-async )
1093+ about doing this properly).
1094+
1095+ Since ` Thread.yield() ` and ` Thread.onSpinWait() ` are rarely, if ever, useful outside of spin loops,
1096+ this item could also be interpreted as that there should be a comment to every call to either of
1097+ these methods, explaining either why they are called outside of a spin loop, or justifying the spin
1098+ loop itself.
1099+
1100+ In any case, the field checked in the busy loop must be ` volatile ` : see
1101+ [ IS.2] ( #non-volatile-visibility ) for details.
1102+
1103+ The busy wait pattern is covered by IntelliJ IDEA's inspections "Busy wait" and "while loop spins on
1104+ field".
1105+
10611106### Threads and Executors
10621107
10631108<a name =" name-threads " ></a >
@@ -1171,37 +1216,6 @@ See also the Javadoc for [`ListenableFuture.addListener()`](
11711216https://guava.dev/releases/28.1-jre/api/docs/com/google/common/util/concurrent/ListenableFuture.html#addListener-java.lang.Runnable-java.util.concurrent.Executor-
11721217) describing this problem.
11731218
1174- <a name =" thread-sleep " ></a >
1175- [ #] ( #thread-sleep ) TE.8. Developers often use busy-wait pattern like
1176- ``` java
1177- class EventHandler {
1178- volatile boolean eventNotificationNotReceived;
1179-
1180- void waitForEventAndHandleIt () {
1181- while (eventNotificationNotReceived) {
1182- Thread . sleep(TimeUnit . SECONDS. toMillis(1L ));
1183- }
1184- readAndProcessEvent();
1185- }
1186-
1187- void readAndProcessEvent () {
1188- // Read event from some source and process it
1189- }
1190- }
1191- ```
1192- If there is a busy wait loop, is it explained in a comment why it's needed in the specific case,
1193- and that the costs and potential problems associated with busy waiting either don't apply in the specific case,
1194- or are outweighed by the benefits?
1195-
1196- Pay attention that ` Thread.sleep() ` ** in certain cases** could be replaced with:
1197- - synchronization primitive (like ` Semaphore ` )
1198- - ` Object.wait() ` /` Object.notify() `
1199- - ` Thread.yield() `
1200- - ` Thread.onSpinWait() `
1201-
1202- The mentioned pattern is covered by IDEA's inspection "Busy wait" which is currently off by default.
1203- It will be on by default when [ IDEA-226838] ( https://youtrack.jetbrains.com/issue/IDEA-226838 ) is fixed.
1204-
12051219### Parallel Streams
12061220
12071221<a name =" justify-parallel-stream-use " ></a >
0 commit comments