Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
Lernen Completablefuture | Multithreading Best Practices
Multithreading in Java

bookCompletablefuture

Es fehlt nur noch ein letzter Schritt! In diesem Kapitel betrachten wir die Hauptklasse für Asynchronität, CompletableFuture.

Verwendung einer Alltagsanalogie. Über eine App wird ein Taxi gerufen (Aufgabenerstellung). Während der Wartezeit kann die App Aktualisierungen zum Standort des Fahrzeugs oder zur voraussichtlichen Ankunftszeit bereitstellen (Ergebnisverarbeitung). Bei Problemen wie Verzögerungen oder Stornierungen informiert die App und schlägt Alternativen vor (Fehlerbehandlung).

Hauptmethoden

Die erste Frage könnte sein, wie eine Aufgabe mit CompletableFuture gestartet werden kann. Hierfür steht die Methode supplyAsync() zur Verfügung, die eine Aufgabe asynchron mit Rückgabewert ausführt.

Main.java

Main.java

copy
12345678910
// Creating an asynchronous task CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> { return "Result"; // Result }); // Processing the result after the task completes future.thenAccept(result -> { // Print the result to the console System.out.println("Result received: " + result); // Result received: });

Es gibt auch die Methode thenAccept(), die den von CompletableFuture zurückgegebenen Wert im asynchronen Code verarbeitet. Sie gibt keinen Wert zurück; sie ist nützlich, wenn eine Antwort angenommen und auf bestimmte Weise verarbeitet werden soll.

Note
Hinweis

Im Beispiel wird die Aufgabe asynchron ausgeführt, und future.thenAccept() erhält die Antwort von der Lambda-Funktion, die anschließend zur Ausgabe auf der Konsole verwendet werden kann.

Es gibt eine ähnliche Methode, thenApply(), die wie thenAccept() funktioniert, aber das Ergebnis der asynchronen Aufgabe erhält und ein neues Ergebnis zurückgibt.

Main.java

Main.java

copy
12345678910
// Creating an asynchronous task that returns "Hello, World!" CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "Hello, World!"); // Transforming the result to uppercase CompletableFuture<String> transformedFuture = future.thenApply(result -> result.toUpperCase()); // Printing the transformed result to the console transformedFuture.thenAccept(result -> { System.out.println("Transformed result: " + result); // Transformed result: });

Was ist, wenn wir das Ergebnis der asynchronen Aufgabe nicht benötigen, sondern lediglich benachrichtigt werden möchten, wenn sie abgeschlossen ist?

Dafür kann thenRun() verwendet werden, das nach dem Abschluss der asynchronen Aufgabe ausgeführt wird.

Main.java

Main.java

copy
12345678
// Creating an asynchronous task that returns "Hello, World!" CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "Hello, World!"); // Running a task when the previous task completes future.thenRun(() -> { // Print message to the console indicating that the task is complete System.out.println("Task completed!"); // Task completed! });

Das Ergebnis einer asynchronen Aufgabe kann auch abgerufen werden, indem der aktuelle Thread blockiert wird, bis die Aufgabe abgeschlossen ist. Zu diesem Zweck wird die Methode get() verwendet.

Main.java

Main.java

copy
1234567
CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> "Hello World"); try { String result = completableFuture.get(); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); }

Es gibt auch eine Methode join(), die ebenfalls den aktuellen Thread pausiert und auf den Abschluss der asynchronen Aufgabe wartet. Der Unterschied zwischen join() und get() besteht jedoch darin, dass sie unterschiedliche Ausnahmen auslösen.

Main.java

Main.java

copy
12345
// Create a `CompletableFuture` that asynchronously executes a task and returns the string "Hello World". CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> "Hello World"); // The `join()` method blocks the current thread until the task is completed and returns the result "Hello World". String result = completableFuture.join();

Hier erfolgt keine Behandlung der Ausnahme, da die Methode join() eine unchecked CompletionException auslöst.

Aufgaben kombinieren und verketten

Mit CompletableFuture können Aufgaben mithilfe von thenCompose() kombiniert werden, um zwei abhängige Aufgaben zu verknüpfen.

