Skip to content

Instantly share code, notes, and snippets.

@isopov
Last active October 4, 2018 13:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save isopov/b2dca9d7152f577741c8451d91e97e37 to your computer and use it in GitHub Desktop.
Save isopov/b2dca9d7152f577741c8451d91e97e37 to your computer and use it in GitHub Desktop.

Future.cancel() return value was pretty consistent before CompletableFuture

ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
Future<Void> foo = executor.submit(() -> {
    try {
        Thread.sleep(TimeUnit.DAYS.toMillis(1));
    } catch (InterruptedException e) {
        //ignore
    }
    return null;
});
System.out.println(foo.cancel(true));
System.out.println(foo.cancel(true));
executor.shutdown();

prints 

true
false

Guava

Future<Void> foo = SettableFuture.create();
System.out.println(foo.cancel(true));
System.out.println(foo.cancel(true));

prints

true
false

Spring

Future<Void> foo = new SettableListenableFuture<>();
System.out.println(foo.cancel(true));
System.out.println(foo.cancel(true));

prints

true
false

However CompletableFuture

Future<Void> foo = new CompletableFuture<>();
System.out.println(foo.cancel(true));
System.out.println(foo.cancel(true));

prints

true
true

and states in javadoc that it `return true if this task is now cancelled

But the following code:

CompletableFuture<Void> foo = new SettableListenableFuture<Void>().completable();
System.out.println(foo.cancel(true));
System.out.println(foo.cancel(true));

prints

true
false

AFAIU Future interface does not specify strictly what should cancel() return for subsequent invocations, CompletableFuture specified it differently than major other implementations and now your DelegatingCompletableFuture violates this specification(?) returning to previous de-facto standard.

I don't know whether this should be fixed in DelegatingCompletableFuture, but it seems that for the consumers of Future-based API it is better to avoid using cancel return value.

Note that in Reactor:

CompletableFuture<Void> foo = Mono.<Void>fromFuture(CompletableFuture::new).toFuture();
System.out.println(foo.cancel(true));
System.out.println(foo.cancel(true));

prints

true
true

since reactor.core.publisher.MonoToCompletableFuture.cancel() logic for return value relies on super.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment