SpringBoot中使用多线程

在 SpringBoot 应用中,经常会遇到在一个接口中,同时做事情1,事情2,事情3,如果同步执行的话,则本次接口时间取决于事情1 2 3执行时间之和;如果三件事同时执行,则本次接口时间取决于事情1 2 3执行时间最长的那个,合理使用多线程,可以大大缩短接口时间

快速使用

SpringBoot应用中需要添加@EnableAsync注解,来开启异步调用,一般还会配置一个线程池,异步的方法交给特定的线程池完成,如下:

@Slf4j
@Configuration
@EnableAsync
public class ThreadPoolCachedConfig {

    /**
     * 允许线程空闲时间(单位:默认为秒)
     */
    private static final int KEEP_ALIVE_TIME = 10;
    /**
     * 缓冲队列数
     */
    private static final int QUEUE_CAPACITY = 200;
    /**
     * 最大线程数
     */
    private static final int maximnum_pool_size = 200;

    private static final int THREADS = Runtime.getRuntime().availableProcessors() + 1;

    private final ThreadFactory threadFactory = new ThreadFactoryBuilder()
            // -%d不要少
            .setNameFormat("tool-task-name-%d")
            .setDaemon(true)
            .build();

    /**
     * 自定义线程池
     * corePoolSize 核心池的大小
     * maximumPoolSize  线程池最大线程数
     * keepAliveTime  表示线程没有任务执行时最多保持多久时间会终止
     * unit 参数keepAliveTime的时间单位,有7种取值,在TimeUnit类中有7种静态属性
     *          TimeUnit.DAYS;               //天
     *          TimeUnit.HOURS;             //小时
     *          TimeUnit.MINUTES;           //分钟
     *          TimeUnit.SECONDS;           //秒
     *          TimeUnit.MILLISECONDS;      //毫秒
     *          TimeUnit.MICROSECONDS;      //微妙
     *          TimeUnit.NANOSECONDS;       //纳秒
     * workQueue  一个阻塞队列,用来存储等待执行的任务,这个参数的选择也很重要
     * threadFactory  用于设置创建线程的工厂,可以通过线程工厂给每个创建出来的线程做些更有意义的事情
     * handler  表示当拒绝处理任务时的策略,有以下四种取值
     * @return
     */
    @Bean("taskExecutor")
    public Executor taskExecutor() {
        log.info("ThreadPoolCachedConfig.class 自定义线程池执行成功。");
        return new ThreadPoolExecutor(THREADS, 2 * THREADS,
                KEEP_ALIVE_TIME, TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(QUEUE_CAPACITY),
                threadFactory, (r, executor) -> {
            // 打印日志,添加监控等
            log.warn("task is rejected!");
        });
    }
}

使用的方式非常简单,在需要异步的方法上加@Async注解。
获取异步方法返回值
当异步方法有返回值时,如何获取异步方法执行的返回结果呢?这时需要异步调用的方法带有返回值CompletableFuture。

CompletableFuture是对Feature的增强,Feature只能处理简单的异步任务,而CompletableFuture可以将多个异步任务进行复杂的组合。如下:


/**
 * 异步线程任务
 *
 * @author wang gang
 * @since 2021-11-09 11:11
 */
@Slf4j
@Service
public class AsyncServiceImpl {

    @Value("${bigData.rainfall.prediction.url}")
    private String bigDataRainfallPredictionUrl;

