[concurrency-interest] CompletableFuture improvements

Chris Purcell chris.purcell.39 at gmail.com
Fri Aug 14 06:48:54 EDT 2015


Hi everyone,

I have a few suggestions for changes that could be made to
CompletableFuture, and wondered what everyone thought about them. To prove
they work, I have coded them up into an alternative CompletionStage
implementation, which you can find (along with a longer discussion) at
https://github.com/cjp39/j8stages

To summarize:

(1) Internally, CompletableFuture's fluent API constructs a work queue of
callbacks to execute, to avoid StackOverflowErrors caused by callback
recursion, but there is no way to add custom tasks to it. If we create a
ThreadLocal work queue instead, we can transform recursive listener
callbacks into iteration even if arbitrary user code intervenes. This lets
the user interoperate with other future implementations (like
ListenableFutures
<http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/util/concurrent/ListenableFuture.html>),
and use complete()/completeExceptionally() in callbacks, without risking
StackOverflowErrors. It also simplifies CompletableFuture, and removes the
requirement that other CompletionStages implement
toCompletableFuture(). Since ThreadLocal is tied into the JVM, it's pretty
efficient, so performance shouldn't be an issue. (For implementation
details, see the GitHub repo <https://github.com/cjp39/j8stages>.)

What do people think of this idea?

(2) CompletionStage.whenComplete discards exceptions if both input stage
and action fail. It would be less surprising if, like try/finally, it added
the action exception to the input exception as a suppressed exception. This
can be done safely by cloning the input exception (all Throwables are
Serializable). I don't think performance should be a blocker, as this is a
rare edge case, and we are providing a very useful service for the cost.

Are there any other issues with doing this that I haven't thought about?

(3) CompletableFuture uses concurrent assistance to execute its callback
queue. I suspect this is to give a parallelism speedup. However, I don't
think this particular problem will scale. If we drop the assistance
algorithm, we can drop the extra queue field and store callbacks in the
main result field (currently set to null before the future completes),
giving a simpler implementation, and avoiding overhead from cacheline
conflicts. (Again, for implementation details, see the GitHub repo
<https://github.com/cjp39/j8stages>.)

My assumption may be way off-base here, though. Are there other reasons for
the two-field approach of CompletableFuture?

Cheers,
Chris
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://cs.oswego.edu/pipermail/concurrency-interest/attachments/20150814/8f675ca8/attachment.html>


More information about the Concurrency-interest mailing list