JAVA8多线程-CompletableFuture+Executor

本文介绍了Java 8 CompletableFuture的创建方式,如何主动设置返回值、配合自定义线程池、处理异常,并展示了数据整合的实践。重点讲解了如何利用CompletableFuture进行高效、异步的并发编程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


两种创建CompletableFuture的方式:
①:CompletableFuture.supplyAsync(执行有返回值的方法)

        CompletableFuture codeFuture = CompletableFuture.supplyAsync(() ->
            loginService.getCode()
        );

②:CompletableFuture.runAsync(执行无返回值的方法)

        CompletableFuture nameFuture = CompletableFuture.runAsync(
            () -> loginService.settingName()
        );

CompletableFuture新特性:
①:
JAVA8的CompletableFuture可以主动设置计算的结果值(也就是说可以主动结束线程阻塞)

    public String getCode() {
        return "1128";
    }
        CompletableFuture codeFuture = CompletableFuture.supplyAsync(() ->
            loginService.getCode()
        );
        // 主动设置返回值
        codeFuture.complete("wozhudongjieshu");
        // 控制台打印返回值
        System.out.println(codeFuture.join());
  

输出结果wozhudongjieshu
结论:同样道理,利用场景就是当线程发生阻塞时,可以利用利用另一个线程主动设置返回值

②:配合自定义线程池使用

CompletableFuture.supplyAsync有两个方法,如果不用自定义线程池,将自己用LinkedBlockingQueuen new一个线程池,根据业务需要,也可以用自己定义的线程池。
定义线程池:

    @Bean("myExecutor")
    public Executor myExecutor(){
        // 活动线程数为20的线程池
        return Executors.newFixedThreadPool(20);
    }

 把线程池放上去

    @Autowired
    @Qualifier("myExecutor")
    Executor executor;       

    public void testAsyn() throws ExecutionException, InterruptedException {
          CompletableFuture codeFuture = CompletableFuture.supplyAsync(() ->
            loginService.getCode(),executor
        );
    }

③:异常抛到主线程中
如果此刻CompletableFuture.supplyAsync不去捕获异常的话,调用getCode这个方法时,异常就会被吞了。

        CompletableFuture codeFuture = CompletableFuture.supplyAsync(() ->
            loginService.getCode(),executor
        );


    public String getCode() {
       throw new RuntimeException("fail");
    }

此时如果想把异常抛到主线程的话就得用.excetionally

        CompletableFuture codeFuture = CompletableFuture.supplyAsync(() ->
            loginService.getCode(), executor
        ).exceptionally(e -> {
                System.out.println(e);
                throw new RuntimeException(e);
            }
        );

这样异常就在主线程捕获到了 

java.lang.RuntimeException: fail

④:数据整合

//a任务        
CompletableFuture<List<String>> listCompletableFuture = CompletableFuture
            .supplyAsync(() -> publicService.add());
//b任务
        CompletableFuture<List<String>> listCompletableFuture1 = 
CompletableFuture.supplyAsync(() 
            -> domoService.mins()
        );
//待a任务和b任务都完成,整合数据(.thenCombine)
        List<String> join = listCompletableFuture
            .thenCombine(listCompletableFuture1, (List<String> a, List<String> b) -> {
                a.addAll(b);
                System.out.println(System.currentTimeMillis());
                return a;
            }).join();

