SpringBoot异步编程实战:@Async与CompletableFuture深度剖析

🎓博主介绍:Java、Python、js全栈开发 “多面手”,精通多种编程语言和技术,痴迷于人工智能领域。秉持着对技术的热爱与执着,持续探索创新,愿在此分享交流和学习,与大家共进步。
📖DeepSeek-行业融合之万象视界(附实战案例详解100+)
📖全栈开发环境搭建运行攻略:多语言一站式指南(环境搭建+运行+调试+发布+保姆级详解)
👉感兴趣的可以先收藏起来,希望帮助更多的人
在这里插入图片描述

SpringBoot异步编程实战:@Async与CompletableFuture深度剖析

一、引言

在现代软件开发中,随着业务逻辑的日益复杂和用户对系统响应速度要求的不断提高,异步编程逐渐成为提升系统性能和响应能力的重要手段。Spring Boot作为一款广泛应用的Java开发框架,提供了强大的异步编程支持,其中@Async注解和CompletableFuture类是实现异步编程的两个关键工具。本文将深入剖析这两种异步编程方式,通过实战案例帮助技术人员掌握它们的使用方法和应用场景。

二、Spring Boot异步编程基础

2.1 同步编程与异步编程的区别

  • 同步编程:在同步编程模型中,程序按照顺序依次执行每个任务,只有当前任务完成后,才会继续执行下一个任务。这种方式简单直观,但在处理耗时操作时会阻塞线程,导致系统响应变慢。
  • 异步编程:异步编程允许程序在执行耗时操作时不阻塞当前线程,而是继续执行其他任务。当耗时操作完成后,通过回调、事件等方式通知主线程。这种方式可以提高系统的并发性能和响应能力。

2.2 Spring Boot异步编程的优势

  • 提高系统性能:通过异步处理耗时任务,释放主线程资源,使系统能够同时处理更多的请求。
  • 改善用户体验:减少用户等待时间,提高系统的响应速度,增强用户体验。
  • 简化代码结构:使用异步编程可以将复杂的业务逻辑拆分成多个独立的任务,使代码结构更加清晰。

三、@Async注解的使用

3.1 开启异步支持

在Spring Boot项目中,要使用@Async注解实现异步方法,首先需要在主应用类上添加@EnableAsync注解来开启异步支持。示例代码如下:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;

@SpringBootApplication
@EnableAsync
public class AsyncApplication {
    public static void main(String[] args) {
        SpringApplication.run(AsyncApplication.class, args);
    }
}

3.2 创建异步方法

在需要异步执行的方法上添加@Async注解。示例代码如下:

import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.util.concurrent.TimeUnit;