Main.java

Main.java

copy
12345678910111213141516171819202122232425
// Method to get book details from a remote service public CompletableFuture<String> getBookDetails() { return CompletableFuture.supplyAsync(() -> { // Request to a remote service to get book details return "Book Details"; // Placeholder for book details }); } // Method to get author details from a remote service public CompletableFuture<String> getAuthorDetails(String bookDetails) { return CompletableFuture.supplyAsync(() -> { // Request to another service to get author details return bookDetails + " Author"; // Placeholder for author details }); } // Combine two asynchronous tasks: get book details and then get author details CompletableFuture<String> result = getBookDetails() .thenCompose(book -> getAuthorDetails(book)); // Process the result and print the author details to the console result.thenAccept(author -> { // Print the author details to the console System.out.println("Author: " + author); // Author details });

Zuerst werden die Buchdaten asynchron mit der Methode getBookDetails() abgerufen. Anschließend wird das Ergebnis verwendet, um die nächste asynchrone Aufgabe auszuführen – das Abrufen der Autorendaten über die Methode getAuthorDetails(). Nachdem beide Aufgaben abgeschlossen sind, wird das Ergebnis (Autoreninformationen) auf der Konsole ausgegeben.

Wir können auch die Ergebnisse von zwei Aufgaben mit der Methode thenCombine() zusammenführen. Sie führt beide Aufgaben gleichzeitig aus und kombiniert deren Ergebnisse, sobald beide Aufgaben abgeschlossen sind.

Main.java

Main.java

copy
123456789101112
// CompletableFuture for adding two numbers CompletableFuture<Double> firstNumberFuture = CompletableFuture.supplyAsync(() -> 50.0); CompletableFuture<Double> secondNumberFuture = CompletableFuture.supplyAsync(() -> 30.0); // Combine the two futures by adding their results CompletableFuture<Double> sumFuture = firstNumberFuture.thenCombine(secondNumberFuture, (first, second) -> first + second); // Print the result of the addition to the console sumFuture.thenAccept(sum -> { System.out.println("Sum: " + sum); // Sum: 80.0 });

Dieser Code ruft asynchron zwei Zahlen ab, summiert sie und gibt das Ergebnis auf der Konsole aus.

Wir können auch auf den Abschluss aller Aufgaben mit der Methode allOf() warten oder auf eine beliebige mit der Methode anyOf().

Main.java

Main.java

