Skip to content

About

Implementation of blocking (IO-Bound) cancellable java.util.concurrent.CompletionStage and related extensions to java.util.concurrent.ExecutorService-s

Topics

Resources

Stars

223 stars

Watchers

12 watching

Forks

Repository files navigation

Maven Central GitHub release license

tascalate-concurrent

The library provides an implementation of the CompletionStage interface and related classes these are designed to support long-running blocking tasks (typically, I/O bound). This functionality augments the sole Java 8 built-in implementation, CompletableFuture, that is primarily supports computational tasks. Also, the library helps with numerous asynchronous programing challenges like handling timeouts, retry/poll functionality, orchestrating results of multiple concurrent computations and similar.

Since the version 0.7.0 the library is shipped as a multi-release JAR and may be used both with Java 8 as a classpath library or with Java 9+ as a module.

IMPORTANT!

In the version 0.8.0 the artifact was renamed: New name:

<dependency>
    <groupId>net.tascalate</groupId>
    <artifactId>net.tascalate.concurrent</artifactId>
    <version>1.0.1</version>
</dependency>

Old Name

<dependency>
    <groupId>net.tascalate.concurrent</groupId>
    <artifactId>net.tascalate.concurrent.lib</artifactId>
    <version>0.7.1</version>
</dependency>

Why CompletableFuture is Not Enough?

There are several shortcomings in the CompletableFuture implementation that complicate its use in real-world asynchronous programming, especially when dealing with I/O-bound, interruptible tasks:

  1. Lack of true interruptibility: The CompletableFuture.cancel() method does not interrupt the underlying thread; it merely transitions the future to an exceptionally completed state. Consequently, even if you use blocking calls inside functions passed to thenApplyAsync, thenAcceptAsync, etc., these functions will run to completion and cannot be interrupted. For more details, see CompletableFuture can't be interrupted by Tomasz Nurkiewicz.
  2. Unconfigurable default executor: By default, all *Async composition methods of CompletableFuture use the ForkJoinPool.commonPool() (see here) unless an explicit Executor is specified. This thread pool is shared among all CompletableFuture instances and parallel streams across all applications deployed on the same JVM. This hard-coded, unconfigurable thread pool is completely outside the application developer's control, making it difficult to monitor and scale. Therefore, in robust real-life applications, you should always specify your own Executor. While Java 9+ introduced API enhancements to mitigate this, addressing it still requires custom coding.
  3. Inconvenient composition API: The built-in Java concurrency API provides a rather limited way to combine multiple CompletionStages. The CompletableFuture.allOf and CompletableFuture.anyOf methods accept only CompletableFuture arguments, meaning there is no built-in mechanism to combine arbitrary CompletionStages without first converting them to CompletableFuture. Furthermore, CompletableFuture.allOf returns a CompletableFuture<Void>, making it inconvenient to extract the individual results of each supplied future. CompletableFuture.anyOf is even more restrictive in this regard; for more details, please read CompletableFuture in Action (see "Shortcomings") by Tomasz Nurkiewicz.
  4. Late addition of timeouts and delays: Support for timeouts and delays was introduced to CompletableFuture only in Java 9, leaving widely used Java 8 applications without this crucial functionality. Furthermore, certain design decisions, such as relying on delayed executors instead of a dedicated delay operator, are somewhat questionable.

While numerous open-source libraries address some of these shortcomings, none provide a fully interruptible CompletionStage implementation, and none solve all of these issues coherently.

How to use?

To use a library you have to add a single Maven dependency

<dependency>
    <groupId>net.tascalate</groupId>
    <artifactId>net.tascalate.concurrent</artifactId>
    <version>1.0.1</version>
</dependency>

Documentation

Complete user documentation is available HERE

Acknowledgements

Internal implementation details are greatly inspired by the work done by Lukáš Křečan. The part of the polling / asynchronous retry functionality is adopted from the async-retry library by Tomasz Nurkiewicz

About

Implementation of blocking (IO-Bound) cancellable java.util.concurrent.CompletionStage and related extensions to java.util.concurrent.ExecutorService-s

Topics

Resources

Stars

223 stars

Watchers

12 watching

Forks

Releases

Packages

Used by

Contributors

Languages