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 and doDestroy, which are both executed under the instance monitor. Note, however, that tools like Spotbugs aren’t aware of this, so making those methods synchronized 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 general AbstractStage 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 given Item.

  • A stage's execute method should never be synchronized although it may call synchronized getters.