在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
开源软件名称:code-review-checklists/java-concurrency开源软件地址:https://github.com/code-review-checklists/java-concurrency开源编程语言:开源软件介绍:Code Review Checklist: Java ConcurrencyDesign
Documentation
Insufficient synchronization
Excessive thread safety
Race conditions
Testing
Locks
Avoiding deadlocks
Improving scalability
Lazy initialization and double-checked locking
Non-blocking and partially blocking code
Threads and Executors
Parallel Streams
Futures
Thread interruption and
Time
Thread safety of Cleaners and native code
Design# Dn.1. If the patch introduces a new subsystem (class, method) with concurrent code, is the necessity for concurrency or thread safety rationalized in the patch description? Is there a discussion of alternative design approaches that could simplify the concurrency model of the code (see the next item)? A way to nudge thinking about concurrency design is demanding the usage of concurrency tools and language constructs to be justified in comments. See also an item about unneeded thread-safety of classes and methods. # Dn.2. Is it possible to apply one or several design patterns (some of them are listed below) to significantly simplify the concurrency model of the code, while not considerably compromising other quality aspects, such as overall simplicity, efficiency, testability, extensibility, etc? Immutability/Snapshotting. When some state should be updated, a new immutable object (or a
snapshot within a mutable object) is created, published and used, while some concurrent threads may
still use older copies or snapshots. See [EJ Item 17], [JCIP 3.4], RC.5 and
NB.2, Divide and conquer. Work is split into several parts that are processed independently, each part
in a single thread. Then the results of processing are combined. Parallel
Streams or Producer-consumer. Pieces of work are transmitted between worker threads via queues. See [JCIP 5.3], Dl.1, CSP, SEDA. Instance confinement. Objects of some root type encapsulate some complex hierarchical child state. Root objects are solitarily responsible for the safety of accesses and modifications to the child state from multiple threads. In other words, composed objects are synchronized rather than synchronized objects are composed. See [JCIP 4.2, 10.1.3, 10.1.4]. RC.3, RC.4, and RC.5 describe race conditions that could happen to instance-confined state. TL.4 touches on instance confinement of thread-local state. Thread/Task/Serial thread confinement. Some state is made local to a thread using top-down
pass-through parameters or Active object. An object manages its own Documentation
# Dc.1. For every class, method, and field that has signs of being thread-safe,
such as the
Wherever some logic is parallelized or the execution is delegated to another thread, are there comments explaining why it’s worse or inappropriate to execute the logic sequentially or in the same thread? See PS.1 regarding this. See also NB.3 and NB.4 regarding justification of non-blocking code, racy code, and busy waiting. If the usage of concurrency tools is not justified, there is a possibility of code ending up with
unnecessary thread-safety, redundant atomics,
redundant
# Dc.2. If the patch introduces a new subsystem that uses threads or thread
pools, are there high-level descriptions of the threading model, the concurrent control flow (or
the data flow) of the subsystem somewhere, e. g. in the Javadoc comment for the package in
Description of the threading model includes the enumeration of threads and thread pools created and
managed in the subsystem, and external pools used in the subsystem (such as
A high-level description of concurrent control flow should be an overview and tie together concurrent control flow documentation for individual classes, see the previous item. If the producer-consumer pattern is used, the concurrent control flow is trivial and the data flow should be documented instead. Describing threading models and control/data flow greatly improves the maintainability of the system, because in the absence of descriptions or diagrams developers spend a lot of time and effort to create and refresh these models in their minds. Putting the models down also helps to discover bottlenecks and the ways to simplify the design (see Dn.2). # Dc.3. For classes and methods that are parts of the public API or the extensions API of the project: is it specified in their Javadoc comments whether they are (or in case of interfaces and abstract classes designed for subclassing in extensions, should they be implemented as) immutable, thread-safe, or not thread-safe? For classes and methods that are (or should be implemented as) thread-safe, is it documented precisely with what other methods (or themselves) they may be called concurrently from multiple threads? See also [EJ Item 82], [JCIP 4.5], CON52-J. If the # Dc.4. For subsystems, classes, methods, and fields that use some concurrency design patterns, either high-level, such as those mentioned in Dn.2, or low-level, such as double-checked locking or spin looping: are the used concurrency patterns pronounced in the design or implementation comments for the respective subsystems, classes, methods, and fields? This helps readers to make sense out of the code quicker. Pronouncing the used patterns in comments may be replaced with more succinct documentation
annotations, such as
# Dc.5. Are This is important, because in code like the following:
It should be pretty obvious that there might be a race condition because an entity may be put into
the map by a concurrent thread between the calls to It’s possible to turn this advice into an inspection in IntelliJ IDEA.
# Dc.6. An extension of the previous item: are ConcurrentHashMaps on which This advice may seem to be overly pedantic, but if used in conjunction with a static analysis rule
that prohibits calling
# Dc.7. Is See [JCIP 2.4] for more information about Usage of # Dc.8. If in a thread-safe class some fields are accessed both from within critical sections and outside of critical sections, is it explained in comments why this is safe? For example, unprotected read-only access to a reference to an immutable object might be benignly racy (see RC.5). Answering this question also helps to prevent problems described in IS.2, IS.3, and RC.2. Instead of writing a comment explaining that access to a lazily initialized field outside of a
critical section is safe, the field could just be annotated with Apart from the explanations why the partially blocking or racy code is safe, there should also be comments justifying such error-prone code and warning the developers that the code should be modified and reviewed with double attention: see NB.3. There is an inspection "Field accessed in both synchronized and unsynchronized contexts" in IntelliJ IDEA which helps to find classes with unbalanced synchronization.
# Dc.9. Regarding every field with a Similarly to what is noted in the previous item, justification for a lazily initialized field to be
By extension, this item also applies when an
# Dc.10. Is it explained in the Javadoc comment for each mutable field in a
thread-safe class that is neither Insufficient synchronization
# IS.1. Can non-private static methods be called concurrently from multiple
threads? If there is a non-private static field with mutable state, such as a collection, is it an
instance of a thread-safe class or synchronized using some Note that calls to
# IS.2. There is no situation where some thread awaits until a
non-volatile field has a certain value in a loop, expecting it to be updated from another thread?
The field should at least be Even if the respective field is Dc.10 also demands adding explaining comments to mutable fields which are neither
# IS.3. Read accesses to non-volatile primitive fields which can be
updated concurrently are protected with a lock as well as the writes? The minimum reason for this
is that reads of As well as with the previous item, accurate documentation of benign races (Dc.8 and Dc.10) should reliably expose the cases when unbalanced synchronization is problematic. See also RC.2 regarding unbalanced synchronization of read accesses to mutable objects, such as collections. There is a relevant inspection "Field accessed in both synchronized and unsynchronized contexts" in IntelliJ IDEA. # IS.4. Is the business logic written for server frameworks thread-safe? This includes:
It's easy to forget that if such code mutates some state (e. g. fields in the class), it must be properly synchronized or access only concurrent collections and classes.
# IS.5. Calls to An inspection "Non thread-safe static field access" in IntelliJ IDEA helps to catch such concurrency bugs. Excessive thread safety
# ETS.1. An example of excessive thread safety is a class where every modifiable
field is There shouldn’t be any "extra" thread safety in code, there should be just enough of it. Duplication of thread safety confuses readers because they might think the extra thread safety precautions are (or used to be) needed for something but will fail to find the purpose. The exception from this principle is the See also the section about double-checked locking.
# ETS.2. Aren’t there # ETS.3. Does a class (method) need to be thread-safe? May a class be accessed (method called) concurrently from multiple threads (without happens-before relationships between the accesses or calls)? Can a class (method) be simplified by making it non-thread-safe? See also Ft.1 about unneeded wrapping of a computation into a This item is a close relative of Dn.1 (about rationalizing concurrency and thread safety in the patch description) and Dc.1 (about justifying concurrency in Javadocs for classes and methods, and documenting concurrent access). If these actions are done, it should be self-evident whether the class (method) needs to be thread-safe or not. There may be cases, however, when it might be desirable to make the class (method) thread-safe although it's not supposed to be accessed or called concurrently as of the moment of the patch. For example, thread safety may be needed to ensure memory safety (see CN.4 about this). Anticipating some changes to the codebase that make the class (method) being accessed from multiple threads may be another reason to make the class (method) thread-safe up front.
# ETS.4. Does a Race conditions
# RC.1. Aren’t
# RC.2. Aren’t there point read accesses such as The problem is that when new entries can be added to a collection, it grows and changes its internal
structure from time to time (HashMap rehashes the hash table, Note that this concern applies to See also IS.3 regarding unbalanced synchronization of accesses to primitive fields.
# RC.3. A variation of the previous item: isn’t a non-thread-safe
collection such as Note that calling Like the previous item, this one applies to growing ArrayLists too. This item applies even to synchronized collections: see RC.10 for details. # RC.4. Generalization of the previous item: aren’t non-trivial objects that can be mutated concurrently returned from getters in a thread-safe class (and thus inevitably leaking outside of critical sections)?
# RC.5. If there are multiple variables in a thread-safe class that are
updated at once but have individual getters, isn’t there a race condition in the code that calls
those getters? If there is, the variables should be made This pattern is also very useful for creating safe and reasonably simple non-blocking code: see NB.2 and [JCIP 15.3.1]. # RC.6. If some logic within some critical section depends on some data that principally is part of the internal mutable state of the class, but was read outside of the critical section or in a different critical section, isn’t there a race condition because the local copy of the data may become out of sync with the internal state by the time when the critical section is entered? This is a typical variant of check-then-act race condition, see [JCIP 2.2.1]. An example of this race condition is calling list = Collections.synchronizedList(new ArrayList<>());
...
elements = list.toArray(new Element[list.size()]); This might unexpectedly leave the See also RC.9 about cache invalidation races which are similar to check-then-act races. # RC.7. Aren't there race conditions between the code (i. e. program runtime actions) and some actions in the outside world or actions performed by some other programs running on the machine? For example, if some configurations or credentials are hot reloaded from some file or external registry, reading separate configuration parameters or separate credentials (such as username and password) in separate transactions with the file or the registry may be racing with a system operator updating those configurations or credentials. Another example is checking that a file exists (or not exists) and then reading, deleting, or
creating it, respectively, while another program or a user may delete or create the file between the
check and the act. It's not always possible to cope with such race conditions, but it's useful to
keep such possibilities in mind. Prefer static methods from
# RC.8. If you are using Guava Cache and # RC.9. Generalization of the previous item: isn't there a potential cache invalidation race in the code? There are several ways to get into this problem:
# RC.10. The whole iteration loop over a synchronized collection
(i. e. obtained from one of the This also applies to passing synchronized collections into:
Because in all these cases there is an implicit iteration on the source collection. See also RC.3 about unprotected iteration over non-thread-safe collections. Testing# T.1. Was it considered to add multi-threaded unit tests for a thread-safe class or method? Single-threaded tests don't really test the thread safety and concurrency. Note that this question doesn't mean to indicate that there must be concurrent unit tests for every piece of concurrent code in the project because correct concurrent tests take a lot of effort to write and therefore they might often have low ROI. What is the worst thing that might happen if this code has a concurrency bug? This is a useful question to inform the decision about writing concurrent tests. The consequences may range from a tiny, entirely undetectable memory leak, to storing corrupted data in a durable database or a security breach.
# T.2. Isn't a shared
# T.3. Do concurrent test workers coordinate their start using a latch
such as
# T.4. Are there more test threads than there are available
processors if possible for the test? This will help to generate more thread scheduling
interleavings and thus test the logic for the absence of race conditions more thoroughly. See
[JCIP 12.1.6] for more information. The number of available processors on the machine can be
obtained as # T.5. Are there no regular assertions in code that is executed not in the main thread running the unit test? Consider the following example: |
2023-10-27
2022-08-15
2022-08-17
2022-09-23
2022-08-13
请发表评论