@Service
public class AsyncService {
    @Async
    public void asyncMethod() {
        try {
            // 模拟耗时操作
            TimeUnit.SECONDS.sleep(5);
            System.out.println("异步方法执行完成");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

3.3 调用异步方法

在其他服务类或控制器中调用异步方法。示例代码如下:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class AsyncController {
    @Autowired
    private AsyncService asyncService;

    @GetMapping("/async")
    public String asyncRequest() {
        asyncService.asyncMethod();
        return "异步请求已发送";
    }
}

3.4 异步方法的返回值

@Async注解的方法可以有返回值,但返回值类型必须是Future或其子类。示例代码如下:

import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.CompletableFuture;

@Service
public class AsyncService {
    @Async
    public Future<String> asyncMethodWithResult() {
        try {
            TimeUnit.SECONDS.sleep(5);
            return CompletableFuture.completedFuture("异步方法执行结果");
        } catch (InterruptedException e) {
            e.printStackTrace();
            return CompletableFuture.completedFuture("执行出错");
        }
    }
}

调用带有返回值的异步方法:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.Future;

@RestController
public class AsyncController {
    @Autowired
    private AsyncService asyncService;

    @GetMapping("/async-result")
    public String asyncRequestWithResult() throws Exception {
        Future<String> result = asyncService.asyncMethodWithResult();
        // 等待异步方法执行完成并获取结果
        while (!result.isDone()) {
            Thread.sleep(100);
        }
        return result.get();
    }
}

3.5 自定义线程池

默认情况下,@Async使用Spring的默认线程池。为了更好地控制异步任务的执行,我们可以自定义线程池。示例代码如下:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.Executor;

@Configuration
@EnableAsync
public class AsyncConfig {
    @Bean(name = "asyncExecutor")
    public Executor asyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(5);
        executor.setMaxPoolSize(10);
        executor.setQueueCapacity(25);
        executor.setThreadNamePrefix("Async-");
        executor.initialize();
        return executor;
    }
}

@Async注解中指定使用自定义线程池:

import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.util.concurrent.TimeUnit;

@Service
public class AsyncService {
    @Async("asyncExecutor")
    public void asyncMethod() {
        try {
            TimeUnit.SECONDS.sleep(5);
            System.out.println("异步方法执行完成");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

四、CompletableFuture的使用

4.1 CompletableFuture简介

CompletableFuture是Java 8引入的一个强大的异步编程工具,它实现了FutureCompletionStage接口,提供了丰富的方法来处理异步任务的结果和组合多个异步任务。

4.2 创建CompletableFuture

  • 使用runAsync方法创建无返回值的异步任务
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class CompletableFutureExample {
    public static void main(String[] args) {
        ExecutorService executor = Executors.newSingleThreadExecutor();
        CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
            try {
                Thread.sleep(2000);
                System.out.println("异步任务执行完成");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, executor);

        // 主线程继续执行其他任务
        System.out.println("主线程继续执行");

        // 等待异步任务完成
        future.join();
        executor.shutdown();
    }
}
  • 使用supplyAsync方法创建有返回值的异步任务
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class CompletableFutureExample {
    public static void main(String[] args) {
        ExecutorService executor = Executors.newSingleThreadExecutor();
        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(2000);
                return "异步任务执行结果";
            } catch (InterruptedException e) {
                e.printStackTrace();
                return "执行出错";
            }
        }, executor);

        // 主线程继续执行其他任务
        System.out.println("主线程继续执行");

        // 等待异步任务完成并获取结果
        String result = future.join();
        System.out.println("异步任务结果: " + result);
        executor.shutdown();
    }
}

4.3 处理CompletableFuture的结果

  • 使用thenApply方法处理异步任务的结果
import java.util.concurrent.CompletableFuture;

public class CompletableFutureExample {
    public static void main(String[] args) {
        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(2000);
                return "异步任务执行结果";
            } catch (InterruptedException e) {
                e.printStackTrace();
                return "执行出错";
            }
        });

        CompletableFuture<String> processedFuture = future.thenApply(result -> {
            return result.toUpperCase();
        });

        String finalResult = processedFuture.join();
        System.out.println("处理后的结果: " + finalResult);
    }
}
  • 使用thenAccept方法消费异步任务的结果
import java.util.concurrent.CompletableFuture;

public class CompletableFutureExample {
    public static void main(String[] args) {
        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(2000);
                return "异步任务执行结果";
            } catch (InterruptedException e) {
                e.printStackTrace();
                return "执行出错";
            }
        });

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

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

4.4 组合多个CompletableFuture

  • 使用thenCompose方法组合两个CompletableFuture
import java.util.concurrent.CompletableFuture;

public class CompletableFutureExample {
    public static void main(String[] args) {
        CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(2000);
                return "第一个异步任务结果";
            } catch (InterruptedException e) {
                e.printStackTrace();
                return "执行出错";
            }
        });

        CompletableFuture<String> future2 = future1.thenCompose(result -> {
            return CompletableFuture.supplyAsync(() -> {
                try {
                    Thread.sleep(2000);
                    return result + " 第二个异步任务结果";
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    return "执行出错";
                }
            });
        });

        String finalResult = future2.join();
        System.out.println("组合后的结果: " + finalResult);
    }
}
  • 使用thenCombine方法组合两个CompletableFuture
import java.util.concurrent.CompletableFuture;

public class CompletableFutureExample {
    public static void main(String[] args) {
        CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(2000);
                return "第一个异步任务结果";
            } catch (InterruptedException e) {
                e.printStackTrace();
                return "执行出错";
            }
        });

        CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(2000);
                return "第二个异步任务结果";
            } catch (InterruptedException e) {
                e.printStackTrace();
                return "执行出错";
            }
        });

        CompletableFuture<String> combinedFuture = future1.thenCombine(future2, (result1, result2) -> {
            return result1 + " " + result2;
        });

        String finalResult = combinedFuture.join();
        System.out.println("组合后的结果: " + finalResult);
    }
}

