Package org.springframework.scheduling.concurrent

# Class SimpleAsyncTaskScheduler

java.lang.Object
org.springframework.util.CustomizableThreadCreator
org.springframework.core.task.SimpleAsyncTaskExecutor
org.springframework.scheduling.concurrent.SimpleAsyncTaskScheduler

All Implemented Interfaces:
  `Serializable`, `AutoCloseable`, `Executor`, `EventListener`, `org.springframework.beans.factory.Aware`, `ApplicationContextAware`, `ApplicationListener<ContextClosedEvent>`, `Lifecycle`, `Phased`, `SmartLifecycle`, `org.springframework.core.task.AsyncListenableTaskExecutor`, `org.springframework.core.task.AsyncTaskExecutor`, `org.springframework.core.task.TaskExecutor`, `TaskScheduler`

public class SimpleAsyncTaskScheduler extends org.springframework.core.task.SimpleAsyncTaskExecutor implements TaskScheduler, ApplicationContextAware, SmartLifecycle, ApplicationListener<ContextClosedEvent>
A simple implementation of Spring's `TaskScheduler` interface, using a single scheduler thread and executing every scheduled task in an individual separate thread. This is an attractive choice with virtual threads on JDK 21, expecting common usage with `setVirtualThreads(true)`.

NOTE: Scheduling with a fixed delay enforces execution on a single scheduler thread, in order to provide traditional fixed-delay semantics! Prefer the use of fixed rates or cron triggers instead which are a better fit with this thread-per-task scheduler variant.

Supports a graceful shutdown through `SimpleAsyncTaskExecutor.setTaskTerminationTimeout(long)`, at the expense of task tracking overhead per execution thread at runtime. Supports limiting concurrent threads through `SimpleAsyncTaskExecutor.setConcurrencyLimit(int)`. By default, the number of concurrent task executions is unlimited. This allows for dynamic concurrency of scheduled task executions, in contrast to `ThreadPoolTaskScheduler` which requires a fixed pool size.

NOTE: This implementation does not reuse threads! Consider a thread-pooling TaskScheduler implementation instead, in particular for scheduling a large number of short-lived tasks. Alternatively, on JDK 21, consider setting `SimpleAsyncTaskExecutor.setVirtualThreads(boolean)` to `true`.

Extends `SimpleAsyncTaskExecutor` and can serve as a fully capable replacement for it, for example, as a single shared instance serving as a `TaskExecutor` as well as a `TaskScheduler`. This is generally not the case with other executor/scheduler implementations which tend to have specific constraints for the scheduler thread pool, requiring a separate thread pool for general executor purposes in practice.

NOTE: This scheduler variant does not track the actual completion of tasks but rather just the hand-off to an execution thread. As a consequence, a `ScheduledFuture` handle (for example, from `schedule(Runnable, Instant)`) represents that hand-off rather than the actual completion of the provided task (or series of repeated tasks). Also, this scheduler participates in lifecycle management to a limited degree only, stopping trigger firing and fixed-delay task execution but not stopping the execution of handed-off tasks.

As an alternative to the built-in thread-per-task capability, this scheduler can also be configured with a separate target executor for scheduled task execution through `setTargetTaskExecutor(java.util.concurrent.Executor)`: for example, pointing to a shared `ThreadPoolTaskExecutor` bean. This is still rather different from a `ThreadPoolTaskScheduler` setup since it always uses a single scheduler thread while dynamically dispatching to the target thread pool which may have a dynamic core/max pool size range, participating in a shared concurrency limit.

Since:
  6.1
Author:
  Juergen Hoeller
See Also:
  - `SimpleAsyncTaskExecutor.setVirtualThreads(boolean)`
  - `SimpleAsyncTaskExecutor.setTaskTerminationTimeout(long)`
  - `SimpleAsyncTaskExecutor.setConcurrencyLimit(int)`
  - `SimpleAsyncTaskExecutor`
  - `ThreadPoolTaskScheduler`
  - Serialized Form

## Field Summary

