Developing for Concurrency
Some random notes:
Framework classes (stages, pipelines, validators, strategies, etc.) should all be designed to be
@ThreadSafe
. The usual strategy for this is:All fields are documented as
@GuardedBy("this")
.Fields must only be referenced directly in:
Setters and getters, all of which must be
synchronized
.doInitialize
anddoDestroy
, which are both executed under the instance monitor. Note, however, that tools like Spotbugs aren’t aware of this, so making those methodssynchronized
anyway is recommended: the overhead of “re-claiming” the object monitor is very low in modern Java implementations.Rarely,
synchronized (this)
blocks.
All other field references must be through the appropriate getter.
When there are many resulting references to getters, it may be worth moving those calls out of loops if possible. This may involve switching from the convenience
AbstractIteratingStage
to the more generalAbstractStage
to expose the implied loop.Theoretically, the first call to any getter is enough to establish the required happens-before relation to avoid data races. Trying to take clever advantage of that to avoid any performance hit from synchronization is not recommended. One alternative in such cases is to use calls to getters inside a
synchronized (this)
block to snapshot all property values at once: the cost of synchronizing getters while the instance monitor is already held is very low.
Item
implementations are not required to be either@ThreadSafe
or@ThreadSafeAfterInit
and will normally be@NotThreadSafe
. They can be used in only one thread at a time (thread containment) but that thread may change over time.Item metadata must be
@Immutable
. It may be shared between multiple copies of a givenItem
.A stage's
execute
method should never besynchronized
although it may call synchronized getters.