    @Async("taskExecutor")
    public CompletableFuture<List<BigDataRainfallPredicionPageVO>> bigDateRainfall(BigDataRainfallPredictionQO bigDataRainfallPredictionQO) {
        try{
            log.info("访问地址{}", bigDataRainfallPredictionUrl);
            List<BigDataRainfallPredicionPageVO> bigDataRainfallPredicionPageVOList = obtainBigDataRainfallPredicionPageVOList(
                    bigDataRainfallPredictionQO, null);
            return CompletableFuture.completedFuture(bigDataRainfallPredicionPageVOList);
        }catch (Exception e){
            log.error(e.toString());
            return CompletableFuture.completedFuture(Collections.emptyList());
        }
    }
}    
 private List<BigDataRainfallPredicionPageVO> getBigDataRainfallPredicionPageVOList(LocalDateTime time){
        LocalDate thisDate = time.toLocalDate();
        LocalDateTime time2HourFront = DateUtil.stringToLocalDateTime(DateUtil.localDateToString(thisDate) + " 01:00:00");
        LocalDateTime time2HourAfter = DateUtil.stringToLocalDateTime(DateUtil.localDateToString(thisDate) + " 02:00:00");
        //5点整
        LocalDateTime time5HourFront = DateUtil.stringToLocalDateTime(DateUtil.localDateToString(thisDate) + " 04:00:00");
        LocalDateTime time5HourAfter = DateUtil.stringToLocalDateTime(DateUtil.localDateToString(thisDate) + " 05:00:00");
        //8点整
        LocalDateTime time8HourFront = DateUtil.stringToLocalDateTime(DateUtil.localDateToString(thisDate) + " 07:00:00");
        LocalDateTime time8HourAfter = DateUtil.stringToLocalDateTime(DateUtil.localDateToString(thisDate) + " 08:00:00");
        //11点整
        LocalDateTime time11HourFront = DateUtil.stringToLocalDateTime(DateUtil.localDateToString(thisDate) + " 10:00:00");
        LocalDateTime time11HourAfter = DateUtil.stringToLocalDateTime(DateUtil.localDateToString(thisDate) + " 11:00:00");
        //14点整
        LocalDateTime time14HourFront = DateUtil.stringToLocalDateTime(DateUtil.localDateToString(thisDate) + " 13:00:00");
        LocalDateTime time14HourAfter = DateUtil.stringToLocalDateTime(DateUtil.localDateToString(thisDate) + " 14:00:00");
        //17点整
        LocalDateTime time17HourFront = DateUtil.stringToLocalDateTime(DateUtil.localDateToString(thisDate) + " 16:00:00");
        LocalDateTime time17HourAfter = DateUtil.stringToLocalDateTime(DateUtil.localDateToString(thisDate) + " 17:00:00");
        //20点整
        LocalDateTime time20HourFront = DateUtil.stringToLocalDateTime(DateUtil.localDateToString(thisDate) + " 19:00:00");
        LocalDateTime time20HourAfter = DateUtil.stringToLocalDateTime(DateUtil.localDateToString(thisDate) + " 20:00:00");
        //23点整
        LocalDateTime time23HourFront = DateUtil.stringToLocalDateTime(DateUtil.localDateToString(thisDate) + " 22:00:00");
        LocalDateTime time23HourAfter = DateUtil.stringToLocalDateTime(DateUtil.localDateToString(thisDate) + " 23:00:00");
        CompletableFuture<List<BigDataRainfallPredicionPageVO>> task2Hour = asyncService.bigDateRainfall(builderBigDataRainfallPredictionQO(time2HourFront, time2HourAfter));
        CompletableFuture<List<BigDataRainfallPredicionPageVO>> task5Hour = asyncService.bigDateRainfall(builderBigDataRainfallPredictionQO(time5HourFront, time5HourAfter));
        CompletableFuture<List<BigDataRainfallPredicionPageVO>> task8Hour = asyncService.bigDateRainfall(builderBigDataRainfallPredictionQO(time8HourFront, time8HourAfter));
        CompletableFuture<List<BigDataRainfallPredicionPageVO>> task11Hour = asyncService.bigDateRainfall(builderBigDataRainfallPredictionQO(time11HourFront, time11HourAfter));
        CompletableFuture<List<BigDataRainfallPredicionPageVO>> task14Hour = asyncService.bigDateRainfall(builderBigDataRainfallPredictionQO(time14HourFront, time14HourAfter));
        CompletableFuture<List<BigDataRainfallPredicionPageVO>> task17Hour = asyncService.bigDateRainfall(builderBigDataRainfallPredictionQO(time17HourFront, time17HourAfter));
        CompletableFuture<List<BigDataRainfallPredicionPageVO>> task20Hour = asyncService.bigDateRainfall(builderBigDataRainfallPredictionQO(time20HourFront, time20HourAfter));
        CompletableFuture<List<BigDataRainfallPredicionPageVO>> task23Hour = asyncService.bigDateRainfall(builderBigDataRainfallPredictionQO(time23HourFront, time23HourAfter));
        // 等待所有任务都执行完
        CompletableFuture.allOf(task2Hour, task5Hour, task8Hour, task11Hour, task14Hour, task17Hour, task20Hour, task23Hour).join();
        List<BigDataRainfallPredicionPageVO> bigDataRainfallPredicionPageList = Lists.newArrayList();
        try {
           // 获取每个任务的返回结果
            bigDataRainfallPredicionPageList.addAll(task2Hour.get());
            bigDataRainfallPredicionPageList.addAll(task5Hour.get());
            bigDataRainfallPredicionPageList.addAll(task8Hour.get());
            bigDataRainfallPredicionPageList.addAll(task11Hour.get());
            bigDataRainfallPredicionPageList.addAll(task14Hour.get());
            bigDataRainfallPredicionPageList.addAll(task17Hour.get());
            bigDataRainfallPredicionPageList.addAll(task20Hour.get());
            bigDataRainfallPredicionPageList.addAll(task23Hour.get());
        } catch (Exception e) {
           log.error(e.toString());
        }
        return bigDataRainfallPredicionPageList;
    }

https://zhuanlan.zhihu.com/p/134636915 SpringBoot中如何优雅的使用多线程

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Boot使用多线程可以使用Java多线程编程的相关类和接口,例如`Thread`、`Runnable`和`Executor`等,并且可以通过Spring的依赖注入特性来管理线程池。 下面是一个示例代码: ```java import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Component; @Component public class MultiThreadService { @Async // 声明这个方法是一个异步方法,Spring会自动创建一个线程池来执行这个方法 public void doTask1() { // 具体操作 System.out.println("Task 1 is running on thread " + Thread.currentThread().getName()); } @Async public void doTask2() { // 具体操作 System.out.println("Task 2 is running on thread " + Thread.currentThread().getName()); } } ``` 在以上示例,我们在Spring Boot定义了一个`MultiThreadService`类,其定义了两个异步方法`doTask1`和`doTask2`。在这两个方法上添加了`@Async`注解,表示这两个方法是异步执行的。 接下来,在Spring Boot的配置类添加`@EnableAsync`注解,启用异步方法。示例代码如下: ```java import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.annotation.EnableAsync; @Configuration @EnableAsync // 启用异步方法 public class AsyncConfig { } ``` 最后,在Spring Boot的控制器调用`MultiThreadService`的异步方法即可。示例代码如下: ```java import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class MultiThreadController { @Autowired private MultiThreadService multiThreadService; @GetMapping("/test") public String test() { multiThreadService.doTask1(); multiThreadService.doTask2(); return "Success"; } } ``` 以上代码,我们在控制器调用了`MultiThreadService`的异步方法`doTask1`和`doTask2`,Spring会自动创建一个线程池来执行这两个方法。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值