Fields
Modifier and Type
Field
Description
`static final int`
`DEFAULT_PHASE`
The default phase for an executor `SmartLifecycle`: `Integer.MAX_VALUE / 2`.

### Fields inherited from class org.springframework.core.task.SimpleAsyncTaskExecutor

`NO_CONCURRENCY, UNBOUNDED_CONCURRENCY`

### Fields inherited from interface org.springframework.core.task.AsyncTaskExecutor

`TIMEOUT_IMMEDIATE, TIMEOUT_INDEFINITE`

## Constructor Summary

Constructors
Constructor
Description
`SimpleAsyncTaskScheduler()`

## Method Summary

Modifier and Type
Method
Description
`void`
`close()`
`protected void`
`doExecute(Runnable task)`
`void`
`execute(Runnable task)`
`Clock`
`getClock()`
Return the clock to use for scheduling purposes.
`int`
`getPhase()`
Return the lifecycle phase for pausing and resuming this executor.
`boolean`
`isRunning()`
Check whether this component is currently running.
`void`
`onApplicationEvent(ContextClosedEvent event)`
Handle an application event.
`ScheduledFuture<?>`
`schedule(Runnable task, Instant startTime)`
Schedule the given `Runnable`, invoking it at the specified execution time.
`ScheduledFuture<?>`
`schedule(Runnable task, Trigger trigger)`
Schedule the given `Runnable`, invoking it whenever the trigger indicates a next execution time.
`ScheduledFuture<?>`
`scheduleAtFixedRate(Runnable task, Duration period)`
Schedule the given `Runnable`, starting as soon as possible and invoking it with the given period.
`ScheduledFuture<?>`
`scheduleAtFixedRate(Runnable task, Instant startTime, Duration period)`
Schedule the given `Runnable`, invoking it at the specified execution time and subsequently with the given period.
`ScheduledFuture<?>`
`scheduleWithFixedDelay(Runnable task, Duration delay)`
Schedule the given `Runnable`, starting as soon as possible and invoking it with the given delay between the completion of one execution and the start of the next.
`ScheduledFuture<?>`
`scheduleWithFixedDelay(Runnable task, Instant startTime, Duration delay)`
Schedule the given `Runnable`, invoking it at the specified execution time and subsequently with the given delay between the completion of one execution and the start of the next.
`void`
`setApplicationContext(ApplicationContext applicationContext)`
Set the ApplicationContext that this object runs in.
`void`
`setClock(Clock clock)`
Set the clock to use for scheduling purposes.
`void`
`setErrorHandler(org.springframework.util.ErrorHandler errorHandler)`
Provide an `ErrorHandler` strategy.
`void`
`setPhase(int phase)`
Specify the lifecycle phase for pausing and resuming this executor.
`void`
`setTargetTaskExecutor(Executor targetTaskExecutor)`
Specify a custom target `Executor` to delegate to for the individual execution of scheduled tasks.
`void`
`start()`
Start this component.
`void`
`stop()`
Stop this component, typically in a synchronous fashion, such that the component is fully stopped upon return of this method.
`void`
`stop(Runnable callback)`
Indicates that a Lifecycle component must stop if it is currently running.
`Future<?>`
`submit(Runnable task)`
`<T> Future<T>`
`submit(Callable<T> task)`
`org.springframework.util.concurrent.ListenableFuture<?>`
`submitListenable(Runnable task)`
`<T> org.springframework.util.concurrent.ListenableFuture<T>`
`submitListenable(Callable<T> task)`

### Methods inherited from class org.springframework.core.task.SimpleAsyncTaskExecutor

`execute, getConcurrencyLimit, getThreadFactory, isActive, isThrottleActive, newThread, setConcurrencyLimit, setRejectTasksWhenLimitReached, setTaskDecorator, setTaskTerminationTimeout, setThreadFactory, setVirtualThreads`

### Methods inherited from class org.springframework.util.CustomizableThreadCreator

`createThread, getDefaultThreadNamePrefix, getThreadGroup, getThreadNamePrefix, getThreadPriority, isDaemon, nextThreadName, setDaemon, setThreadGroup, setThreadGroupName, setThreadNamePrefix, setThreadPriority`

