[concurrency-interest] CompletableFuture with delay

Peter Levart peter.levart at gmail.com
Mon Aug 25 10:16:31 EDT 2014

On 08/25/2014 09:55 AM, Millies, Sebastian wrote:
> Hello there,
> I'd like to simulate asynchronous IO events in a test system (without actual IO).
> For this purpose, I have defined a method that creates a future which returns a value after a delay.
> In contrast to Future#get(Long,TimeUnit) this method does not wait, but uses a separate ScheduledFuture
> to complete the future. Code is shown below.
> So far, so good. But I also want to cancel the scheduled task (the ScheduledFuture returned from
> ScheduledExecutorService#schedule()) when the future is cancelled before the timeout. (So that
> I can keep my timeout tasks from piling up when timeouts are long in relation to the real
> computations.)
> Please look at the code below, where I create an additional future with whenComplete and use
> that to cancel the task. Is that a correct solution? Or could this additional future be optimized
> away or be garbage collected? Does the variable "future" that is returned from the method hold a
> reference to the additional future? I couldn't tell from the source code of CompletableFuture.
>    private static final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(TIMER_THREADS);
>    public static <T> CompletableFuture<T> delayedSuccess(T value, int delay, TimeUnit unit) {
>      CompletableFuture<T> future = new CompletableFuture<T>();
>      ScheduledFuture<Boolean> task = scheduler.schedule(() -> future.complete(value), delay, unit);
>      future.whenComplete((t, ex) -> {
>        if (future.isCancelled())
>          task.cancel(true);               // <== HERE
>      });
>      return future;
>    }

Hi Sebastian,

The returned CompletableFuture 'future' references the BiConsumer 
function (in your case a lambda) until it completes. At that time it 
invokes it and releases the reference to it, so it can be GC-ed. The 
lambda captures the ScheduledFuture 'task' so it implicitly references 
it, when the lambda goes away, so would the captured 'task'.

But the returned 'future' (and BiConsumer lambda referenced by it) is 
captured by another lambda, the Runnable passed to scheduler.schedule(). 
This lambda and ScheduledFuture 'task' are referenced by the 'scheduler' 
until the time comes and the scheduler executes the delayed task and 
then they are released. This happens even when the ScheduledFuture 
'task' is canceled beforehand. Unless you configure 
ScheduledThreadPoolExecutor to remove the task on cancel:

((ScheduledThreadPoolExecutor) scheduler).setRemoveOnCancelPolicy(true);

By setting that, I think you get the timely clean-up of all the objects 

Regards, Peter

> Sebastian Millies
> Expert Java Business Analytics
> Phone: +49 681 210 3221 | Fax: +49 681 210 1801 | Sebastian.Millies at softwareag.com<mailto:Sebastian.Millies at ids-scheer.com>
> Software AG -- Sitz/Registered office: Uhlandstraße 12, 64297 Darmstadt, Germany -- Registergericht/Commercial register: Darmstadt HRB 1562 - Vorstand/Management Board: Karl-Heinz Streibich (Vorsitzender/Chairman), Dr. Wolfram Jost, Arnd Zinnhardt; - Aufsichtsratsvorsitzender/Chairman of the Supervisory Board: Dr. Andreas Bereczky - http://www.softwareag.com
> _______________________________________________
> Concurrency-interest mailing list
> Concurrency-interest at cs.oswego.edu
> http://cs.oswego.edu/mailman/listinfo/concurrency-interest

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://cs.oswego.edu/pipermail/concurrency-interest/attachments/20140825/1989927b/attachment-0001.html>

More information about the Concurrency-interest mailing list