使用SpringBoot内置多线程

作者: adm 分类: java 发布时间: 2023-08-22

SpringBoot使用多线程
一 概述
1 为什么使用多线程
  在我们开发系统过程中,经常会处理一些好费时间的任务(如向数据库中插入上百万数据,将会导致系统阻塞),这个时候就会自然想到使用多线程。

  当数据量大的时候,一个新的线程满足不了系统的要求,但是只有少量的请求可以直接new一个新线程,如下代码。

// 少量请求可以这样做
new Thread(){
    @Override
    public void run() {
        //TODO异步任务
    }
}.start();

2 为什么使用Spring来实现多线程
使用Spring比使用JDK原生的并发API更简单。(@Async就能解决)。
一般的开发环境都会集成Spring框架,Bean也都交给Spring来管理,因此,Spring实现多线程更简单。
3 为什么需要使用异步(多线程)
传统的调用方式:调用一个服务,需要等待服务调用完成后,才能执行后面的代码,因此,需要等待时间。
使用异步的方式:调用一个服务的同时,继续执行后面的代码,几乎是不需要多少的等待时间。

二 SpringBoot使用多线程
1 如何使用
在 SpringBoot 中对其进行了简化处理,只需要配置一个类型为 java.util.concurrent.TaskExecutor
或其子类( 一般使用 Spring 提供的ThreadPoolTaskExecutor 类)的Bean,并在配置类或直接在程序入口类上声明注解 @EnableAsync。
调用也简单,在由Spring管理的对象的方法上标注注解 @Async,显式调用即可生效。

2 配置多线程
通过新增配置类的方式,使用 ThreadPoolTaskExecutor配置Bean

@Configuration
// 通过注解启用异步任务
@EnableAsync 
public class ThreadConfig {
    @Bean
    public ThreadPoolTaskExecutor executor(){
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        //配置核心线程数
        executor.setCorePoolSize(15);
        //配置最大线程数
        executor.setMaxPoolSize(30);
        //配置队列大小
        executor.setQueueCapacity(1000);
        //线程的名称前缀
        executor.setThreadNamePrefix("Executor-");
        //线程活跃时间(秒)
        //executor.setKeepAliveSeconds(60);
        //等待所有任务结束后再关闭线程池
        executor.setWaitForTasksToCompleteOnShutdown(true);
        //设置拒绝策略
        //executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        //执行初始化
        executor.initialize();
        return executor;
    }
}

如果只是简单的参数配置,那么直接在配置文件中加入如下配置即可

# 多线程配置
spring:
    task:
        execution:
        pool:
            core-size: 8
            max-size: 256
            keep-alive: 60000
            queue-capacity: 256
        thread-name-prefix: test

注意,以上通过yaml配置的方式,需要在启动类上加上多线程的启动注解。

// 通过注解启用异步任务
@EnableAsync
@SpringBootApplication
public class DbpmsApplication {
    public static void main(String[] args) {
        SpringApplication.run(DbpmsApplication.class, args);
    }
}

3 使用多线程
service层

public interface Test{
    // 不能有返回值,如果需要返回值需要callback方法
    void saveObject(String str);
}

service实现层

// 注解不再是@Override而是@Async
@Async
public void saveObject(String str){
    // 打印线程名,看是否开启了多线程
    String tName=Thread.currentThread().getName();
    System.err.println("调用的线程名字:"+tName);
    // 可以在下方添加保存数据库操作
}

测试类

@Test
void testMd503() {
    sysLogService.saveObject("张三");
    sysLogService.saveObject("李四");
    sysLogService.saveObject("王五");
    sysLogService.saveObject("赵六");
}

打印结果

如果不通过@Async注解的方式声明并创建多线程,也可以直接通过注入的ThreadPoolTaskExecutor类的execute方法来创建多线程,如下所示。

@RestController
@RequestMapping("/test")
public class ThreadPoolController {
    @Autowired
    private SysLogService sysLogService;
	// 注入线程池类
    @Autowired
    private ThreadPoolTaskExecutor executor;

    @GetMapping("/test")
    public Results test(){
        // 线程异步导入数据库,会异步开始执行新增方法,同时原线程不会等待,继续执行。实现了异步操作。
        executor.execute(() -> sysLogService.saveObject("张三"););
        Results results = Results.success();
        return results;
    }
}

如果觉得我的文章对您有用,请随意赞赏。您的支持将鼓励我继续创作!