### Methods inherited from class java.lang.Object

`clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait`

### Methods inherited from interface org.springframework.context.ApplicationListener

`supportsAsyncExecution`

### Methods inherited from interface org.springframework.core.task.AsyncTaskExecutor

`submitCompletable, submitCompletable`

### Methods inherited from interface org.springframework.context.SmartLifecycle

`isAutoStartup`

### Methods inherited from interface org.springframework.scheduling.TaskScheduler

`schedule, scheduleAtFixedRate, scheduleAtFixedRate, scheduleWithFixedDelay, scheduleWithFixedDelay`

## Field Details

### DEFAULT_PHASE

public static final int DEFAULT_PHASE
The default phase for an executor `SmartLifecycle`: `Integer.MAX_VALUE / 2`.

Since:
  6.2
See Also:
  - `getPhase()`
  - `ExecutorConfigurationSupport.DEFAULT_PHASE`
  - Constant Field Values

## Constructor Details

### SimpleAsyncTaskScheduler

public SimpleAsyncTaskScheduler()

## Method Details

### setErrorHandler

public void setErrorHandler(org.springframework.util.ErrorHandler errorHandler)
Provide an `ErrorHandler` strategy.

Since:
  6.2

### setClock

public void setClock(Clock clock)
Set the clock to use for scheduling purposes.

The default clock is the system clock for the default time zone.

See Also:
  - `Clock.systemDefaultZone()`

### getClock

public Clock getClock()
Description copied from interface: `TaskScheduler`
Return the clock to use for scheduling purposes.

Specified by:
  `getClock` in interface `TaskScheduler`
See Also:
  - `Clock.systemDefaultZone()`

### setPhase

public void setPhase(int phase)
Specify the lifecycle phase for pausing and resuming this executor. The default is `DEFAULT_PHASE`.

See Also:
  - `SmartLifecycle.getPhase()`

### getPhase

public int getPhase()
Return the lifecycle phase for pausing and resuming this executor.

Specified by:
  `getPhase` in interface `Phased`
Specified by:
  `getPhase` in interface `SmartLifecycle`
See Also:
  - `setPhase(int)`

### setTargetTaskExecutor

public void setTargetTaskExecutor(Executor targetTaskExecutor)
Specify a custom target `Executor` to delegate to for the individual execution of scheduled tasks. This can for example be set to a separate thread pool for executing scheduled tasks, whereas this scheduler keeps using its single scheduler thread.

If not set, the regular `SimpleAsyncTaskExecutor` arrangements kicks in with a new thread per task.

### setApplicationContext

public void setApplicationContext(ApplicationContext applicationContext)
Description copied from interface: `ApplicationContextAware`
Set the ApplicationContext that this object runs in. Normally this call will be used to initialize the object.

Invoked after population of normal bean properties but before an init callback such as `InitializingBean.afterPropertiesSet()` or a custom init-method. Invoked after `ResourceLoaderAware.setResourceLoader(org.springframework.core.io.ResourceLoader)`, `ApplicationEventPublisherAware.setApplicationEventPublisher(org.springframework.context.ApplicationEventPublisher)` and `MessageSourceAware`, if applicable.

Specified by:
  `setApplicationContext` in interface `ApplicationContextAware`
Parameters:
  `applicationContext` - the ApplicationContext object to be used by this object
See Also:
  - `BeanInitializationException`

### doExecute

protected void doExecute(Runnable task)

Overrides:
  `doExecute` in class `org.springframework.core.task.SimpleAsyncTaskExecutor`

### execute

public void execute(Runnable task)

Specified by:
  `execute` in interface `Executor`
Specified by:
  `execute` in interface `org.springframework.core.task.TaskExecutor`
Overrides:
  `execute` in class `org.springframework.core.task.SimpleAsyncTaskExecutor`

### submit

public Future<?> submit(Runnable task)

Specified by:
  `submit` in interface `org.springframework.core.task.AsyncTaskExecutor`
Overrides:
  `submit` in class `org.springframework.core.task.SimpleAsyncTaskExecutor`

