Class Synchronizer

  • All Implemented Interfaces:
    SynchronizerApi.RunGet, SynchronizerApi.SleepRunGet

    public final class Synchronizer
    extends Object
    implements SynchronizerApi.SleepRunGet
    Encapsulates synchronization and wait/notify functionality.

    Introduction

    By calling any of the instance methods of Synchronizer, the calling code defines a chain of actions that is completed with invoke(). All those actions are performed in one synchronized block using a lock which is private to the Synchronizer instance.

    With its fluent API and encapsulated lock, this class can help increasing both the readability and robustness of concurrent algorithms. Still, care must be taken to avoid deadlocks, just as if using synchronized blocks and Object.wait() / Object.notifyAll() directly.

    Actions

    Synchronizer provides the following actions:

    • Main action
    • Sleep until condition is true
      • Can be used before (sleepUntil) and/or after (thenSleepUntil) the main action.
        Sleeping is implemented in line with secure coding practices, i.e. Object.wait() is called inside a loop to ensure liveness and safety (see SEI CERT rule THI03-J for details).
        If the thread is interrupted while waiting, UncheckedInterruptedException is thrown and the thread's interrupted flag is re-set.

    • Wake other threads
      • Using wakeOthers() is equivalent to calling Object.notifyAll(). If the main action is a Supplier<T>, the calling code can decide whether waking takes place by using andWakeOthersIf(Predicate<T>) instead.

    Fluent API overview



    Example usage

    synchronizer.run(...)
         .thenSleepUntil(...)
         .invoke();
    
     synchronizer.sleepUntil(...)
         .run(...)
         .andWakeOthers()
         .invoke();
    
     ResultClass result = synchronizer.get(...)
         .invoke();
    
     Spline result = synchronizer.get(...)
         .andWakeOthersIf(Spline::isReticulated)
         .invoke();