Up-to-date coverage of task executor and scheduler variants
Includes a clarification of ThreadPoolExecutor configuration options and a note on early AsyncConfigurer initialization. Issue: SPR-16944 Issue: SPR-16945
This commit is contained in:
@@ -76,6 +76,11 @@ import org.springframework.core.Ordered;
|
|||||||
* method.</li>
|
* method.</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
*
|
*
|
||||||
|
* <p><b>NOTE: {@link AsyncConfigurer} configuration classes get initialized early
|
||||||
|
* in the application context bootstrap. If you need any dependencies on other beans
|
||||||
|
* there, make sure to declare them 'lazy' as far as possible in order to let them
|
||||||
|
* go through other post-processors as well.</b>
|
||||||
|
*
|
||||||
* <pre class="code">
|
* <pre class="code">
|
||||||
* @Configuration
|
* @Configuration
|
||||||
* @EnableAsync
|
* @EnableAsync
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2002-2017 the original author or authors.
|
* Copyright 2002-2018 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -37,6 +37,16 @@ import org.springframework.lang.Nullable;
|
|||||||
* "queueCapacity" properties) and exposing it as a bean reference of its native
|
* "queueCapacity" properties) and exposing it as a bean reference of its native
|
||||||
* {@link java.util.concurrent.ExecutorService} type.
|
* {@link java.util.concurrent.ExecutorService} type.
|
||||||
*
|
*
|
||||||
|
* <p>The default configuration is a core pool size of 1, with unlimited max pool size
|
||||||
|
* and unlimited queue capacity. This is roughly equivalent to
|
||||||
|
* {@link java.util.concurrent.Executors#newSingleThreadExecutor()}, sharing a single
|
||||||
|
* thread for all tasks. Setting {@link #setQueueCapacity "queueCapacity"} to 0 mimics
|
||||||
|
* {@link java.util.concurrent.Executors#newCachedThreadPool()}, with immediate scaling
|
||||||
|
* of threads in the pool to a potentially very high number. Consider also setting a
|
||||||
|
* {@link #setMaxPoolSize "maxPoolSize"} at that point, as well as possibly a higher
|
||||||
|
* {@link #setCorePoolSize "corePoolSize"} (see also the
|
||||||
|
* {@link #setAllowCoreThreadTimeOut "allowCoreThreadTimeOut"} mode of scaling).
|
||||||
|
*
|
||||||
* <p>For an alternative, you may set up a {@link ThreadPoolExecutor} instance directly
|
* <p>For an alternative, you may set up a {@link ThreadPoolExecutor} instance directly
|
||||||
* using constructor injection, or use a factory method definition that points to the
|
* using constructor injection, or use a factory method definition that points to the
|
||||||
* {@link java.util.concurrent.Executors} class.
|
* {@link java.util.concurrent.Executors} class.
|
||||||
|
|||||||
@@ -48,11 +48,15 @@ import org.springframework.util.concurrent.ListenableFutureTask;
|
|||||||
* providing several useful attributes: "corePoolSize", "maxPoolSize", "keepAliveSeconds"
|
* providing several useful attributes: "corePoolSize", "maxPoolSize", "keepAliveSeconds"
|
||||||
* (all supporting updates at runtime); "poolSize", "activeCount" (for introspection only).
|
* (all supporting updates at runtime); "poolSize", "activeCount" (for introspection only).
|
||||||
*
|
*
|
||||||
* <p>For an alternative, you may set up a ThreadPoolExecutor instance directly using
|
* <p>The default configuration is a core pool size of 1, with unlimited max pool size
|
||||||
* constructor injection, or use a factory method definition that points to the
|
* and unlimited queue capacity. This is roughly equivalent to
|
||||||
* {@link java.util.concurrent.Executors} class. To expose such a raw Executor as a
|
* {@link java.util.concurrent.Executors#newSingleThreadExecutor()}, sharing a single
|
||||||
* Spring {@link org.springframework.core.task.TaskExecutor}, simply wrap it with a
|
* thread for all tasks. Setting {@link #setQueueCapacity "queueCapacity"} to 0 mimics
|
||||||
* {@link org.springframework.scheduling.concurrent.ConcurrentTaskExecutor} adapter.
|
* {@link java.util.concurrent.Executors#newCachedThreadPool()}, with immediate scaling
|
||||||
|
* of threads in the pool to a potentially very high number. Consider also setting a
|
||||||
|
* {@link #setMaxPoolSize "maxPoolSize"} at that point, as well as possibly a higher
|
||||||
|
* {@link #setCorePoolSize "corePoolSize"} (see also the
|
||||||
|
* {@link #setAllowCoreThreadTimeOut "allowCoreThreadTimeOut"} mode of scaling).
|
||||||
*
|
*
|
||||||
* <p><b>NOTE:</b> This class implements Spring's
|
* <p><b>NOTE:</b> This class implements Spring's
|
||||||
* {@link org.springframework.core.task.TaskExecutor} interface as well as the
|
* {@link org.springframework.core.task.TaskExecutor} interface as well as the
|
||||||
@@ -61,13 +65,17 @@ import org.springframework.util.concurrent.ListenableFutureTask;
|
|||||||
* exception handling follows the TaskExecutor contract rather than the Executor contract,
|
* exception handling follows the TaskExecutor contract rather than the Executor contract,
|
||||||
* in particular regarding the {@link org.springframework.core.task.TaskRejectedException}.
|
* in particular regarding the {@link org.springframework.core.task.TaskRejectedException}.
|
||||||
*
|
*
|
||||||
* <p><b>If you prefer native {@link java.util.concurrent.ExecutorService} exposure instead,
|
* <p>For an alternative, you may set up a ThreadPoolExecutor instance directly using
|
||||||
* consider {@link ThreadPoolExecutorFactoryBean} as an alternative to this class.</b>
|
* constructor injection, or use a factory method definition that points to the
|
||||||
|
* {@link java.util.concurrent.Executors} class. To expose such a raw Executor as a
|
||||||
|
* Spring {@link org.springframework.core.task.TaskExecutor}, simply wrap it with a
|
||||||
|
* {@link org.springframework.scheduling.concurrent.ConcurrentTaskExecutor} adapter.
|
||||||
*
|
*
|
||||||
* @author Juergen Hoeller
|
* @author Juergen Hoeller
|
||||||
* @since 2.0
|
* @since 2.0
|
||||||
* @see org.springframework.core.task.TaskExecutor
|
* @see org.springframework.core.task.TaskExecutor
|
||||||
* @see java.util.concurrent.ThreadPoolExecutor
|
* @see java.util.concurrent.ThreadPoolExecutor
|
||||||
|
* @see ThreadPoolExecutorFactoryBean
|
||||||
* @see ConcurrentTaskExecutor
|
* @see ConcurrentTaskExecutor
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("serial")
|
@SuppressWarnings("serial")
|
||||||
|
|||||||
@@ -5930,49 +5930,37 @@ behavior, it is possible to use this abstraction for your own needs.
|
|||||||
==== TaskExecutor types
|
==== TaskExecutor types
|
||||||
|
|
||||||
There are a number of pre-built implementations of `TaskExecutor` included with the
|
There are a number of pre-built implementations of `TaskExecutor` included with the
|
||||||
Spring distribution. In all likelihood, you shouldn't ever need to implement your own.
|
Spring distribution. In all likelihood, you should never need to implement your own.
|
||||||
|
The common out-of-the-box variants are:
|
||||||
|
|
||||||
|
* `SyncTaskExecutor`
|
||||||
|
This implementation does not execute invocations asynchronously. Instead, each
|
||||||
|
invocation takes place in the calling thread. It is primarily used in situations
|
||||||
|
where multi-threading is not necessary such as in simple test cases.
|
||||||
* `SimpleAsyncTaskExecutor`
|
* `SimpleAsyncTaskExecutor`
|
||||||
This implementation does not reuse any threads, rather it starts up a new thread
|
This implementation does not reuse any threads, rather it starts up a new thread
|
||||||
for each invocation. However, it does support a concurrency limit which will block
|
for each invocation. However, it does support a concurrency limit which will block
|
||||||
any invocations that are over the limit until a slot has been freed up. If you
|
any invocations that are over the limit until a slot has been freed up. If you
|
||||||
are looking for true pooling, see the discussions of `SimpleThreadPoolTaskExecutor`
|
are looking for true pooling, see `ThreadPoolTaskExecutor` below.
|
||||||
and `ThreadPoolTaskExecutor` below.
|
|
||||||
* `SyncTaskExecutor`
|
|
||||||
This implementation doesn't execute invocations asynchronously. Instead, each
|
|
||||||
invocation takes place in the calling thread. It is primarily used in situations
|
|
||||||
where multi-threading isn't necessary such as simple test cases.
|
|
||||||
* `ConcurrentTaskExecutor`
|
* `ConcurrentTaskExecutor`
|
||||||
This implementation is an adapter for a `java.util.concurrent.Executor` object.
|
This implementation is an adapter for a `java.util.concurrent.Executor` instance.
|
||||||
There is an alternative, `ThreadPoolTaskExecutor`, that exposes the `Executor`
|
There is an alternative, `ThreadPoolTaskExecutor`, that exposes the `Executor`
|
||||||
configuration parameters as bean properties. It is rare to need to use the
|
configuration parameters as bean properties. There is rarely a need to use
|
||||||
`ConcurrentTaskExecutor`, but if the `ThreadPoolTaskExecutor` isn't flexible
|
`ConcurrentTaskExecutor` directly, but if the `ThreadPoolTaskExecutor` is not
|
||||||
enough for your needs, the `ConcurrentTaskExecutor` is an alternative.
|
flexible enough for your needs, then `ConcurrentTaskExecutor` is an alternative.
|
||||||
* `SimpleThreadPoolTaskExecutor`
|
|
||||||
This implementation is actually a subclass of Quartz's `SimpleThreadPool` which
|
|
||||||
listens to Spring's lifecycle callbacks. This is typically used when you have a
|
|
||||||
thread pool that may need to be shared by both Quartz and non-Quartz components.
|
|
||||||
* `ThreadPoolTaskExecutor`
|
* `ThreadPoolTaskExecutor`
|
||||||
This implementation is the most commonly used one. It exposes bean properties for
|
This implementation is the most commonly used one. It exposes bean properties for
|
||||||
configuring a `java.util.concurrent.ThreadPoolExecutor` and wraps it in a `TaskExecutor`.
|
configuring a `java.util.concurrent.ThreadPoolExecutor` and wraps it in a `TaskExecutor`.
|
||||||
If you need to adapt to a different kind of `java.util.concurrent.Executor`, it is
|
If you need to adapt to a different kind of `java.util.concurrent.Executor`, it is
|
||||||
recommended that you use a `ConcurrentTaskExecutor` instead.
|
recommended that you use a `ConcurrentTaskExecutor` instead.
|
||||||
* `WorkManagerTaskExecutor`
|
* `WorkManagerTaskExecutor`
|
||||||
|
This implementation uses a CommonJ `WorkManager` as its backing service provider
|
||||||
+
|
and is the central convenience class for setting up CommonJ-based thread pool
|
||||||
|
integration on WebLogic/WebSphere within a Spring application context.
|
||||||
****
|
* `DefaultManagedTaskExecutor`
|
||||||
CommonJ is a set of specifications jointly developed between BEA and IBM. These
|
This implementation uses a JNDI-obtained `ManagedExecutorService` in a JSR-236
|
||||||
specifications are not Java EE standards, but are standard across BEA's and IBM's
|
compatible runtime environment such as a Java EE 7+ application server,
|
||||||
Application Server implementations.
|
replacing a CommonJ WorkManager for that purpose.
|
||||||
****
|
|
||||||
|
|
||||||
+
|
|
||||||
|
|
||||||
This implementation uses the CommonJ `WorkManager` as its backing implementation and is
|
|
||||||
the central convenience class for setting up a CommonJ `WorkManager` reference in a Spring
|
|
||||||
context. Similar to the `SimpleThreadPoolTaskExecutor`, this class implements the
|
|
||||||
`WorkManager` interface and therefore can be used directly as a `WorkManager` as well.
|
|
||||||
|
|
||||||
|
|
||||||
[[scheduling-task-executor-usage]]
|
[[scheduling-task-executor-usage]]
|
||||||
@@ -6000,7 +5988,6 @@ out a set of messages.
|
|||||||
public void run() {
|
public void run() {
|
||||||
System.out.println(message);
|
System.out.println(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private TaskExecutor taskExecutor;
|
private TaskExecutor taskExecutor;
|
||||||
@@ -6014,7 +6001,6 @@ out a set of messages.
|
|||||||
taskExecutor.execute(new MessagePrinterTask("Message" + i));
|
taskExecutor.execute(new MessagePrinterTask("Message" + i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
@@ -6054,16 +6040,25 @@ with a variety of methods for scheduling tasks to run at some point in the futur
|
|||||||
|
|
||||||
ScheduledFuture schedule(Runnable task, Trigger trigger);
|
ScheduledFuture schedule(Runnable task, Trigger trigger);
|
||||||
|
|
||||||
|
ScheduledFuture schedule(Runnable task, Instant startTime);
|
||||||
|
|
||||||
ScheduledFuture schedule(Runnable task, Date startTime);
|
ScheduledFuture schedule(Runnable task, Date startTime);
|
||||||
|
|
||||||
|
ScheduledFuture scheduleAtFixedRate(Runnable task, Instant startTime, Duration period);
|
||||||
|
|
||||||
ScheduledFuture scheduleAtFixedRate(Runnable task, Date startTime, long period);
|
ScheduledFuture scheduleAtFixedRate(Runnable task, Date startTime, long period);
|
||||||
|
|
||||||
|
ScheduledFuture scheduleAtFixedRate(Runnable task, Duration period);
|
||||||
|
|
||||||
ScheduledFuture scheduleAtFixedRate(Runnable task, long period);
|
ScheduledFuture scheduleAtFixedRate(Runnable task, long period);
|
||||||
|
|
||||||
|
ScheduledFuture scheduleWithFixedDelay(Runnable task, Instant startTime, Duration delay);
|
||||||
|
|
||||||
ScheduledFuture scheduleWithFixedDelay(Runnable task, Date startTime, long delay);
|
ScheduledFuture scheduleWithFixedDelay(Runnable task, Date startTime, long delay);
|
||||||
|
|
||||||
ScheduledFuture scheduleWithFixedDelay(Runnable task, long delay);
|
ScheduledFuture scheduleWithFixedDelay(Runnable task, Duration delay);
|
||||||
|
|
||||||
|
ScheduledFuture scheduleWithFixedDelay(Runnable task, long delay);
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
@@ -6077,8 +6072,8 @@ much more flexible.
|
|||||||
[[scheduling-trigger-interface]]
|
[[scheduling-trigger-interface]]
|
||||||
==== Trigger interface
|
==== Trigger interface
|
||||||
|
|
||||||
The `Trigger` interface is essentially inspired by JSR-236, which, as of Spring 3.0, has
|
The `Trigger` interface is essentially inspired by JSR-236 which, as of Spring 3.0,
|
||||||
not yet been officially implemented. The basic idea of the `Trigger` is that execution
|
was not yet officially implemented. The basic idea of the `Trigger` is that execution
|
||||||
times may be determined based on past execution outcomes or even arbitrary conditions.
|
times may be determined based on past execution outcomes or even arbitrary conditions.
|
||||||
If these determinations do take into account the outcome of the preceding execution,
|
If these determinations do take into account the outcome of the preceding execution,
|
||||||
that information is available within a `TriggerContext`. The `Trigger` interface itself
|
that information is available within a `TriggerContext`. The `Trigger` interface itself
|
||||||
@@ -6090,7 +6085,6 @@ is quite simple:
|
|||||||
public interface Trigger {
|
public interface Trigger {
|
||||||
|
|
||||||
Date nextExecutionTime(TriggerContext triggerContext);
|
Date nextExecutionTime(TriggerContext triggerContext);
|
||||||
|
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
@@ -6109,7 +6103,6 @@ default). Here you can see what methods are available for `Trigger` implementati
|
|||||||
Date lastActualExecutionTime();
|
Date lastActualExecutionTime();
|
||||||
|
|
||||||
Date lastCompletionTime();
|
Date lastCompletionTime();
|
||||||
|
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
@@ -6144,19 +6137,21 @@ could be configured externally and therefore easily modified or extended.
|
|||||||
==== TaskScheduler implementations
|
==== TaskScheduler implementations
|
||||||
|
|
||||||
As with Spring's `TaskExecutor` abstraction, the primary benefit of the `TaskScheduler`
|
As with Spring's `TaskExecutor` abstraction, the primary benefit of the `TaskScheduler`
|
||||||
is that code relying on scheduling behavior need not be coupled to a particular
|
arrangement is that an application's scheduling needs are decoupled from the deployment
|
||||||
scheduler implementation. The flexibility this provides is particularly relevant when
|
environment. This abstraction level is particularly relevant when deploying to an
|
||||||
running within Application Server environments where threads should not be created
|
application server environment where threads should not be created directly by the
|
||||||
directly by the application itself. For such cases, Spring provides a
|
application itself. For such scenarios, Spring provides a `TimerManagerTaskScheduler`
|
||||||
`TimerManagerTaskScheduler` that delegates to a CommonJ TimerManager instance, typically
|
delegating to a CommonJ TimerManager on WebLogic/WebSphere as well as a more recent
|
||||||
configured with a JNDI-lookup.
|
`DefaultManagedTaskScheduler` delegating to a JSR-236 `ManagedScheduledExecutorService`
|
||||||
|
in a Java EE 7+ environment, both typically configured with a JNDI lookup.
|
||||||
|
|
||||||
A simpler alternative, the `ThreadPoolTaskScheduler`, can be used whenever external
|
Whenever external thread management is not a requirement, a simpler alternative is
|
||||||
thread management is not a requirement. Internally, it delegates to a
|
a local `ScheduledExecutorService` setup within the application which can be adapted
|
||||||
`ScheduledExecutorService` instance. `ThreadPoolTaskScheduler` actually implements
|
through Spring's `ConcurrentTaskScheduler`. As a convenience, Spring also provides a
|
||||||
Spring's `TaskExecutor` interface as well, so that a single instance can be used for
|
`ThreadPoolTaskScheduler` which internally delegates to a `ScheduledExecutorService`,
|
||||||
asynchronous execution __as soon as possible__ as well as scheduled, and potentially
|
providing common bean-style configuration along the lines of `ThreadPoolTaskExecutor`.
|
||||||
recurring, executions.
|
These variants work perfectly fine for locally embedded thread pool setups in lenient
|
||||||
|
application server environments as well, in particular on Tomcat and Jetty.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -7378,7 +7373,6 @@ Alternatively for XML configuration use the `cache:annotation-driven` element:
|
|||||||
http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd">
|
http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd">
|
||||||
|
|
||||||
<cache:annotation-driven/>
|
<cache:annotation-driven/>
|
||||||
|
|
||||||
</beans>
|
</beans>
|
||||||
----
|
----
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user