copy
1234567891011121314151617181920
CompletableFuture<Void> future1 = CompletableFuture.runAsync(() -> { // Task 1 System.out.println("Task 1 completed"); }); CompletableFuture<Void> future2 = CompletableFuture.runAsync(() -> { // Task 2 System.out.println("Task 2 completed"); }); // Combine both futures and wait for both tasks to complete CompletableFuture<Void> combinedFuture1 = CompletableFuture.allOf(future1, future2); // Combine both futures and proceed as soon as any one task completes CompletableFuture<Object> combinedFuture2 = CompletableFuture.anyOf(future1, future2); // Print a message after all tasks are completed combinedFuture1.thenRun(() -> { System.out.println("All tasks completed"); });

Wie werden Fehler behandelt und was ist ein Timeout?

Kurzer Ausschnitt aus dem Video

  • handle(): Verarbeitung des Ergebnisses oder Behandlung von Ausnahmen, die durch das CompletableFuture ausgelöst wurden;
  • exceptionally(): Behandlung von Ausnahmen, die während der Ausführung des CompletableFuture auftreten;
  • completeOnTimeout(): Vervollständigung des CompletableFuture mit einem angegebenen Wert, falls ein Timeout vor Abschluss eintritt.
Note
Hinweis

CompletableFuture erleichtert die Verwaltung asynchroner Aufgaben und die Verarbeitung ihrer Ergebnisse und ist somit ein leistungsfähiges Werkzeug für die Entwicklung moderner Anwendungen.

War alles klar?

Wie können wir es verbessern?

Danke für Ihr Feedback!

Abschnitt 4. Kapitel 6

Fragen Sie AI

expand

Fragen Sie AI

ChatGPT

Fragen Sie alles oder probieren Sie eine der vorgeschlagenen Fragen, um unser Gespräch zu beginnen

Awesome!

Completion rate improved to 3.33

bookCompletablefuture

Swipe um das Menü anzuzeigen

Es fehlt nur noch ein letzter Schritt! In diesem Kapitel betrachten wir die Hauptklasse für Asynchronität, CompletableFuture.

Verwendung einer Alltagsanalogie. Über eine App wird ein Taxi gerufen (Aufgabenerstellung). Während der Wartezeit kann die App Aktualisierungen zum Standort des Fahrzeugs oder zur voraussichtlichen Ankunftszeit bereitstellen (Ergebnisverarbeitung). Bei Problemen wie Verzögerungen oder Stornierungen informiert die App und schlägt Alternativen vor (Fehlerbehandlung).

Hauptmethoden

Die erste Frage könnte sein, wie eine Aufgabe mit CompletableFuture gestartet werden kann. Hierfür steht die Methode supplyAsync() zur Verfügung, die eine Aufgabe asynchron mit Rückgabewert ausführt.

Main.java

Main.java

copy
12345678910
// Creating an asynchronous task CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> { return "Result"; // Result }); // Processing the result after the task completes future.thenAccept(result -> { // Print the result to the console System.out.println("Result received: " + result); // Result received: });

Es gibt auch die Methode thenAccept(), die den von CompletableFuture zurückgegebenen Wert im asynchronen Code verarbeitet. Sie gibt keinen Wert zurück; sie ist nützlich, wenn eine Antwort angenommen und auf bestimmte Weise verarbeitet werden soll.

Note
Hinweis

Im Beispiel wird die Aufgabe asynchron ausgeführt, und future.thenAccept() erhält die Antwort von der Lambda-Funktion, die anschließend zur Ausgabe auf der Konsole verwendet werden kann.

Es gibt eine ähnliche Methode, thenApply(), die wie thenAccept() funktioniert, aber das Ergebnis der asynchronen Aufgabe erhält und ein neues Ergebnis zurückgibt.

Main.java

Main.java

copy
12345678910
// Creating an asynchronous task that returns "Hello, World!" CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "Hello, World!"); // Transforming the result to uppercase CompletableFuture<String> transformedFuture = future.thenApply(result -> result.toUpperCase()); // Printing the transformed result to the console transformedFuture.thenAccept(result -> { System.out.println("Transformed result: " + result); // Transformed result: });

Was ist, wenn wir das Ergebnis der asynchronen Aufgabe nicht benötigen, sondern lediglich benachrichtigt werden möchten, wenn sie abgeschlossen ist?

Dafür kann thenRun() verwendet werden, das nach dem Abschluss der asynchronen Aufgabe ausgeführt wird.

Main.java

Main.java

copy
12345678
// Creating an asynchronous task that returns "Hello, World!" CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "Hello, World!"); // Running a task when the previous task completes future.thenRun(() -> { // Print message to the console indicating that the task is complete System.out.println("Task completed!"); // Task completed! });

Das Ergebnis einer asynchronen Aufgabe kann auch abgerufen werden, indem der aktuelle Thread blockiert wird, bis die Aufgabe abgeschlossen ist. Zu diesem Zweck wird die Methode get() verwendet.

Main.java

Main.java

copy
1234567
CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> "Hello World"); try { String result = completableFuture.get(); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); }

Es gibt auch eine Methode join(), die ebenfalls den aktuellen Thread pausiert und auf den Abschluss der asynchronen Aufgabe wartet. Der Unterschied zwischen join() und get() besteht jedoch darin, dass sie unterschiedliche Ausnahmen auslösen.

Main.java

Main.java

copy
12345
// Create a `CompletableFuture` that asynchronously executes a task and returns the string "Hello World". CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> "Hello World"); // The `join()` method blocks the current thread until the task is completed and returns the result "Hello World". String result = completableFuture.join();

Hier erfolgt keine Behandlung der Ausnahme, da die Methode join() eine unchecked CompletionException auslöst.

Aufgaben kombinieren und verketten

