Thực thi nhiều tác vụ cùng lúc như thế nào trong Java?

Trong bài viết về CompletableFuture, chúng ta đã tìm hiểu về cách sử dụng multi-thread trong Java 8. Trong bài này, chúng ta sẽ cùng xem cách sử dụng CompletableFuture trong một bài toán thực tế.

Giả sử chúng ta có một ứng dụng cần thực hiện 2 công việc, tạm gọi là work1 và work2. Có hàng nghìn hàng triệu công việc work1 và khi mỗi công việc work1 hoàn thành sẽ có một danh sách các công việc work2 cần thực hiện. Để tiết kiệm được thời gian, chúng ta sẽ sử dụng Multi-Thread để thực thi công việc work1, khi mỗi công việc work1 hoàn thành, chúng ta cũng sẽ sử dụng Multi-Thread để xử lý kết quả nhận được từ công việc work1 (thực thi công việc work2).

Chương trình của chúng ta như sau:

package com.maixuanviet.completable_future;
 
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
 
/**
 * All level is running with multi-thread
 */
public class ConcurrencyWithCompletableFuture3 {
 
    public static void main(String[] args) {
        List<String> works = new ArrayList<>();
        works.add("A");
        works.add("B");
        works.add("C");
        works.add("D");
        works.add("E");
        runMultipleAsync(works);
    }
 
    private static void runMultipleAsync(List<String> works) {
        List<CompletableFuture<List<Void>>> allOfWork1Futures = new ArrayList<>();
        works.stream().forEach(work -> {
            allOfWork1Futures.add(createWork1(work).thenCompose(work1Results -> {
                List<CompletionStage<Void>> allOfWork2Futures = work1Results.stream()
                        .map(work1Result -> createWork2(work1Result)).collect(Collectors.toList());
                CompletableFuture<Void> done = CompletableFuture
                        .allOf(allOfWork2Futures.toArray(new CompletableFuture[allOfWork2Futures.size()]));
                return done.thenApplyAsync(v -> allOfWork2Futures.stream().map(CompletionStage::toCompletableFuture)
                        .map(CompletableFuture::join) // Returns the result value when complete
                        .collect(Collectors.toList()));
            }).whenCompleteAsync((result, th) -> {
                // Do something when complete
            }).toCompletableFuture());
        });
        CompletableFuture<Void> done = CompletableFuture
                .allOf(allOfWork1Futures.toArray(new CompletableFuture[allOfWork1Futures.size()]))
                .whenComplete((result, th) -> {
                    // Do something when complete
                });
        done.join(); // Returns the result value when complete
    }
 
    private static CompletionStage<List<String>> createWork1(String str) {
        return CompletableFuture.completedFuture(str).thenApplyAsync(s -> executeWork1(s));
    }
 
    private static CompletionStage<Void> createWork2(String str) {
        return CompletableFuture.completedFuture(str).thenAcceptAsync(s -> executeWork2(s));
    }
 
    private static List<String> executeWork1(String _item) {
        waitingForComplete();
        System.out.println("Work" + _item + " -> work1");
        return Arrays.asList(_item + "_item" + 1, _item + "_item" + 2);
    }
 
    private static void executeWork2(String data) {
        waitingForComplete();
        System.out.println("Work" + data + " -> work2");
    }
 
    private static void waitingForComplete() {
        try {
            TimeUnit.SECONDS.sleep(random(0, 3));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
 
    private static int random(int min, int max) {
        Random r = new Random();
        return r.nextInt((max - min) + 1) + min;
    }
}

Output của chương trình:

WorkB -&gt; work1
WorkC -&gt; work1
WorkB_item1 -&gt; work2
WorkA -&gt; work1
WorkB_item2 -&gt; work2
WorkC_item1 -&gt; work2
WorkD -&gt; work1
WorkE -&gt; work1
WorkA_item1 -&gt; work2
WorkC_item2 -&gt; work2
WorkD_item1 -&gt; work2
WorkD_item2 -&gt; work2
WorkE_item2 -&gt; work2
WorkA_item2 -&gt; work2
WorkE_item1 -&gt; work2
5.0

Related posts:

Logging a Reactive Sequence
Apache Commons Collections OrderedMap
Working with Kotlin and JPA
Guide to java.util.concurrent.Future
Java Program to Implement Stack using Two Queues
Using JWT with Spring Security OAuth
Java Program to Implement Hash Tables Chaining with List Heads
Constructor Dependency Injection in Spring
Hướng dẫn tạo và sử dụng ThreadPool trong Java
Java Program to Check if a Directed Graph is a Tree or Not Using DFS
Java Program to Check Cycle in a Graph using Topological Sort
Java Program to Create a Random Graph Using Random Edge Generation
Tạo ứng dụng Java RESTful Client với thư viện OkHttp
Debug a HttpURLConnection problem
Java TreeMap vs HashMap
Multipart Upload with HttpClient 4
A Quick Guide to Using Keycloak with Spring Boot
A Guide to Spring Boot Admin
Java Program to Check whether Undirected Graph is Connected using DFS
Assert an Exception is Thrown in JUnit 4 and 5
Java Program to Generate All Pairs of Subsets Whose Union Make the Set
Merging Two Maps with Java 8
Jackson – Change Name of Field
Java Program to Implement Karatsuba Multiplication Algorithm
Java Program to Use the Bellman-Ford Algorithm to Find the Shortest Path
Loại bỏ các phần tử trùng trong một ArrayList như thế nào trong Java 8?
Java Program to Check if a Given Graph Contain Hamiltonian Cycle or Not
Introduction to the Functional Web Framework in Spring 5
Java Program to Find Nearest Neighbor for Dynamic Data Set
Changing Annotation Parameters At Runtime
Java Program to Find Basis and Dimension of a Matrix
The Dining Philosophers Problem in Java