- All Implemented Interfaces:
Closeable,AutoCloseable,Releasable
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. You can continue to acquire additional references
outside the try-with-resources block, even using different threads, as long as you ensure 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 (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.
The delegate action runs on the thread that releases the last reference, or the thread that closes the try-with-resources block if there are no unreleased references when this happens.
See also RefCountingListener, which fulfils a similar role in situations where the subsidiary actions might fail, and you want
such failures to propagate automatically to the final action.
-
Constructor Summary
ConstructorsConstructorDescriptionRefCountingRunnable(Runnable delegate) Construct aRefCountingRunnablewhich executesdelegatewhen all refs are released. -
Method Summary
Modifier and TypeMethodDescriptionacquire()Acquire a reference to this object and return an action which releases it.Acquire a reference to this object and return a listener which releases it when notified.voidclose()Release the original reference to this object, which executes the delegateRunnableif there are no other references.toString()
-
Constructor Details
-
RefCountingRunnable
Construct aRefCountingRunnablewhich executesdelegatewhen 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
Acquire a reference to this object and return an action which releases it. The delegateRunnableis called when all its references have been released, on the thread that releases the last reference.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
IllegalStateExceptionotherwise.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
Acquire a reference to this object and return a listener which releases it when notified. The delegateRunnableis called when all its references have been released, on the thread that releases the last reference.If the returned listener is completed exceptionally then the exception is ignored. Use
RefCountingListenerin situations where you want to keep track of exceptions from subsidiary actions. -
close
public void close()Release the original reference to this object, which executes the delegateRunnableif 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:
closein interfaceAutoCloseable- Specified by:
closein interfaceCloseable- Specified by:
closein interfaceReleasable
-
toString
-