Java面試題#thenApply 和 thenApplyAsync 之間的區別

2024年2月6日 25点热度 0人点赞

thenApply是在同一線程中執行的。

thenApply更具有同步的特性,因為它在執行函數之前會等待當前 future 的完成。

thenApply是在處理函數或 輕量級future 且不涉及長時間運行的計算或阻塞操作時使用。

當需要快速非阻塞,或者當您需要保持嚴格的執行順序時,選擇thenApply 。

thenApplyAsync是另一個線程(通常來自默認線程(ForkJoinPool))異步執行的。

當需要可能長時間運行或想要確保非阻塞行為時,則最好使用thenApplyAsync方法。

當轉換非常耗時或阻塞時,或者想要將處理業務換到另一個線程以保持當前線程響應時,選擇thenApplyAsync。

在下面的示例中,運行 SupplyAsync 的線程將被 processData 方法阻止。除非流程數據返回,否則 SupplyAsync 不會完成。

package org.example;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;
public class ThenApplyExample {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        // Simulate a web service call
        long startTime = System.nanoTime();
        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
            // Fetch data (simulate with sleep)
            try {
                Thread.sleep(4000); // Simulate delay
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "Web Server Data";
        });
        // Process data asynchronously after fetching
        CompletableFuture<String> processedData = future.thenApply(data -> {
            // Data processing (CPU-intensive task)
            System.out.println("Processing data on thread: "   Thread.currentThread().getName());
            return processData(data);
        });
        // Output the processed data
        System.out.println("Processed Data: "   processedData.get());
        long endTime = System.nanoTime();
        long duration = (endTime - startTime) / 1_000_000; // Convert to milliseconds
        System.out.println("Execution Time: "   duration   " ms");
    }
    private static String processData(String data) {
        // Simulate data processing
        return "Processed "   data;
    }
}

在下面的示例中,我在線程中運行 SupplyAsync,並且該線程處理階段不會被 processData 方法阻止,因為 processData 方法將在其自己的線程中運行,並且不會阻止 SupplyAsync 。

package org.example;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;
public class ThenApplyAsyncExample {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        // Simulate a web service call
        long startTime = System.nanoTime();
        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
            // Fetch data (simulate with sleep)
            try {
                Thread.sleep(4000); // Simulate delay
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "Web Server Data";
        });
        // Process data asynchronously after fetching
        CompletableFuture<String> processedData = future.thenApplyAsync(data -> {
            // Data processing (CPU-intensive task)
            System.out.println("Processing data on thread: "   Thread.currentThread().getName());
            return processData(data);
        });
        // Output the processed data
        System.out.println("Processed Data: "   processedData.get());
        long endTime = System.nanoTime();
        long duration = (endTime - startTime) / 1_000_000; // Convert to milliseconds
        System.out.println("Execution Time: "   duration   " ms");
    }
    private static String processData(String data) {
        // Simulate data processing
        return "Processed "   data;
    }
}

thenAccept 和 thenAcceptAsync 之間的區別

thenAccept

  • thenAccept 是在同一個線程中執行。
  • thenAccept適用於對結果執行某些操作,並且該操作是快速非阻塞的情況。當希望維護執行順序或確定代碼將在哪個線程上下文中運行時,thenAccept也非常有用。

thenAcceptAsync

  • thenAcceptAsync是為在不同的線程中執行提供的操作,通常取自默認值ForkJoinPool