Different ways of dealing with asynchronicity, which is informally, to allow multiple things to happen "at the same time", i.e. concurrently.
You may find
here
5 different approaches of using asynchronicity to count the total number
of lines of given files (e.g. countLines(String...paths)
), namely:
- Threads and blocking IO (avoid it)
- Tasks and blocking IO (avoid it)
- Asynchronous IO
Teaching Modelling and Design Patterns course at ISEL we should achieve Reactive Streams by the end of the semester. To that end, we start from the basis: Reactive + Streams. For familiarity, we start by:
- Streams and first with the
Iterator
, which is a well-known pattern for all students at 4th semester and later we move tojava.util.stream.Stream
. - After that, we tackle Reactive Streams starting with asynchronous programming (this repo).
At the end, students are able to manage:
Multiplicity | Access | Call | ||
---|---|---|---|---|
T |
1 | item |
||
Optional<T> |
1 | Internal External |
op.ifPresent(item -> …) item = op.get() |
Blocking |
Iterator<T> |
* | External | item = iter.next() |
Blocking |
Spliterator<T> |
* | Internal | iter.tryAdvance(item -> …) iter.forEachRemaining(item -> …) |
Blocking |
CompletableFuture<T> |
1 | Internal | cf.thenAccept(item -> …) |
Non-blocking |
Publisher<T> (e.g. RxJava, Reactor, Kotlin Flow) |
* | Internal | pub.subscribe(item -> …) |
Non-blocking |
Async Iterator (e.g C# and .Net) |
* | External | item = await iter.next() for await(const item of iter) … |
Non-blocking |
(*) Notice that Spliterator
is not only related with the Stream
parallelism. For a quick explanation about its advantages in sequential processing you may read the answer of Brian Goetz here: Iterator versus Stream of Java 8.
Stream<T> |
CompletableFuture<T> |
---|---|
void forEach(Consumer<T>) |
CF<Void> thenAccept(Consumer<T>) |
Stream<R> map(Function<T, R>) |
CF<R> thenApply(Function<T, R>) |
Stream<R> flatMap(Function<T, Stream<R>>) |
CF<R> thenCompose(Function<T, CF<R>>) |
Stream<T> peek(Consumer<T>) |
CF<T> whenComplete(BiConsumer<T,Throwable>) |
Stream<R> zip(Stream<U>, BiFunction<T, U, R>) (*) |
CF<R> thenCombine(CF<U>, BiFunction<T, U, R>) |
(*) does not exist in JDK.