Files
rikako-note/spring/spring boot/Spring Boot Async.md
2023-01-04 23:54:51 +08:00

4.6 KiB
Raw Blame History

Spring Boot Async

Spring Executor和Scheduler的自动配置

当当前上下文中没有Executor类型的bean对象时spring boot会自动配置一个ThreadPoolTaskExecutor类型的bean对象并且将该bean对象和异步task执行@EnableAsync和spring mvc异步请求处理关联在一起。
该默认创建的ThreadPoolTaskExecutor默认使用8个核心线程并且线程数量可以根据负载动态的增加或者减少。
可以通过如下方式对ThreadPoolTaskExecutor进行配置

# 该线程池最多含有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

如果使用@EnableScheduling一个ThreadPoolTaskScheduler也可以被配置。该线程池默认使用一个线程但是也可以动态设置

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来配置线程池的核心线程数和最大线程数等属性。

# 该线程池最多含有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

为了在特定的时间点执行taskSpring引入了TaskScheduler接口接口定义如下

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 rateTTWWWTTTWWT...(开始时间间隔为5)
  • fixed delayTTWWWWWTTTTWWWWWTTTTTTTWWWWWT...(上次结束和下次开始之间的间隔为5)

通常TaskScheduler默认情况下是单线程执行的故而fixed rate执行时如果一个Task执行时间超过period时在当前task执行完成之前下一个task并不会开始执行。下一个task会等待当前task执行完成之后立马执行。