Class DelayedAction

java.lang.Object
org.dellroad.stuff.spring.DelayedAction
All Implemented Interfaces:
Runnable

public abstract class DelayedAction extends Object implements Runnable
Manages a delayed action without race conditions.

A "delayed action" is a some action that needs to get done by some time in the future.

This class does two things:

  • It collapses multiple attempts to schedule the action into a single scheduled action, i.e., at most one outstanding scheduled action can exist at a time.
  • It provides a race-free and 100% reliable way to cancel() a future scheduled action, if any.

The action itself is defined by the subclass' implementation of run().

To avoid races, this class requires the user to supply a locking object. This may either be a normal Java object, in which case normal Java synchronization is used, or a Lock object. The locking object is used to serialize scheduling activity and action invocation. In other words, the locking object is locked during the execution of schedule(), cancel(), and run().

Therefore, any time the locking object is locked, the state of this DelayedAction instance is "frozen" in one of three states: not scheduled, scheduled, or executing (in the latter case, of course the thread doing the executing is the one holding the lock). Therefore, to completely avoid race conditions, user code must itself lock the locking object itself prior to invoking any methods in this class.

Typically the most convenient locking object to use is the user's own this object, which can be locked using a synchronized method or block.

Note: in the case that run() invokes Object.wait() on the locking object, thereby temporarily releasing the lock, to any other methods in this class it will appear as if that execution has already completed.

  • Constructor Details

  • Method Details

    • schedule

      public void schedule(Instant instant)
      Schedule the delayed action for the given time.

      More precisely:

      • If an action currently executing, before doing anything else this method blocks until it completes; if this behavior is undesirable, the caller can avoid this behavior by synchronizing on the locking object prior to invoking this method.
      • If no action is scheduled, one is scheduled for the given time.
      • If an action is already scheduled, and the given time is on or after the scheduled time, nothing changes.
      • If an action is already scheduled, and the given time is prior to the scheduled time, the action is rescheduled for the earlier time.

      The net result is that, for any invocation, this method guarantees exactly one execution of the action will occur approximately on or before the given instant; however, multiple invocations of this method prior to action execution can only ever result in a single "shared" action.

      Parameters:
      instant - scheduled execution time (at the latest)
      Throws:
      IllegalArgumentException - if instant is null
      TaskRejectedException - if the given task was not accepted for internal reasons (e.g. a pool overload handling policy or a pool shutdown in progress)
    • cancel

      public void cancel()
      Cancel the future scheduled action, if any.

      More precisely:

      • If an action currently executing, before doing anything else this method blocks until it completes; if this behavior is undesirable, the caller can avoid this behavior by synchronizing on the locking object prior to invoking this method.
      • If an action is scheduled but has not started yet, it is guaranteed not to run.
      • If no action is scheduled or executing, nothing changes.
    • isScheduled

      public boolean isScheduled()
      Determine whether there is currently an outstanding scheduled action.
      Returns:
      true if an action is pending
    • getScheduledTime

      public Instant getScheduledTime()
      Get the scheduled time for the outstanding scheduled action, if any.
      Returns:
      oustanding action scheduled time, or null if there is no scheduled action
    • schedule

      protected ScheduledFuture<?> schedule(Runnable action, Instant instant)
      Schedule the given action using the task scheduler passed to the constructor. Use of this method does not change the state of this instance.
      Parameters:
      action - action to perform
      instant - when to perform it
      Returns:
      future for completion of action
      Throws:
      IllegalArgumentException - if either parameter is null
      RejectedExecutionException - if the given task was not accepted for internal reasons (e.g. a pool overload handling policy or a pool shutdown in progress)