您现在的位置是:首页 >技术交流 >Spring Boot注解@Async与线程池的配置网站首页技术交流

Spring Boot注解@Async与线程池的配置

没有昵称的打工仔 2024-06-26 14:24:01
简介Spring Boot注解@Async与线程池的配置

目录

使用异步注解创建异步任务

@Async注解

使用Demo

线程池配置

Spring Boot默认用于异步任务线程池配置

 线程池配置

 线程池隔离

为什么需要线程池隔离?

线程池隔离实现Demo

 线程池配置:

 异步任务:

测试demo

参考内容:


使用异步注解创建异步任务

@Async注解

异步注解,需要在 springboot主程序上配置@EnableAsync。

使用条件:任务本身之间不存在依赖关系

使用Demo

@Component
@Slf4j
public class AsyncTasksService {

    public static Random random = new Random();

    @Async
    public CompletableFuture<String> doTaskOne() throws Exception {
        log.info("doTaskOne()开始");
        long start = System.currentTimeMillis();
        Thread.sleep(random.nextInt(10000));
        long end = System.currentTimeMillis();
        log.info("doTaskOne()执行结束,耗时:" + (end - start) + "毫秒");
        return CompletableFuture.completedFuture("doTaskOne()执行结束");
    }
    @Async
    public CompletableFuture<String> doTaskTwo() throws Exception {
        log.info("doTaskTwo()开始");
        long start = System.currentTimeMillis();
        Thread.sleep(random.nextInt(10000));
        long end = System.currentTimeMillis();
        log.info("doTaskTwo()执行结束,耗时:" + (end - start) + "毫秒");
        return CompletableFuture.completedFuture("doTaskTwo()执行结束");
    }
    @Async
    public CompletableFuture<String> doTaskThree() throws Exception {
        log.info("doTaskThree()开始");
        long start = System.currentTimeMillis();
        Thread.sleep(random.nextInt(10000));
        long end = System.currentTimeMillis();
        log.info("doTaskThree()执行结束,耗时:" + (end - start) + "毫秒");
        return CompletableFuture.completedFuture("doTaskThree()执行结束");
    }
}
@SpringBootTest
@Slf4j
@RunWith(SpringRunner.class)
public class AsyncTasksTest {
    @Resource
    private AsyncTasksService asyncTasksService;
    @Test
    public void test() throws Exception {
        long start = System.currentTimeMillis();

        CompletableFuture<String> task1 = asyncTasksService.doTaskOne();
        CompletableFuture<String> task2 = asyncTasksService.doTaskTwo();
        CompletableFuture<String> task3 = asyncTasksService.doTaskThree();

        CompletableFuture.allOf(task1, task2, task3).join();

        long end = System.currentTimeMillis();

        log.info("任务全部完成,总耗时:" + (end - start) + "毫秒");
    }
}

 测试结果:

11:02:20.078 [task-3] INFO  com.springwork.high.asyncTasks.AsyncTasksService - doTaskThree()开始
11:02:20.078 [task-1] INFO  com.springwork.high.asyncTasks.AsyncTasksService - doTaskOne()开始
11:02:20.078 [task-2] INFO  com.springwork.high.asyncTasks.AsyncTasksService - doTaskTwo()开始
11:02:24.453 [task-2] INFO  com.springwork.high.asyncTasks.AsyncTasksService - doTaskTwo()执行结束,耗时:4375毫秒
11:02:26.571 [task-1] INFO  com.springwork.high.asyncTasks.AsyncTasksService - doTaskOne()执行结束,耗时:6493毫秒
11:02:27.570 [task-3] INFO  com.springwork.high.asyncTasks.AsyncTasksService - doTaskThree()执行结束,耗时:7492毫秒
11:02:27.571 [main] INFO  com.springwork.high.AsyncTasksTest - 任务全部完成,总耗时:7500毫秒

线程池配置

为了控制异步任务的并发不影响到应用的正常运作,我们必须要对线程池做好相应的配置,防止资源的过渡使用

Spring Boot默认用于异步任务线程池配置

源码位置:org.springframework.boot.autoconfigure.task.TaskExecutionProperties

 线程池配置

spring:
  task:
    execution:
      pool:
        core-size: 8
        max-size: 5
        queue-capacity: 10
        keep-alive: 60s
        allow-core-thread-timeout: true
      shutdown:
        await-termination: false
        await-termination-period:
      thread-name-prefix: hightask-
task:
  execution:
    pool:
      core-size: 8 (线程池创建时的初始化线程数,默认为8)
      max-size: 5 (线程池的最大线程数,默认为int最大值,即(2^31)-1)
      queue-capacity: 10 (用来缓冲执行任务的队列,默认为int最大值,即(2^31)-1)
      keep-alive: 60s  (线程终止前允许保持空闲的时间)
      allow-core-thread-timeout: true (是否允许核心线程超时)
    shutdown:
      await-termination: false (是否等待剩余任务完成后才关闭应用)
      await-termination-period: (等待剩余任务完成的最大时间)
    thread-name-prefix: hightask- (线程名的前缀)

 配置线程池,并将初始化线程数改成2后结果:

15:11:00.786 [hightask-1] INFO  com.springwork.high.asyncTasks.AsyncTasksService - doTaskOne()开始
15:11:00.786 [hightask-2] INFO  com.springwork.high.asyncTasks.AsyncTasksService - doTaskTwo()开始
15:11:02.434 [hightask-2] INFO  com.springwork.high.asyncTasks.AsyncTasksService - doTaskTwo()执行结束,耗时:1648毫秒
15:11:02.434 [hightask-2] INFO  com.springwork.high.asyncTasks.AsyncTasksService - doTaskThree()开始
15:11:04.397 [hightask-2] INFO  com.springwork.high.asyncTasks.AsyncTasksService - doTaskThree()执行结束,耗时:1963毫秒
15:11:04.757 [hightask-1] INFO  com.springwork.high.asyncTasks.AsyncTasksService - doTaskOne()执行结束,耗时:3971毫秒
15:11:04.757 [main] INFO  com.springwork.high.AsyncTasksTest - 任务全部完成,总耗时:3979毫秒

 线程池隔离

为什么需要线程池隔离?

@Async创建的异步任务都是共用的一个线程池,当有一些异步任务碰到性能问题的时候,是会直接影响其他异步任务的。

线程池隔离实现Demo

 线程池配置:

package com.springwork.high.asyncTasks;



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;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * @author gj
 * @version 1.0.0
 * @date 2023/5/26 15:25
 */
@EnableAsync
@Configuration
public class AsyncTasksPoolConfig {
    @Bean(name = "highExecutor1")
    public Executor asyncTaskExecutor1() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(2);
        executor.setMaxPoolSize(2);
        executor.setQueueCapacity(10);
        executor.setKeepAliveSeconds(60);
        executor.setThreadNamePrefix("high-1-");
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        return executor;
    }
    @Bean(name = "highExecutor2")
    public Executor asyncTaskExecutor2() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(2);
        executor.setMaxPoolSize(2);
        executor.setQueueCapacity(10);
        executor.setKeepAliveSeconds(60);
        executor.setThreadNamePrefix("high-2-");
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        return executor;
    }
}

 异步任务:

package com.springwork.high.asyncTasks;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import java.util.Random;
import java.util.concurrent.CompletableFuture;

/**
 * @author gj
 * @version 1.0.0
 * @date 2023/5/26 10:17
 */
@Component
@Slf4j
public class AsyncTasksService {

    public static Random random = new Random();

    @Async("highExecutor1")
    public CompletableFuture<String> doTaskOne(String taskName) throws Exception {
        log.info("开始任务:"+taskName);
        long start = System.currentTimeMillis();
        Thread.sleep(random.nextInt(10000));
        long end = System.currentTimeMillis();
        log.info("执行结束"+taskName+"耗时:" + (end - start) + "毫秒");
        return CompletableFuture.completedFuture("doTaskOne()执行结束");
    }
    @Async("highExecutor2")
    public CompletableFuture<String> doTaskTwo(String taskName) throws Exception {
        log.info("开始任务:"+taskName);
        long start = System.currentTimeMillis();
        Thread.sleep(random.nextInt(10000));
        long end = System.currentTimeMillis();
        log.info("执行结束"+taskName+"耗时:" + (end - start) + "毫秒");
        return CompletableFuture.completedFuture("执行结束");
    }
}

测试demo

        CompletableFuture<String> task1 = asyncTasksService.doTaskOne("1");
        CompletableFuture<String> task2 = asyncTasksService.doTaskOne("2");
        CompletableFuture<String> task3 = asyncTasksService.doTaskOne("3");
        CompletableFuture<String> task4 = asyncTasksService.doTaskTwo("4");
        CompletableFuture<String> task5 = asyncTasksService.doTaskTwo("5");
        CompletableFuture<String> task6 = asyncTasksService.doTaskTwo("6");


        CompletableFuture.allOf(task1, task2, task3,task4,task5,task6).join();

测试结果:

 15:44:50.899 [high-1-1] INFO  com.springwork.high.asyncTasks.AsyncTasksService - 开始任务:1
15:44:50.899 [high-2-2] INFO  com.springwork.high.asyncTasks.AsyncTasksService - 开始任务:5
15:44:50.899 [high-1-2] INFO  com.springwork.high.asyncTasks.AsyncTasksService - 开始任务:2
15:44:50.899 [high-2-1] INFO  com.springwork.high.asyncTasks.AsyncTasksService - 开始任务:4
15:44:51.159 [high-1-2] INFO  com.springwork.high.asyncTasks.AsyncTasksService - 执行结束2耗时:260毫秒
15:44:51.159 [high-1-2] INFO  com.springwork.high.asyncTasks.AsyncTasksService - 开始任务:3
15:44:51.442 [high-1-1] INFO  com.springwork.high.asyncTasks.AsyncTasksService - 执行结束1耗时:542毫秒
15:44:52.724 [high-1-2] INFO  com.springwork.high.asyncTasks.AsyncTasksService - 执行结束3耗时:1564毫秒
15:45:00.414 [high-2-2] INFO  com.springwork.high.asyncTasks.AsyncTasksService - 执行结束5耗时:9515毫秒
15:45:00.414 [high-2-2] INFO  com.springwork.high.asyncTasks.AsyncTasksService - 开始任务:6
15:45:00.690 [high-2-1] INFO  com.springwork.high.asyncTasks.AsyncTasksService - 执行结束4耗时:9791毫秒
15:45:00.764 [pool-2-thread-1] INFO  com.springwork.high.common.ScheduleTaskCommon - CurrentTime: 2023-05-26T15:45:00.764
15:45:08.855 [high-2-2] INFO  com.springwork.high.asyncTasks.AsyncTasksService - 执行结束6耗时:8440毫秒
15:45:08.856 [main] INFO  com.springwork.high.AsyncTasksTest - 任务全部完成,总耗时:17964毫秒

参考内容:

http://t.csdn.cn/Drzb4

http://t.csdn.cn/9usjv

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。