CompletableFuture使用例子

CompletableFuture 本身支持异步执行,可以通过指定线程池来控制任务的执行方式,也可以通过默认的公共线程池(ForkJoinPool.commonPool())来执行。你可以通过传递自定义的线程池,或是使用 Thread 类来启动异步任务,下面我将分别介绍如何使用这些方式来提交 CompletableFuture 任务。

1. 使用线程池执行任务

默认情况下,CompletableFuture 使用 ForkJoinPool.commonPool() 来执行异步任务。如果你想使用自定义的线程池来执行任务,可以通过重载的 supplyAsyncrunAsync 方法来指定线程池。

例子:通过自定义线程池提交任务
import java.util.concurrent.*;

public class CompletableFutureWithThreadPool {
    public static void main(String[] args) throws InterruptedException, ExecutionException {
        // 创建自定义线程池
        ExecutorService executorService = Executors.newFixedThreadPool(3);

        // 使用自定义线程池提交任务
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            System.out.println("线程 ID: " + Thread.currentThread().getName());
            return 42;
        }, executorService);

        // 获取结果
        Integer result = future.get();  // 阻塞,等待结果
        System.out.println("结果: " + result);

        // 关闭线程池
        executorService.shutdown();
    }
}

在这个例子中,我们使用 Executors.newFixedThreadPool(3) 创建了一个具有 3 个线程的固定线程池,并通过将 executorService 作为参数传递给 supplyAsync() 来确保任务在该线程池中执行。

2. 通过 Thread 类启动异步任务

如果你想通过 Thread 类来启动 CompletableFuture,可以使用 Thread 创建并启动一个线程,然后在该线程中执行异步任务。虽然这样不是 CompletableFuture 的标准做法,因为 CompletableFuture 通常与线程池配合使用,但你依然可以手动启动一个线程来执行任务。

例子:通过 Thread 类启动任务
import java.util.concurrent.CompletableFuture;

public class CompletableFutureWithThread {
    public static void main(String[] args) throws InterruptedException {
        // 创建线程
        Thread thread = new Thread(() -> {
            CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
                System.out.println("线程 ID: " + Thread.currentThread().getName());
                return 42;
            });

            future.thenAccept(result -> {
                System.out.println("结果: " + result);
            });
        });

        // 启动线程
        thread.start();

        // 等待线程执行完成
        thread.join();
    }
}

在这个例子中,我们显式地创建了一个 Thread 来启动一个新的线程,并在该线程中执行 CompletableFuture.supplyAsync() 任务。虽然这种方法可以实现功能,但与线程池相比,它没有线程池的资源管理优势。

3. 使用 runAsync() 提交任务

runAsync() 用于提交没有返回值的异步任务。如果你不关心返回值,只想执行某些操作,可以使用 runAsync()

例子:提交无返回值任务
import java.util.concurrent.*;

public class CompletableFutureWithRunAsync {
    public static void main(String[] args) throws InterruptedException {
        // 创建自定义线程池
        ExecutorService executorService = Executors.newFixedThreadPool(3);

        // 提交无返回值的异步任务
        CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
            System.out.println("任务开始执行,线程 ID: " + Thread.currentThread().getName());
        }, executorService);

        // 等待任务完成
        future.join();

        // 关闭线程池
        executorService.shutdown();
    }
}

这里使用了 runAsync() 提交一个没有返回值的异步任务,并且指定了自定义线程池。

4. 组合多个任务(线程池或 Thread)

你也可以组合多个 CompletableFuture,在多个线程中异步执行多个任务并组合它们的结果。可以使用 thenCombine()thenCompose() 等方法来处理多个异步任务的结果。

例子:组合多个任务
import java.util.concurrent.*;

public class CompletableFutureWithMultipleTasks {
    public static void main(String[] args) throws InterruptedException, ExecutionException {
        // 创建自定义线程池
        ExecutorService executorService = Executors.newFixedThreadPool(3);

        // 创建第一个任务
        CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务 1 执行在: " + Thread.currentThread().getName());
            return 5;
        }, executorService);

        // 创建第二个任务
        CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务 2 执行在: " + Thread.currentThread().getName());
            return 10;
        }, executorService);

        // 组合任务 1 和 2
        CompletableFuture<Integer> resultFuture = future1.thenCombine(future2, (result1, result2) -> result1 + result2);

        // 获取最终结果
        Integer result = resultFuture.get();
        System.out.println("最终结果: " + result);

        // 关闭线程池
        executorService.shutdown();
    }
}

总结

  • 使用线程池:推荐使用 CompletableFuture.supplyAsync()CompletableFuture.runAsync() 并传入自定义的线程池。这样能确保任务的管理更具灵活性、可控性,并提高资源的利用率。
  • 通过 Thread 启动任务:虽然你可以通过显式地创建并启动一个 Thread 来执行任务,但这通常不如使用线程池高效,因为线程池会自动管理线程的生命周期,减少频繁创建和销毁线程的开销。
  • 组合任务:通过 thenCombine()thenCompose() 等方法,可以轻松地组合多个异步任务。

CompletableFuture 与线程池的结合,使得异步编程更加高效、灵活、可读性强。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值