### submit

public <T> Future<T> submit(Callable<T> task)

Specified by:
  `submit` in interface `org.springframework.core.task.AsyncTaskExecutor`
Overrides:
  `submit` in class `org.springframework.core.task.SimpleAsyncTaskExecutor`

### submitListenable

public org.springframework.util.concurrent.ListenableFuture<?> submitListenable(Runnable task)

Specified by:
  `submitListenable` in interface `org.springframework.core.task.AsyncListenableTaskExecutor`
Overrides:
  `submitListenable` in class `org.springframework.core.task.SimpleAsyncTaskExecutor`

### submitListenable

public <T> org.springframework.util.concurrent.ListenableFuture<T> submitListenable(Callable<T> task)

Specified by:
  `submitListenable` in interface `org.springframework.core.task.AsyncListenableTaskExecutor`
Overrides:
  `submitListenable` in class `org.springframework.core.task.SimpleAsyncTaskExecutor`

### schedule

@Nullable public ScheduledFuture<?> schedule(Runnable task, Trigger trigger)
Description copied from interface: `TaskScheduler`
Schedule the given `Runnable`, invoking it whenever the trigger indicates a next execution time.

Execution will end once the scheduler shuts down or the returned `ScheduledFuture` gets cancelled.

Specified by:
  `schedule` in interface `TaskScheduler`
Parameters:
  `task` - the Runnable to execute whenever the trigger fires
  `trigger` - an implementation of the `Trigger` interface, for example, a `CronTrigger` object wrapping a cron expression
Returns:
  a `ScheduledFuture` representing pending execution of the task, or `null` if the given Trigger object never fires (i.e. returns `null` from `Trigger.nextExecution(org.springframework.scheduling.TriggerContext)`)
See Also:
  - `CronTrigger`

### schedule

public ScheduledFuture<?> schedule(Runnable task, Instant startTime)
Description copied from interface: `TaskScheduler`
Schedule the given `Runnable`, invoking it at the specified execution time.

Execution will end once the scheduler shuts down or the returned `ScheduledFuture` gets cancelled.

Specified by:
  `schedule` in interface `TaskScheduler`
Parameters:
  `task` - the Runnable to execute whenever the trigger fires
  `startTime` - the desired execution time for the task (if this is in the past, the task will be executed immediately, i.e. as soon as possible)
Returns:
  a `ScheduledFuture` representing pending execution of the task

### scheduleAtFixedRate

public ScheduledFuture<?> scheduleAtFixedRate(Runnable task, Instant startTime, Duration period)
Description copied from interface: `TaskScheduler`
Schedule the given `Runnable`, invoking it at the specified execution time and subsequently with the given period.

Execution will end once the scheduler shuts down or the returned `ScheduledFuture` gets cancelled.

Specified by:
  `scheduleAtFixedRate` in interface `TaskScheduler`
Parameters:
  `task` - the Runnable to execute whenever the trigger fires
  `startTime` - the desired first execution time for the task (if this is in the past, the task will be executed immediately, i.e. as soon as possible)
  `period` - the interval between successive executions of the task
Returns:
  a `ScheduledFuture` representing pending execution of the task

### scheduleAtFixedRate

public ScheduledFuture<?> scheduleAtFixedRate(Runnable task, Duration period)
Description copied from interface: `TaskScheduler`
Schedule the given `Runnable`, starting as soon as possible and invoking it with the given period.

Execution will end once the scheduler shuts down or the returned `ScheduledFuture` gets cancelled.

Specified by:
  `scheduleAtFixedRate` in interface `TaskScheduler`
Parameters:
  `task` - the Runnable to execute whenever the trigger fires
  `period` - the interval between successive executions of the task
Returns:
  a `ScheduledFuture` representing pending execution of the task

### scheduleWithFixedDelay

public ScheduledFuture<?> scheduleWithFixedDelay(Runnable task, Instant startTime, Duration delay)
Description copied from interface: `TaskScheduler`
Schedule the given `Runnable`, invoking it at the specified execution time and subsequently with the given delay between the completion of one execution and the start of the next.

