Bootstrap

Spring Boot中多线程的使用

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

在我们的日常开发中,难免会遇到请求响应的速度慢的问题。这时就可以使用多线程的方式,一个方法多个线程同时执行,但是,不是所有的方法都能使用多线程,需具体问题具体分析。


一、什么是多线程编程?它的优势是什么?

多线程编程是指在一个程序中同时使用多个线程来执行任务。多线程编程的优势包括:

  • 提高程序的并发性:多个线程可以同时执行,从而提高程序的执行效率和响应性。
  • 提高资源利用率:多线程共享同一进程的资源,避免了创建多个进程时的资源开销。
  • 简化编程模型:多线程编程相对于多进程编程更轻量级,线程之间的通信和数据共享更加简单,编程模型更容易理解和实现。
  • 支持多核处理器:多线程编程可以充分利用多核处理器的优势,提高程序的执行效率

多线程编程也存在一些挑战,如线程同步、资源竞争和死锁等问题,需要合理设计和管理线程的执行。

二、Java中实现多线程的方式有哪些?

实现多线程的方式有以下几种:

  • 继承Thread类:创建一个继承自Thread类的子类,重写run()方法来定义线程的执行逻辑。
  • 实现Runnable接口:创建一个实现了Runnable接口的类,并实现其中的run()方法,然后将该类的实例传递给Thread类的构造函数创建线程对象。
  • 实现Callable接口:创建一个实现了Callable接口的类,并实现其中的call()方法,可以通过ExecutorService提交Callable对象来创建并执行线程,并返回执行结果。
  • 使用线程池:通过Executor框架创建线程池,可以管理和复用线程,提高线程的执行效率和资源利用率。

三、线程池构造器

线程池构造器的7个参数:

  • CorePoolSize:核心线程数,它是不会被销毁的
  • MaximumPoolSize :最大线程数,核心线程数+非核心线程数的总和
  • KeepAliveTime:非核心线程的最大空闲时间,到了这个空闲时间没被使用,非核心线程销毁
  • Unit:空闲时间单位
  • WorkQueue:是一个BlockingQueue阻塞队列,超过核心线程数的任务会进入队列排队
  • ThreadFactory:它是一个创建新线程的工厂
  • Handler:拒绝策略,任务超过最大线程数+队列排队数 ,多出来的任务该如何处理取决于Handler

四、SpringBoot中使用多线程

1.配置线程池

在Spring Boot中配置多线程可以通过使用ThreadPoolTaskExecutor来实现。首先,需要在项目中添加一个异步配置类。这个配置类需要使用@Configuration和@EnableAsync注解,并实现AsyncConfigurer接口。在这个配置类中,你可以设置线程池的各种参数。比如,你可以设置CorePoolSize来指定线程池的最小线程数,MaxPoolSize来指定线程池的最大还可以设置ThreadNamePrefix来指定线程的名称前缀。在getAsyncExecutor方法中,你需要创建一个ThreadPoolTaskExecutor对象,并设置相应的参数。最后,通过调用initialize方法来初始化线程池,并将其返回。getAsyncUncaughtExceptionHandler方法用于设置线程池中出现异常时的处理方式。这里使用了SimpleAsyncUncaughtExceptionHandler作为默认的异常处理器。

import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.aop.interceptor.SimpleAsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * 线程池配置
 */
@Configuration
@EnableAsync
public class ThreadPoolConfig implements AsyncConfigurer {

    @Override
    public Executor getAsyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        // 核心线程数:线程池创建的时候初始化的线程数
        executor.setCorePoolSize(10);
        // 最大线程数:线程池最大的线程数,只有缓冲队列满了之后才会申请超过核心线程数的线程
        executor.setMaxPoolSize(20);
        // 等待队列:用来缓冲执行任务的队列
        executor.setQueueCapacity(300);
        // 最大空闲时间:超过核心线程之外的线程到达200秒后会被销毁
        executor.setKeepAliveSeconds(200);
        // 拒绝策略:超过线程容量,拒绝策略设置(由调用的线程执行)
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        // 线程名称前缀
        executor.setThreadNamePrefix("Async Task-");
        // 初始化线程
        executor.initialize();
        return executor;
    }

    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return new SimpleAsyncUncaughtExceptionHandler();
    }
}

通过以上的配置,你就可以在Spring Boot中使用多线程了。可以根据你的项目需求来设置合适的线程池参数。

2.使用多线程

通过controller层调用测试 Async。

@RestController
@RequestMapping("/thread")
public class ThreadPoolController {

    @Autowired
    private ThreadPoolService threadPoolService;

    @GetMapping("/test")
    public void threadTest () throws InterruptedException {
        for (int i = 0; i <= 10; i++) {
            threadPoolService.threadTest(i);
        }
    }
}

通过@Async注解表明该方法是异步方法,如果注解在类上,那表明这个类里面的所有方法都是异步的。

@Service
public class ThreadPoolServiceImpl implements ThreadPoolService {

    @Override
    @Async
    public void threadTest(int i) {
        System.out.println("线程" + Thread.currentThread().getName() + " 执行异步任务:" + i);
    }
}

测试执行结果如下 线程的前缀“Async Task-”即为线程池配置中的线程名称前缀(可根据自己的喜好修改)

线程Async Task-3 执行异步任务:0
线程Async Task-2 执行异步任务:2
线程Async Task-1 执行异步任务:1
线程Async Task-2 执行异步任务:4
线程Async Task-3 执行异步任务:3
线程Async Task-5 执行异步任务:5
线程Async Task-1 执行异步任务:6
线程Async Task-2 执行异步任务:7
线程Async Task-4 执行异步任务:8
线程Async Task-6 执行异步任务:9
;