The Java language annotation facility for annotation is useful for documenting programmer design intent about the concurrency properties of code. Annotation . Source code annotation is a mechanism for associating a meta-tag metadata with a program element and allowing making it available to the compiler, tools, or the VM to examine itanalyzers, debuggers, or Java Virtual Machine (JVM) for examination. Several annotations are available to help with the documentation of for documenting thread-safety , or the lack thereof, of Java code.
Obtaining Concurrency Annotations
Wiki Markup |
---|
There are two sets of concurrency annotations that are freely available and licensed for use in any code. The first is the four annotations described in _Java Concurrency in Practice_ (JCIP hereafter) \[[Goetz 06|AA. Java References#Goetz 06]\] which can be downloaded from [jcip.net|http://www.jcip.net] ([jar|http://jcip.net/jcip-annotations.jar], [javadoc|http://jcip.net/annotations/doc/index.html], [source|http://jcip.net/jcip-annotations-src.jar]). The JCIP annotations are released under the [Creative Commons Attribution License|http://creativecommons.org/licenses/by/2.5]. |
Two sets of concurrency annotations are freely available and licensed for use in any code. The first set consists of four annotations described in Java Concurrency in Practice (JCIP) [Goetz 2006], which can be downloaded from jcip.net (jar, javadoc, source). The JCIP annotations are released under the Creative Commons Attribution License.
The second, larger The second, larger, set of concurrency annotations is available from and supported by SureLogic. The SureLogic These annotations are released under the The Apache Software License, Version 2.0 and can be downloaded from via the Internet Archive at surelogic.com (jar, javadoc, source). These The annotations can be verified by the SureLogic JSure tool but are , and they remain useful for documenting code documentation purposes without even when the tool is unavailable. The SureLogic These annotations include the JCIP annotations because they are also supported by the JSure tool. (the tool JSure also supports use of the JCIP Jar directly as well).JAR file.)
To use the annotations, download and add one or both of the above Jar aforementioned JAR files to your the code's build path. The use of these annotations to document thread-safety is described belowis descr
Warning | ||
---|---|---|
| ||
These examples are based on SureLogic, as of 2010. The intent is still useful but the implementation is no longer supported. We recommend using an annotation package that still enjoys active support. |
Documenting Intended Thread-
...
Safety
JCIP provides three class-level annotations to describe the programmer's design intent with respect to thread-safety.
The @ThreadSafe
annotation is applied to a class to indicate that the class it is thread-safe. This means that no sequences of accesses (reads and writes to public fields, calls to public methods) may put can leave the object into in an invalid inconsistent state, regardless of the interleaving of those actions these accesses by the runtime , and without requiring any additional or any external synchronization or coordination on the part of the caller.
For example, the following Aircraft
class shown below declares specifies that it is thread-safe as part of its lock locking policy documentation. This class protects the x
and y
fields using a ReentrantLock
reentrant lock.
Code Block | ||
---|---|---|
| ||
@ThreadSafe @Region("private AircraftState") @RegionLock("StateLock is stateLock protects AircraftState") public final class Aircraft { private final Lock stateLock = new ReentrantLock(); // ... @InRegion("AircraftState") private long x, y; // ... public void setPosition(long x, long y) { stateLock.lock(); try { this.x = x; this.y = y; } finally { stateLock.unlock(); } } // ... } |
The @Region
and @RegionLock
annotations (described below) document the precise locking policy that upon which the promise of thread-safety is predicated upon.
Even if when one or more @RegionLock
or @GuardedBy
annotations has have been made used to document the locking policy of a class this annotation can help to clarify that the overall , the @ThreadSafe
annotation provides an intuitive way for reviewers to learn that the class is thread-safe.
The @Immutable
The class to which this annotation is applied is to immutable. This means that its state cannot be seen to change by callers, which implies that (1) all public fields are final, (2) all public final reference fields refer to other immutable objects, and (3) constructors and methods do not publish references to any internal state which is potentially mutable by the implementation. Immutable objects may still have internal mutable state for purposes of performance optimization; some state variables may be lazily computed, provided they are computed from immutable state and that callers cannot tell the difference. Immutable objects are classes. Immutable objects are inherently thread-safe; once they are fully constructed, they may be passed between threads or published without synchronization.published via a reference and shared safely among multiple threads.
The following example shows an immutable Point
class:For example, the immutable Point
class below is considered thread-safe.
Code Block | ||
---|---|---|
| ||
@Immutable public final class Point { private final int f_x; private final int f_y; public Point(int x, int y) { f_x = x; f_y = y; } public int getX() { return f_x; } public int getY() { return f_y; } } |
According to Joshua Bloch [Bloch 2008],
It is not necessary to document the immutability of
enum
types. Unless it is obvious from the return type, static factories must document the thread safety of the returned object, as demonstrated byCollections.synchronizedMap
.
The @NotThreadSafe
annotation is applied to classes that are not thread-safe. Many classes fail to document whether they are safe for multithreaded use. Consequently, a programmer has no easy way to determine whether the class is thread-safe. This annotation provides clear indication of the class's lack of thread-safety@NotThreadSafe The class to which this annotation is applied is not thread-safe. This annotation primarily exists for clarifying the non-thread-safety of a class that might otherwise be assumed to be thread-safe, despite the fact that it is a bad idea to assume a class is thread-safe without good reason.
For example, most of the collection implementations provided in java.util
are not thread-safe. This could be documented for The class java.util.ArrayList
, for example, as shown below. could document this as follows:
Code Block | ||
---|---|---|
| ||
package java.util.ArrayList; @NotThreadSafe public class ArrayListArrayList<E> extends ... { // ... } |
Documenting
...
Locking Policies
It is important to document all the locks that are being used to protect shared state. According to Brian Goetz and colleagues [Goetz 2006], On page 28 of _Java Concurrency in Practice_ \[[Goetz 06|AA. Java References#Goetz 06]\], Goetz states: Wiki Markup
For each mutable state variable that may be accessed by more than one thread, all accesses to that variable must be preformed performed with the same lock headheld. In this case, we say that the variable is guarded by that lock. (p. 28)
Therefore, it is important to document which lock is used to protect each shared, mutable variable. JCIP provides the @GuardedBy
annotation for this purpose while , and SureLogic provides the @RegionLock
annotation. The use of both annotations is discussed in this section. @GuardedBy The field or method to which this the @GuardedBy
annotation is applied can only be accessed only when holding a particular lock, which . It may be a built-in (synchronization) lock, or may be an explicit an intrinsic lock or a dynamic lock such as java.util.concurrent.Lock
.
For example, the following MovablePoint
class implements a movable point with a capability to remember (that is, memo) that can remember its past locations .using the memo
array list:
Code Block | ||
---|---|---|
| ||
@ThreadSafe public final class MovablePoint { @GuardedBy("this") double xPos = 1.0; @GuardedBy("this") double yPos = 1.0; @GuardedBy("itself") static final ListList<MovablePoint> memo = new ArrayListArrayList<MovablePoint>(); public void move(double slope, double distance) { synchronized (this) { xPos =rememberPoint(this); xPos += ((1 / slope) * distance); yPos += yPos + (slope * distance); } } public static void memorememberPoint(ex1MovablePoint value) { synchronized (memo) { memo.add(value); } } } |
The @GuardedBy
annotations on the xPos
and yPos
fields indicate that access to these fields is protected by holding a lock on this
(as is done in the move
method which mutates these fields). The . The move()
method also synchronizes on this
, which modifies these fields. The @GuardedBy
annotation on the memo
list indicates that a lock on the ArrayList
object protects its contents (as is done in the memo
method).. The rememberPoint()
method also synchronizes on the memo
list.
One issue with the A problem with the @GuardedBy
annotation is that it does not make it clear that fails to indicate when there is a relationship between the two fields in the example abovefields of a class. This limitation can be overcome by using the SureLogic @RegionLock
which we now discuss.@RegionLock Declares annotation, which declares a new region lock for the class to which this annotation is applied. This declaration creates a new named lock that associates a particular lock object with a region of the class. The region may only be accessed only when the lock is held. For example, the SimpleLock
locking policy indicates that synchronizing on the instance protects the all of the instance's state.its state:
Code Block | ||
---|---|---|
| ||
@RegionLock("SimpleLock is this protects Instance")
class Simple { ... }
|
Unlike the use of @GuardedBy
, the @RegionLock
annotation allows the program programmer to give an explicit, and hopefully meaningful, name to the locking policy.
In addition to naming the locking policy, the @Region
annotation allows a name to be given to the region of the state that is being protected. This That name makes it clear that the state belongs together with respect to the and locking policy . This is demonstrated in the examples below.A locking policy, named StateLock
, that indicates that locking on the java.util.concurrent.Lock
stateLock
protects the named region, AircraftPosition
, that includes all of the mutable state used represent the position of the aircraft.belong together, as demonstrated in the following example:
Code Block | ||
---|---|---|
| ||
@Region("private AircraftPosition") @RegionLock("StateLock is stateLock protects AircraftPosition") public final class Aircraft { private final Lock stateLock = new ReentrantLock(); @InRegion("AircraftPosition") private long x, y; @InRegion("AircraftPosition") private long altitude; // ... public void setPosition(long x, long y) { stateLock.lock(); try { this.x = x; this.y = y; } finally { stateLock.unlock(); } } // ... } |
In this example, a locking policy named StateLock
is used to indicate that locking on stateLock
protects the named AircraftPosition
region, which includes the mutable state used to represent the position of the aircraft.
Construction of
...
Mutable Objects
Typically, object construction is considered an exception to the locking policy . Why? This is because objects are thread-confined when they are constructed. They are created. An object is confined to the thread that invoked uses the new
expression to construct the object. Subsequently operator to create its instance. After creation, the object is safely can be published to other threads safely. At issueHowever, is that the object does is not become shared until the thread that invoked the new
expression expects created the instance allows it to . One approach is be shared. Safe publication approaches discussed in CON14TSM01-J. Do not let the " this " reference escape during object construction and can be expressed succinctly with the @Unique("return")
annotation.
For example, in the following code, the @Unique("return")
annotation documents that the object returned from the constructor is a unique reference:
Code Block | ||
---|---|---|
| ||
@RegionLock("Lock is this protects Instance") public final class Example { private int x = 1; private int y; @Unique("return") public Example(int y) { this.y = y; } // ... } |
...
Documenting
...
Thread-
...
Confinement Policies
Dean Sutherland and William Scherlis in Composable Thread Coloring propose annotations that can document thread-confinement policies. Their approach is designed to allow allows verification of the annotations with the against as-written code [Sutherland 2010].
For example, expression, using the annotations proposed by Sutherland and Scherlis, of following annotations express the design intent that a program has, at most, one Abstract Window Toolkit (AWT) event dispatch thread , as many Compute threads as it wishesand several compute threads, and that the Compute thread is compute threads are forbidden to handle AWT data structures or events.:
Code Block | ||
---|---|---|
| ||
@ColorDeclare@ThreadRole AWT, Compute @IncompatibleColors@IncompatibleThreadRoles AWT, Compute @MaxColorCount@MaxRoleCount AWT 1 |
...
Documenting
...
Wait-
...
Notify Protocols
According to Goetz and colleagues [Goetz 2006],
A
...
state-dependent
...
class
...
should
...
either
...
fully
...
expose
...
(and
...
document)
...
its
...
waiting
...
and
...
notification
...
protocols
...
to
...
subclasses,
...
or
...
prevent
...
subclasses
...
from
...
participating
...
in
...
them
...
at
...
all.
...
(This
...
is
...
an
...
extension
...
of
...
"design
...
and
...
document
...
for
...
inheritance,
...
or
...
else
...
prohibit
...
it"
...
[EJ
...
Item
...
15
...
].)
...
At
...
the
...
very
...
least,
...
designing
...
a
...
state-dependent
...
class
...
for
...
inheritance
...
requires
...
exposing
...
the
...
condition
...
queues
...
and
...
locks
...
and
...
documenting
...
the
...
condition
...
predicates
...
and
...
synchronization
...
policy;
...
it
...
may
...
also
...
require
...
exposing
...
the
...
underlying
...
state
...
variables.
...
(The
...
worst
...
thing
...
a
...
state-dependent
...
class
...
can
...
do
...
is
...
expose
...
its
...
state
...
to
...
subclasses
...
but
...
not
...
document
...
its
...
protocols
...
for
...
waiting
...
and
...
notification;
...
this
...
is
...
like
...
a
...
class
...
exposing
...
its
...
state
...
variables
...
but
...
not
...
documenting
...
its
...
invariants.)
...
(p. 395)
Wait-notify protocols should be documented adequately. Currently, we are not aware of any annotations for this purpose.
Applicability
Annotating concurrent code helps document the design intent and can be used to automate the detection and prevention of race conditions and data races.
Automated Detection
Tool | Version | Checker | Description |
---|---|---|---|
The Checker Framework | 2.1.3 | GUI Effect Checker | Ensure that non-GUI threads do not access the UI which would crash the application (see Chapter 14) |
Bibliography
Item 70, "Document Thread Safety" | |
Java Concurrency in Practice | |
...