Class RefCountingRunnable

java.lang.Object
org.elasticsearch.action.support.RefCountingRunnable
All Implemented Interfaces:
Closeable, AutoCloseable, Releasable

public final class RefCountingRunnable extends Object implements Releasable
A mechanism to trigger an action on the completion of some (dynamic) collection of other actions. Basic usage is as follows:
 try (var refs = new RefCountingRunnable(finalRunnable)) {
     for (var item : collection) {
         runAsyncAction(item, refs.acquire()); // releases the acquired ref on completion
     }
 }
 
The delegate action is completed when execution leaves the try-with-resources block and every acquired reference is released. Unlike a CountDown there is no need to declare the number of subsidiary actions up front (refs can be acquired dynamically as needed) nor does the caller need to check for completion each time a reference is released. Moreover even outside the try-with-resources block you can continue to acquire additional references, even in a separate thread, as long as there's at least one reference outstanding:
 try (var refs = new RefCountingRunnable(finalRunnable)) {
     for (var item : collection) {
         if (condition(item)) {
             runAsyncAction(item, refs.acquire());
         }
     }
     if (flag) {
         runOneOffAsyncAction(refs.acquire());
         return;
     }
     for (var item : otherCollection) {
         var itemRef = refs.acquire(); // delays completion while the background action is pending
         executorService.execute(() -> {
             try (var ignored = itemRef) {
                 if (condition(item)) {
                     runOtherAsyncAction(item, refs.acquire());
                 }
             }
         });
     }
 }
 
In particular (and also unlike a CountDown) this works even if you don't acquire any extra refs at all: in that case, the delegate action executes at the end of the try-with-resources block.
  • Constructor Details

    • RefCountingRunnable

      public RefCountingRunnable(Runnable delegate)
      Construct a RefCountingRunnable which executes delegate when all refs are released.
      Parameters:
      delegate - The action to execute when all refs are released. This action must not throw any exception.
  • Method Details

    • acquire

      public Releasable acquire()
      Acquire a reference to this object and return an action which releases it. The delegate Runnable is called when all its references have been released. It is invalid to call this method once all references are released. Doing so will trip an assertion if assertions are enabled, and will throw an IllegalStateException otherwise. It is also invalid to release the acquired resource more than once. Doing so will trip an assertion if assertions are enabled, but will be ignored otherwise. This deviates from the contract of Closeable.
    • acquireListener

      public ActionListener<Void> acquireListener()
      Acquire a reference to this object and return a listener which releases it when notified. The delegate Runnable is called when all its references have been released.
    • close

      public void close()
      Release the original reference to this object, which executes the delegate Runnable if there are no other references. It is invalid to call this method more than once. Doing so will trip an assertion if assertions are enabled, but will be ignored otherwise. This deviates from the contract of Closeable.
      Specified by:
      close in interface AutoCloseable
      Specified by:
      close in interface Closeable
      Specified by:
      close in interface Releasable
    • toString

      public String toString()
      Overrides:
      toString in class Object