java|Spring Boot 到底是单线程还是多线程

前言 我们知道用Spring Boot来构建项目非常的方便,开发过程中我们会使用它来快速的构建项目,自带tomcat容器、启动也会将需要配置的bean全部加载到我们的Spring容器里面。但是在调用Controller方法的时候,是单线程、还是多线程的呢,今天我们来一起研究下。
执行Controller 首先我们通过执行两个Controller方法,发现打印的日志,执行这两个方法分别是不同的线程,但是对创建的变量进行了叠加,因为Spring的默认是以单例模式创建的,所以就会导致线程不安全。
java|Spring Boot 到底是单线程还是多线程
文章图片

我们在?ontroller头部加入@Scope,使它的作用域变成原型模式,这时候我们再次执行方法。

@RequestMapping(“test”) @Scope(“prototype”) @RestController public class TestController { 复制代码

可以看到依旧是两个线程执行,但是我们变量的操作没有进行类加,而是分别进行了i++的操作,证明每次的reqeust请求都会创建一个bean。 注意??:我们写代码的时候千万不能在?ontroller里面定义常量,然后方法里面进行操作,会有很大的问题,这里只是做演示。
java|Spring Boot 到底是单线程还是多线程
文章图片

由此可见Spring Boot中Controller默认是单例模式,并且执行的时候是多线程的方式。
@Async 既然提到了这里,我们就来说下Spring Boot的一个多线程首先原理,先来看下我们的异步执行注解@Async,通过使用注解的方式,在我们需要异步执行方法的场景下,实现一个异步执行。 当然也离不开@EnableAsync这个注解,它是一个异步注解的开关。可以看到使用的是代理的模式。
java|Spring Boot 到底是单线程还是多线程
文章图片

通过看源码追踪到AsyncTaskExecutor 这个接口,看名字就知道是异步任务的一个线程池创建的接口,继承的TaskExecutor父接口。
java|Spring Boot 到底是单线程还是多线程
文章图片

可以看到ThreadPoolTaskExecutor这个线程池的配置类,可以看到异步操作其实是由创建线程池来完成的,通过向线程池提交task任务,用Future类接收,可以获取异步任务的执行结果。
java|Spring Boot 到底是单线程还是多线程
文章图片

java|Spring Boot 到底是单线程还是多线程
文章图片

使用Async 下面来通过自定线程池,然后先线程池提交我们的异步任务。
AsyncService异步方法
@Service public class AsyncService {private Logger logger = LoggerFactory./getLogger/(TestController.class); @Async(“taskExecutor”) public String getAsyncMessage(String message) { try { logger.info(“执行异步方法,message is “ + message); Thread./sleep/(1000); } catch (InterruptedException e) { e.printStackTrace(); }return message; } 复制代码

AsyncConfig异步线程池配置
public class AsyncConfig {@Bean(“taskExecutor”) public Executor taskExecutor(){ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); // 核心线程数:线程池创建时候初始化的线程数 executor.setCorePoolSize(10); // 最大线程数:线程池最大的线程数,只有在缓冲队列满了之后才会申请超过核心线程数的线程 executor.setMaxPoolSize(20); // 缓冲队列:用来缓冲执行任务的队列 executor.setQueueCapacity(500); // 允许线程的空闲时间60秒:当超过了核心线程之外的线程在空闲时间到达之后会被销毁 executor.setKeepAliveSeconds(60); // 线程池名的前缀:设置好了之后可以方便我们定位处理任务所在的线程池 executor.setThreadNamePrefix(“Async-task-“); // 缓冲队列满了之后的拒绝策略:由调用线程处理(一般是主线程) executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); executor.initialize(); return executor; } 复制代码

执行结果,我们可以看见异步方法通过我们定义的线程池提交,没有按照for循环的顺序提交,而是实现了异步的提交。
java|Spring Boot 到底是单线程还是多线程
文章图片

总结 Spring Boot框架是一个可以实现多线程的框架,不是一个线程安全的框架,我们要使它变成线程安全,还需要集成其他组件,包括用到一些线程安全的类,但是可以说明Spring Boot在执行Controller方法的时候确实是以多线程的方式执行的,包括异步的方法。
java|Spring Boot 到底是单线程还是多线程
文章图片

【java|Spring Boot 到底是单线程还是多线程】

    推荐阅读