相关推荐recommended
Spring Boot中多线程的使用
作者:mmseoamin日期:2024-04-30

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

目录

  • 前言
  • 一、什么是多线程编程?它的优势是什么?
  • 二、Java中实现多线程的方式有哪些?
  • 三、线程池构造器
  • 四、SpringBoot中使用多线程
    • 1.配置线程池
    • 2.使用多线程

      前言

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


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

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

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

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

        二、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