diff --git a/spring/spring boot/Spring Boot Async.md b/spring/spring boot/Spring Boot Async.md index fa49cdf..9f66eb5 100644 --- a/spring/spring boot/Spring Boot Async.md +++ b/spring/spring boot/Spring Boot Async.md @@ -1,4 +1,5 @@ # Spring Boot Async +## Spring Executor和Scheduler的自动配置 当当前上下文中没有Executor类型的bean对象时,spring boot会自动配置一个ThreadPoolTaskExecutor类型的bean对象,并且将该bean对象和异步task执行(@EnableAsync)和spring mvc异步请求处理关联在一起。 该默认创建的ThreadPoolTaskExecutor默认使用8个核心线程,并且线程数量可以根据负载动态的增加或者减少。 可以通过如下方式对ThreadPoolTaskExecutor进行配置: @@ -9,10 +10,63 @@ spring.task.execution.pool.max-size=16 spring.task.execution.pool.queue-capacity=100 # 当线程空闲10s(默认60s)时会进行回收 spring.task.execution.pool.keep-alive=10s +# 设置核心线程数量 +spring.task.execution.pool.core-size=8 ``` 如果使用@EnableScheduling,一个ThreadPoolTaskScheduler也可以被配置。该线程池默认使用一个线程,但是也可以动态设置: ```properties spring.task.scheduling.thread-name-prefix=scheduling- spring.task.scheduling.pool.size=2 ``` +## Task Execution and Scheduling +Spring通过TaskExecutor和TaskScheduler接口为task的异步执行和调度提供了抽象。 +### Task Execution Abstraction +Executor对应的是JDK中线程池的概念。在Spring中,TaskExecutor接口和java.util.concurrent.Executor接口相同,该接口中只有一个execute方法(execute(Runnable task)),接受一个task。 +### TaskExecutor接口的实现种类 +Spring中包含许多预制的TaskExecutor实现类,该实现类如下: +- SyncTaskExecutor:该实现类不会执行异步的调用,所有任务的执行都会发生在调用该executor的线程中。(通常使用在不需要多线程的场景) +- SimpleAsyncTaskExecutor:该实现类不会复用任何的线程,相反的,对于每次调用该executor,都会使用一个全新的线程。但是,该实现类的确支持对并发数量的限制,该executor会阻塞任何超过并发数量限制的调用,直到slot被释放为止。(SimpleAsyncTaskExecutor并不支持池化技术) +- ConcurrentTaskExecutor:该实现类是java.util.concurrent.Executor实例的adapter,其可以将java.util.concurrent.Executor实例的配置参数以bean properties的形式暴露。(当ThreadPoolTaskExecutor的灵活性无法满足需求时,可以使用ConcurrentTaskExecutor) +- ThreadPoolTaskExecutor:该实现类型是最广泛被使用的。该实现类可以通过bean properties来配置java.util.concurrent.ThreadPoolExecutor实例,并且将该实例wrap在TaskExecutor实例中。当想要使用另一种java.util.concurrent.Executor时,可以使用ConcurrentTaskExecutor。 +- DefaultManagedTaskExecutor:该实现使用了通过JNDI获取的ManagedExecutorService + +### TaskExecutor的使用 +在springboot中,当使用@EnableAsync时,可以通过配置ThreadPoolExecutor的bean properties来配置线程池的核心线程数和最大线程数等属性。 +```properties +# 该线程池最多含有16个线程 +spring.task.execution.pool.max-size=16 +# 有有界队列存放task,上限为100 +spring.task.execution.pool.queue-capacity=100 +# 当线程空闲10s(默认60s)时会进行回收 +spring.task.execution.pool.keep-alive=10s +# 设置核心线程数量 +spring.task.execution.pool.core-size=8 +``` + +## Spring TaskScheduler Abstraction +为了在特定的时间点执行task,Spring引入了TaskScheduler接口,接口定义如下: +```java +public interface TaskScheduler { + + ScheduledFuture schedule(Runnable task, Trigger trigger); + + ScheduledFuture schedule(Runnable task, Instant startTime); + + ScheduledFuture scheduleAtFixedRate(Runnable task, Instant startTime, Duration period); + + ScheduledFuture scheduleAtFixedRate(Runnable task, Duration period); + + ScheduledFuture scheduleWithFixedDelay(Runnable task, Instant startTime, Duration delay); + + ScheduledFuture scheduleWithFixedDelay(Runnable task, Duration delay); +``` +> scheduleAtFixedRate和scheduleAtFixedDelay区别: +> - fixed rate:表示两个task执行开始时间的间隔 +> - fixed delay:表示上一个task结束时间和下一个task开始时间的间隔 +> +> 实例如下: +> - fixed rate:TTWWWTTTWWT...(开始时间间隔为5) +> - fixed delay:TTWWWWWTTTTWWWWWTTTTTTTWWWWWT...(上次结束和下次开始之间的间隔为5) +> +> **通常,TaskScheduler默认情况下是单线程执行的,故而fixed rate执行时,如果一个Task执行时间超过period时,在当前task执行完成之前,下一个task并不会开始执行。下一个task会等待当前task执行完成之后立马执行。**