Flow API, CompletableFuture und Concurrency-Bibliothek
Mit Java 9 haben wichtige Interfaces wie Publisher und Subscriber als Flow API Einzug in die Concurrency-Bibliothek gehalten. Außerdem gibt es Erweiterungen des seit Java 8 existierenden CompletableFuture APIs und andere, eher kleinere Anpassungen. Diese im Java Extension Proposal 266 beschriebenen Erweiterungen tragen die Bezeichnung „More Concurrency Updates“. Das steckt im Detail dahinter.
Seit Java 5 gibt es den Type Future, der allerdings beim Aufruf der Methode get() den aktuellen Thread blockiert. Abhilfe dafür wurde in Java 8 mit der Einführung der APIs CompletableFuture und CompletionStage geschaffen. Diese ermöglichen es, die Verarbeitung in der definierten Callback-Methode asynchron fortzusetzen oder weitere Schritte daran zu knüpfen. JavaScript-Entwickler kennen diese Vorgehensweise unter der Bezeichnung Promise. Diese Abstraktion hat ihre Einschränkungen. Wenn wir beispielsweise CompletableFuture<List<T>> haben, müssen wir solange warten, bis wir die Liste komplett aufgebaut haben. Erst danach können wir deren Elemente im Callback verarbeiten. Es wäre besser, sie verarbeiten zu können, sobald sie verfügbar sind.
Das Stream API, das ebenfalls seit Java 8 existiert, ist ein pull-basiertes API. Zum Ausführen von latenzsensitiven I/O-Operationen ist es nur begrenzt geeignet und wurde dafür auch nicht konzipiert. Ein weiterer Nachteil des Stream APIs liegt darin, dass es vor allem für die Verarbeitung der Elemente der Collections und Arrays bereitgestellt wurde. Genau an dieser Stelle glänzen die reaktiven APIs. Zu deren Stärken gehört allerdings nicht die blockierende Verarbeitung der potenziell unendlichen Sequenzen von beliebigen Events, die mit Latenz ankommen können.
Mit Java 9 haben vier API-Komponenten in Form von Interfaces Eingang ins Package java.util.concurrent.Flow gefunden (Listing 1).
Listing 1: Die neuen Interfaces
public interface Publisher<T> {
public void subscribe(Subscriber<? super T> s);
}
public interface Subscriber<T> {
public void onSubscribe(Subscription s);
public void onNext(T t);
public void onError(Throwable t);
public void onComplete();
}
public interface Subscription {
public void request(long n);
public void cancel();
}
public interface Processor<T, R> extends Subscriber<T>, Publisher<R> {
}
Das Flow API in JDK 9 entspricht der Spezifikation Reactive Streams. Die Reactive-Streams-Spezifikation ist eine der Initiativen zur Standardisierung der reaktiven Programmierung. Sie wurde von den Firmen Netflix, Pivotal, Red Hat, Twitter und Typesafe gegründet. Außer den besagten vier Interfaces wird die Regel (Spezifikation) für die Reactive Streams definiert und ein Technology Compatibility Kit (TCK) mitgeliefert. Mehrere Implementierungen unterstützen bereits die Reactive-Streams-Spezifikation, darunter unter anderem Spring Reactor 3, RxJava 2, Akka Streams, die jeweils von den Mitgliedern der Initiative stammen. Oracle hat lediglich die Interfaces aus der Spezifikation Reactive Streams als Flow API in Java 9 übernommen.
Das Flow API und das Reactive Streams API sind in gewisser Weise eine Kombination von Ideen aus Iterator- und Observer-Patterns. Der Iterator ist ein Pull-Modell, bei dem die Applikation Items aus der Quelle zieht. Der Observer ist ein Push-Modell, bei ...