Execution will end once the scheduler shuts down or the returned `ScheduledFuture` gets cancelled.

Specified by:
  `scheduleWithFixedDelay` in interface `TaskScheduler`
Parameters:
  `task` - the Runnable to execute whenever the trigger fires
  `startTime` - the desired first execution time for the task (if this is in the past, the task will be executed immediately, i.e. as soon as possible)
  `delay` - the delay between the completion of one execution and the start of the next
Returns:
  a `ScheduledFuture` representing pending execution of the task

### scheduleWithFixedDelay

public ScheduledFuture<?> scheduleWithFixedDelay(Runnable task, Duration delay)
Description copied from interface: `TaskScheduler`
Schedule the given `Runnable`, starting as soon as possible and invoking it with the given delay between the completion of one execution and the start of the next.

Execution will end once the scheduler shuts down or the returned `ScheduledFuture` gets cancelled.

Specified by:
  `scheduleWithFixedDelay` in interface `TaskScheduler`
Parameters:
  `task` - the Runnable to execute whenever the trigger fires
  `delay` - the delay between the completion of one execution and the start of the next
Returns:
  a `ScheduledFuture` representing pending execution of the task

### start

public void start()
Description copied from interface: `Lifecycle`
Start this component.

Should not throw an exception if the component is already running.

In the case of a container, this will propagate the start signal to all components that apply.

Specified by:
  `start` in interface `Lifecycle`
See Also:
  - `SmartLifecycle.isAutoStartup()`

### stop

public void stop()
Description copied from interface: `Lifecycle`
Stop this component, typically in a synchronous fashion, such that the component is fully stopped upon return of this method. Consider implementing `SmartLifecycle` and its `stop(Runnable)` variant when asynchronous stop behavior is necessary.

Note that this stop notification is not guaranteed to come before destruction: On regular shutdown, `Lifecycle` beans will first receive a stop notification before the general destruction callbacks are being propagated; however, on hot refresh during a context's lifetime or on aborted refresh attempts, a given bean's destroy method will be called without any consideration of stop signals upfront.

Should not throw an exception if the component is not running (not started yet).

In the case of a container, this will propagate the stop signal to all components that apply.

Specified by:
  `stop` in interface `Lifecycle`
See Also:
  - `SmartLifecycle.stop(Runnable)`
  - `DisposableBean.destroy()`

### stop

public void stop(Runnable callback)
Description copied from interface: `SmartLifecycle`
Indicates that a Lifecycle component must stop if it is currently running.

The provided callback is used by the `LifecycleProcessor` to support an ordered, and potentially concurrent, shutdown of all components having a common shutdown order value. The callback must be executed after the `SmartLifecycle` component does indeed stop.

The `LifecycleProcessor` will call only this variant of the `stop` method; i.e. `Lifecycle.stop()` will not be called for `SmartLifecycle` implementations unless explicitly delegated to within the implementation of this method.

The default implementation delegates to `Lifecycle.stop()` and immediately triggers the given callback in the calling thread. Note that there is no synchronization between the two, so custom implementations may at least want to put the same steps within their common lifecycle monitor (if any).

Specified by:
  `stop` in interface `SmartLifecycle`
See Also:
  - `Lifecycle.stop()`
  - `SmartLifecycle.getPhase()`

### isRunning

public boolean isRunning()
Description copied from interface: `Lifecycle`
Check whether this component is currently running.

In the case of a container, this will return `true` only if all components that apply are currently running.

Specified by:
  `isRunning` in interface `Lifecycle`
Returns:
  whether the component is currently running

### onApplicationEvent

public void onApplicationEvent(ContextClosedEvent event)
Description copied from interface: `ApplicationListener`
Handle an application event.

Specified by:
  `onApplicationEvent` in interface `ApplicationListener<ContextClosedEvent>`
Parameters:
  `event` - the event to respond to

### close

public void close()

Specified by:
  `close` in interface `AutoCloseable`
Overrides:
  `close` in class `org.springframework.core.task.SimpleAsyncTaskExecutor`