Mit CompletableFuture können Aufgaben mithilfe von thenCompose() kombiniert werden, um zwei abhängige Aufgaben zu verknüpfen.

Main.java

Main.java

copy
12345678910111213141516171819202122232425
// Method to get book details from a remote service public CompletableFuture<String> getBookDetails() { return CompletableFuture.supplyAsync(() -> { // Request to a remote service to get book details return "Book Details"; // Placeholder for book details }); } // Method to get author details from a remote service public CompletableFuture<String> getAuthorDetails(String bookDetails) { return CompletableFuture.supplyAsync(() -> { // Request to another service to get author details return bookDetails + " Author"; // Placeholder for author details }); } // Combine two asynchronous tasks: get book details and then get author details CompletableFuture<String> result = getBookDetails() .thenCompose(book -> getAuthorDetails(book)); // Process the result and print the author details to the console result.thenAccept(author -> { // Print the author details to the console System.out.println("Author: " + author); // Author details });

Zuerst werden die Buchdaten asynchron mit der Methode getBookDetails() abgerufen. Anschließend wird das Ergebnis verwendet, um die nächste asynchrone Aufgabe auszuführen – das Abrufen der Autorendaten über die Methode getAuthorDetails(). Nachdem beide Aufgaben abgeschlossen sind, wird das Ergebnis (Autoreninformationen) auf der Konsole ausgegeben.

Wir können auch die Ergebnisse von zwei Aufgaben mit der Methode thenCombine() zusammenführen. Sie führt beide Aufgaben gleichzeitig aus und kombiniert deren Ergebnisse, sobald beide Aufgaben abgeschlossen sind.

Main.java

Main.java

copy
123456789101112
// CompletableFuture for adding two numbers CompletableFuture<Double> firstNumberFuture = CompletableFuture.supplyAsync(() -> 50.0); CompletableFuture<Double> secondNumberFuture = CompletableFuture.supplyAsync(() -> 30.0); // Combine the two futures by adding their results CompletableFuture<Double> sumFuture = firstNumberFuture.thenCombine(secondNumberFuture, (first, second) -> first + second); // Print the result of the addition to the console sumFuture.thenAccept(sum -> { System.out.println("Sum: " + sum); // Sum: 80.0 });

Dieser Code ruft asynchron zwei Zahlen ab, summiert sie und gibt das Ergebnis auf der Konsole aus.

Wir können auch auf den Abschluss aller Aufgaben mit der Methode allOf() warten oder auf eine beliebige mit der Methode anyOf().

Main.java

Main.java

copy
1234567891011121314151617181920
CompletableFuture<Void> future1 = CompletableFuture.runAsync(() -> { // Task 1 System.out.println("Task 1 completed"); }); CompletableFuture<Void> future2 = CompletableFuture.runAsync(() -> { // Task 2 System.out.println("Task 2 completed"); }); // Combine both futures and wait for both tasks to complete CompletableFuture<Void> combinedFuture1 = CompletableFuture.allOf(future1, future2); // Combine both futures and proceed as soon as any one task completes CompletableFuture<Object> combinedFuture2 = CompletableFuture.anyOf(future1, future2); // Print a message after all tasks are completed combinedFuture1.thenRun(() -> { System.out.println("All tasks completed"); });

Wie werden Fehler behandelt und was ist ein Timeout?

Kurzer Ausschnitt aus dem Video

  • handle(): Verarbeitung des Ergebnisses oder Behandlung von Ausnahmen, die durch das CompletableFuture ausgelöst wurden;
  • exceptionally(): Behandlung von Ausnahmen, die während der Ausführung des CompletableFuture auftreten;
  • completeOnTimeout(): Vervollständigung des CompletableFuture mit einem angegebenen Wert, falls ein Timeout vor Abschluss eintritt.
Note
Hinweis

CompletableFuture erleichtert die Verwaltung asynchroner Aufgaben und die Verarbeitung ihrer Ergebnisse und ist somit ein leistungsfähiges Werkzeug für die Entwicklung moderner Anwendungen.

War alles klar?

Wie können wir es verbessern?

Danke für Ihr Feedback!

Abschnitt 4. Kapitel 6
some-alt