<think>好的,我现在需要解释Java多线程CompletableFuture。用户可能是一个有一定Java基础的后端程序员,之前问过如何学习Vue的问题,现在转向Java并发相关内容。他们可能对多线程的基本概念有所了解,但想深入理解,特别是CompletableFuture的作用和用法。 首先,我需要明确多线程的基本概念,包括线程的创建、生命周期、同步机制,比如synchronized和Lock。然后要解释为什么需要多线程,比如提高性能、处理并发任务。但用户可能已经知道这些,所以需要更深入一点,比如线程池的使用,Executors框架,以及常见的问题如死锁、竞态条件。 接下来是CompletableFuture,这是Java 8引入的,用于异步编程。需要说明它解决了什么问题,比如传统Future的局限性,无法非阻塞地组合多个异步任务。要对比Future和CompletableFuture的区别,突出CompletableFuture的优势,比如链式调用、异常处理、组合多个任务等。 需要举一些例子,比如如何创建异步任务,使用thenApply、thenAccept等方法进行链式处理,还有allOf、anyOf等方法组合多个Future。可能用户实际开发中会遇到需要多个异步任务完成后执行某个操作的情况,这时候CompletableFuture的allOf就很有用。 同时,要注意用户的背景是后端开发,可能对并发处理有实际需求,比如处理HTTP请求、数据库操作等,可以结合这些场景说明CompletableFuture的应用,比如异步调用多个服务聚合结果,提高响应速度。 另外,要提到与线程池的结合使用,避免创建过多线程,合理配置线程池参数。可能还需要提到异常处理,如何在异步链中捕获和处理异常,比如使用exceptionally方法。 还要注意用户可能对函数式编程不熟悉,CompletableFuture大量使用了Lambda表达式,可能需要简单说明一下,但用户作为Java程序员应该已经接触过Lambda,所以可以稍微带过。 最后,总结多线程CompletableFutureJava并发编程中的地位,以及如何在实际项目中合理使用它们来提升性能和代码可维护性。可能还需要推荐一些学习资源,比如官方文档、书籍或者在线教程,帮助用户进一步学习。 在组织内容时,结构要清晰,分点解释,先讲多线程的基础,再引出CompletableFuture,说明其解决的问题和用法。语言要简洁,避免过于技术化的术语,但也要准确,确保用户能理解。需要检查是否有错误的地方,比如线程池的类型,CompletableFuture的方法是否正确,避免误导用户。</think>### **Java 多线程CompletableFuture 详解** #### **一、Java 多线程基础** **1. 什么是多线程?** 多线程允许程序同时执行多个任务,每个任务在一个独立的线程中运行。线程是操作系统调度的最小单位,Java 通过 `Thread` 类和 `Runnable` 接口实现多线程。 **2. 为什么需要多线程?** - **提高性能**:充分利用多核 CPU,并行处理任务(如批量计算、数据处理)。 - **响应性**:避免主线程阻塞(如 GUI 应用需要同时处理用户操作和后台任务)。 - **资源复用**:通过线程池管理线程生命周期,减少频繁创建/销毁的开销。 **3. 创建线程的两种方式** - **继承 `Thread` 类** ```java class MyThread extends Thread { public void run() { System.out.println("Thread running"); } } new MyThread().start(); ``` - **实现 `Runnable` 接口**(更推荐,避免单继承限制) ```java Runnable task = () -> System.out.println("Runnable task"); new Thread(task).start(); ``` **4. 线程同步与锁** 多线程共享资源时可能引发 **竞态条件**(Race Condition),需通过同步机制解决: - **`synchronized` 关键字**:修饰方法或代码块,保证原子性。 ```java public synchronized void increment() { count++; } ``` - **`ReentrantLock`**:更灵活的显式锁,支持超时、公平锁等。 ```java Lock lock = new ReentrantLock(); lock.lock(); try { /* 临界区 */ } finally { lock.unlock(); } ``` **5. 线程池(ExecutorService)** 直接创建线程成本高,推荐使用线程池管理: ```java ExecutorService executor = Executors.newFixedThreadPool(4); executor.submit(() -> System.out.println("Task in thread pool")); executor.shutdown(); ``` --- #### **二、CompletableFuture:异步编程利器** **1. 什么是 CompletableFuture?** Java 8 引入的类,用于简化异步编程。它是 `Future` 的增强版,支持链式调用、组合多个异步任务、异常处理等。 **2. 为什么需要 CompletableFuture?** 传统 `Future` 的局限性: - 无法手动设置结果,只能在任务完成后获取。 - 不支持非阻塞回调(需轮询 `isDone()` 检查状态)。 - 难以组合多个异步任务(如任务 A 完成后触发任务 B)。 **3. 核心功能** - **异步执行任务**:通过 `supplyAsync`、`runAsync` 提交任务到线程池。 - **链式处理结果**:使用 `thenApply`、`thenAccept`、`thenRun` 等方法串联操作。 - **组合多个任务**:通过 `thenCombine`、`allOf`、`anyOf` 实现并行或依赖执行。 - **异常处理**:通过 `exceptionally`、`handle` 捕获并恢复。 **4. 典型用法示例** **示例 1:异步执行 + 链式处理** ```java CompletableFuture.supplyAsync(() -> "Hello") // 异步任务 .thenApply(s -> s + " World") // 转换结果 .thenAccept(System.out::println); // 消费结果 ``` **示例 2:组合多个任务** ```java CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> 10); CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(() -> 20); // 等待所有任务完成,合并结果 future1.thenCombine(future2, (a, b) -> a + b) .thenAccept(sum -> System.out.println("Sum: " + sum)); // 任意一个任务完成即可触发 CompletableFuture.anyOf(future1, future2) .thenRun(() -> System.out.println("At least one task done")); ``` **示例 3:异常处理** ```java CompletableFuture.supplyAsync(() -> { if (Math.random() > 0.5) throw new RuntimeException("Error!"); return "Success"; }).exceptionally(ex -> "Fallback Result") // 异常时返回默认值 .thenAccept(System.out::println); ``` **5. 与线程池结合** 默认使用 `ForkJoinPool.commonPool()`,也可指定自定义线程池: ```java ExecutorService customPool = Executors.newCachedThreadPool(); CompletableFuture.supplyAsync(() -> "Task", customPool); ``` --- #### **三、适用场景** 1. **并行调用多个服务**:聚合多个 API 结果(如用户信息 + 订单数据)。 2. **异步非阻塞 IO**:避免阻塞主线程(如文件读写、网络请求)。 3. **复杂任务流水线**:将任务拆分为多个阶段,按顺序或条件执行。 --- #### **四、注意事项** - **避免阻塞**:不要在异步任务中调用 `get()` 阻塞线程,优先使用回调。 - **资源泄漏**:及时关闭线程池(`shutdown()`)。 - **异常传播**:通过 `exceptionally` 或 `handle` 处理异常,防止任务静默失败。 --- #### **五、总结** - **多线程**是 Java 并发编程的基础,需掌握线程管理、同步机制和线程池。 - **CompletableFuture** 通过链式语法和组合能力,极大简化了异步编程复杂度,适合处理 I/O 密集型或复杂任务流场景。 - 两者结合可构建高效、响应式的后端服务,提升吞吐量和用户体验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值