4.5 异常处理

使用exceptionally方法处理异步任务中的异常:

import java.util.concurrent.CompletableFuture;

public class CompletableFutureExample {
    public static void main(String[] args) {
        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
            throw new RuntimeException("模拟异常");
        });

        CompletableFuture<String> handledFuture = future.exceptionally(ex -> {
            return "异常处理结果: " + ex.getMessage();
        });

        String result = handledFuture.join();
        System.out.println(result);
    }
}

五、@Async与CompletableFuture的比较

5.1 适用场景

  • @Async:适用于简单的异步任务,不需要复杂的任务组合和结果处理。例如,在Spring Boot应用中处理一些耗时的日志记录、消息发送等任务。
  • CompletableFuture:适用于复杂的异步任务,需要进行任务组合、结果处理和异常处理。例如,在微服务架构中,需要同时调用多个服务并处理它们的结果。

5.2 性能差异

  • @Async:使用Spring的线程池管理异步任务,性能相对稳定,但在处理复杂任务时可能不够灵活。
  • CompletableFuture:提供了更细粒度的任务控制和并发处理能力,性能更高,但代码复杂度也相对较高。

5.3 代码复杂度

  • @Async:代码简单,只需要在方法上添加注解即可实现异步调用。
  • CompletableFuture:代码复杂度较高,需要使用各种方法来处理异步任务的结果和组合多个任务。

六、实战案例:综合应用@Async与CompletableFuture

6.1 需求描述

假设我们有一个电商系统,需要同时查询商品信息、用户信息和订单信息,并将这些信息整合后返回给用户。为了提高系统的响应速度,我们可以使用异步编程来并行查询这些信息。

6.2 代码实现

import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.util.concurrent.CompletableFuture;

@Service
public class DataService {
    @Async
    public CompletableFuture<String> getProductInfo() {
        try {
            Thread.sleep(2000);
            return CompletableFuture.completedFuture("商品信息");
        } catch (InterruptedException e) {
            e.printStackTrace();
            return CompletableFuture.failedFuture(e);
        }
    }

    @Async
    public CompletableFuture<String> getUserInfo() {
        try {
            Thread.sleep(1500);
            return CompletableFuture.completedFuture("用户信息");
        } catch (InterruptedException e) {
            e.printStackTrace();
            return CompletableFuture.failedFuture(e);
        }
    }

    @Async
    public CompletableFuture<String> getOrderInfo() {
        try {
            Thread.sleep(1800);
            return CompletableFuture.completedFuture("订单信息");
        } catch (InterruptedException e) {
            e.printStackTrace();
            return CompletableFuture.failedFuture(e);
        }
    }
}
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

@RestController
public class DataController {
    @Autowired
    private DataService dataService;

    @GetMapping("/data")
    public String getData() throws ExecutionException, InterruptedException {
        CompletableFuture<String> productFuture = dataService.getProductInfo();
        CompletableFuture<String> userFuture = dataService.getUserInfo();
        CompletableFuture<String> orderFuture = dataService.getOrderInfo();

        CompletableFuture<Void> allFutures = CompletableFuture.allOf(productFuture, userFuture, orderFuture);
        CompletableFuture<String> combinedFuture = allFutures.thenApply(v -> {
            try {
                return productFuture.get() + " " + userFuture.get() + " " + orderFuture.get();
            } catch (InterruptedException | ExecutionException e) {
                e.printStackTrace();
                return "执行出错";
            }
        });

        return combinedFuture.get();
    }
}

七、总结

本文深入剖析了Spring Boot中@Async注解和CompletableFuture类的使用方法和应用场景。@Async注解提供了简单的异步方法调用功能,适用于处理简单的异步任务;而CompletableFuture类则提供了更强大的异步任务处理和组合能力,适用于处理复杂的异步场景。通过合理使用这两种异步编程方式,可以显著提高Spring Boot应用的性能和响应能力。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

fanxbl957

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值