提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
在我们的日常开发中,难免会遇到请求响应的速度慢的问题。这时就可以使用多线程的方式,一个方法多个线程同时执行,但是,不是所有的方法都能使用多线程,需具体问题具体分析。
一、什么是多线程编程?它的优势是什么?
多线程编程是指在一个程序中同时使用多个线程来执行任务。多线程编程的优势包括:
- 提高程序的并发性:多个线程可以同时执行,从而提高程序的执行效率和响应性。
- 提高资源利用率:多线程共享同一进程的资源,避免了创建多个进程时的资源开销。
- 简化编程模型:多线程编程相对于多进程编程更轻量级,线程之间的通信和数据共享更加简单,编程模型更容易理解和实现。
- 支持多核处理器:多线程编程可以充分利用多核处理器的优势,提高程序的执行效率
多线程编程也存在一些挑战,如线程同步、资源竞争和死锁等问题,需要合理设计和管理线程的执行。
二、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