Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
Вивчайте Completablefuture | Найкращі Практики Багатопотокового Програмування
Багатопотоковість у Java

bookCompletablefuture

Залишився останній крок! У цьому розділі ми розглянемо основний клас асинхронності CompletableFuture.

Використаємо реальну аналогію. Ви замовляєте таксі через додаток (створення завдання). Поки ви чекаєте, додаток може надавати оновлення щодо місцезнаходження автомобіля або орієнтовного часу прибуття (обробка результату). Якщо виникають проблеми, наприклад затримки чи скасування, додаток сповістить вас і запропонує альтернативи (обробка винятків).

Основні методи

Перше питання, яке може виникнути — як запустити завдання за допомогою CompletableFuture. Для цього можна використати метод supplyAsync(), який призначений для виконання завдання, що повертає результат асинхронно.

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: });

Маємо також метод thenAccept(), який обробляє значення, повернуте з CompletableFuture, у асинхронному коді. Він нічого не повертає; корисний, коли потрібно прийняти відповідь і певним чином її обробити.

Note
Примітка

У нашому прикладі завдання виконується асинхронно, а future.thenAccept() отримує відповідь з лямбди, яку потім можна використати для виведення у консоль.

Існує схожий метод, thenApply(), який працює подібно до thenAccept(), але отримує результат асинхронного завдання та повертає новий результат.

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: });

Що робити, якщо нам не потрібно отримувати результат асинхронного завдання, а лише потрібно бути сповіщеним про його завершення?

Для цього можна використати thenRun(), який виконується після завершення асинхронного завдання.

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! });

Можна також отримати результат асинхронного завдання, заблокувавши поточний потік до завершення завдання. Для цього використовується метод get().

Main.java

Main.java

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

Існує також метод join(), який також призупиняє поточний потік і очікує завершення асинхронного завдання. Однак, різниця між join() та get() полягає в тому, що вони викидають різні винятки.

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();

Тут ми не обробляємо виняток, оскільки метод join() викидає неперевірений виняток CompletionException.

Комбінування задач і їх ланцюжок

Можна комбінувати задачі у CompletableFuture за допомогою thenCompose(), який об'єднує 2 залежні задачі.

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 });

Спочатку отримуємо дані про книгу асинхронно за допомогою методу getBookDetails(), а потім використовуємо результат для виконання наступної асинхронної задачі — отримання даних про автора через метод getAuthorDetails(). Після завершення обох задач результат (інформація про автора) виводиться у консоль.

Можна також об'єднати результати двох завдань за допомогою методу thenCombine(). Він виконує обидва завдання паралельно та об'єднує їх результати після завершення обох завдань.

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 });

Цей код асинхронно отримує два числа, підсумовує їх і виводить результат у консоль.

Також можна дочекатися завершення всіх завдань за допомогою методу allOf(), або будь-якого з них — за допомогою методу 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"); });

Як обробляти помилки та що таке тайм-аут?

Короткий фрагмент з відео

  • handle(): Обробка результату або обробка будь-яких винятків, що виникають у CompletableFuture;
  • exceptionally(): Обробка винятків, що виникають під час виконання CompletableFuture;
  • completeOnTimeout(): Завершення CompletableFuture із заданим значенням у разі перевищення часу очікування до завершення.
Note
Примітка

CompletableFuture спрощує керування асинхронними завданнями та обробку їх результатів, що робить його потужним інструментом для розробки сучасних застосунків.

Все було зрозуміло?

Як ми можемо покращити це?

Дякуємо за ваш відгук!

Секція 4. Розділ 6

Запитати АІ

expand

Запитати АІ

ChatGPT

Запитайте про що завгодно або спробуйте одне із запропонованих запитань, щоб почати наш чат

Awesome!

Completion rate improved to 3.33

bookCompletablefuture

Свайпніть щоб показати меню

Залишився останній крок! У цьому розділі ми розглянемо основний клас асинхронності CompletableFuture.

Використаємо реальну аналогію. Ви замовляєте таксі через додаток (створення завдання). Поки ви чекаєте, додаток може надавати оновлення щодо місцезнаходження автомобіля або орієнтовного часу прибуття (обробка результату). Якщо виникають проблеми, наприклад затримки чи скасування, додаток сповістить вас і запропонує альтернативи (обробка винятків).

Основні методи

Перше питання, яке може виникнути — як запустити завдання за допомогою CompletableFuture. Для цього можна використати метод supplyAsync(), який призначений для виконання завдання, що повертає результат асинхронно.

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: });

Маємо також метод thenAccept(), який обробляє значення, повернуте з CompletableFuture, у асинхронному коді. Він нічого не повертає; корисний, коли потрібно прийняти відповідь і певним чином її обробити.

Note
Примітка

У нашому прикладі завдання виконується асинхронно, а future.thenAccept() отримує відповідь з лямбди, яку потім можна використати для виведення у консоль.

Існує схожий метод, thenApply(), який працює подібно до thenAccept(), але отримує результат асинхронного завдання та повертає новий результат.

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: });

Що робити, якщо нам не потрібно отримувати результат асинхронного завдання, а лише потрібно бути сповіщеним про його завершення?

Для цього можна використати thenRun(), який виконується після завершення асинхронного завдання.

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! });

Можна також отримати результат асинхронного завдання, заблокувавши поточний потік до завершення завдання. Для цього використовується метод get().

Main.java

Main.java

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

Існує також метод join(), який також призупиняє поточний потік і очікує завершення асинхронного завдання. Однак, різниця між join() та get() полягає в тому, що вони викидають різні винятки.

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();

Тут ми не обробляємо виняток, оскільки метод join() викидає неперевірений виняток CompletionException.

Комбінування задач і їх ланцюжок

Можна комбінувати задачі у CompletableFuture за допомогою thenCompose(), який об'єднує 2 залежні задачі.

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 });

Спочатку отримуємо дані про книгу асинхронно за допомогою методу getBookDetails(), а потім використовуємо результат для виконання наступної асинхронної задачі — отримання даних про автора через метод getAuthorDetails(). Після завершення обох задач результат (інформація про автора) виводиться у консоль.

Можна також об'єднати результати двох завдань за допомогою методу thenCombine(). Він виконує обидва завдання паралельно та об'єднує їх результати після завершення обох завдань.

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 });

Цей код асинхронно отримує два числа, підсумовує їх і виводить результат у консоль.

Також можна дочекатися завершення всіх завдань за допомогою методу allOf(), або будь-якого з них — за допомогою методу 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"); });

Як обробляти помилки та що таке тайм-аут?

Короткий фрагмент з відео

  • handle(): Обробка результату або обробка будь-яких винятків, що виникають у CompletableFuture;
  • exceptionally(): Обробка винятків, що виникають під час виконання CompletableFuture;
  • completeOnTimeout(): Завершення CompletableFuture із заданим значенням у разі перевищення часу очікування до завершення.
Note
Примітка

CompletableFuture спрощує керування асинхронними завданнями та обробку їх результатів, що робить його потужним інструментом для розробки сучасних застосунків.

Все було зрозуміло?

Як ми можемо покращити це?

Дякуємо за ваш відгук!

Секція 4. Розділ 6
some-alt