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:
parent
71aee9211f
commit
d58c09b89f
|
|
@ -76,6 +76,11 @@ import org.springframework.core.Ordered;
|
|||
* method.</li>
|
||||
* </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">
|
||||
* @Configuration
|
||||
* @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");
|
||||
* 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
|
||||
* {@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
|
||||
* using constructor injection, or use a factory method definition that points to the
|
||||
* {@link java.util.concurrent.Executors} class.
|
||||
|
|
|
|||
|
|
@ -48,11 +48,15 @@ import org.springframework.util.concurrent.ListenableFutureTask;
|
|||
* providing several useful attributes: "corePoolSize", "maxPoolSize", "keepAliveSeconds"
|
||||
* (all supporting updates at runtime); "poolSize", "activeCount" (for introspection only).
|
||||
*
|
||||
* <p>For an alternative, you may set up a ThreadPoolExecutor instance directly using
|
||||
* 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.
|
||||
* <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><b>NOTE:</b> This class implements Spring's
|
||||
* {@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,
|
||||
* in particular regarding the {@link org.springframework.core.task.TaskRejectedException}.
|
||||
*
|
||||
* <p><b>If you prefer native {@link java.util.concurrent.ExecutorService} exposure instead,
|
||||
* consider {@link ThreadPoolExecutorFactoryBean} as an alternative to this class.</b>
|
||||
* <p>For an alternative, you may set up a ThreadPoolExecutor instance directly using
|
||||
* 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
|
||||
* @since 2.0
|
||||
* @see org.springframework.core.task.TaskExecutor
|
||||
* @see java.util.concurrent.ThreadPoolExecutor
|
||||
* @see ThreadPoolExecutorFactoryBean
|
||||
* @see ConcurrentTaskExecutor
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
|
|
|
|||
|
|
@ -463,7 +463,7 @@ shown in this example:
|
|||
<entry key="/remoting/AccountService" value-ref="accountExporter"/>
|
||||
</util:map>
|
||||
</property>
|
||||
<property name="port" value="8080" />
|
||||
<property name="port" value="8080"/>
|
||||
</bean>
|
||||
----
|
||||
|
||||
|
|
@ -2061,13 +2061,13 @@ containers that ships with Spring (in this case the `DefaultMessageListenerConta
|
|||
[subs="verbatim,quotes"]
|
||||
----
|
||||
<!-- this is the Message Driven POJO (MDP) -->
|
||||
<bean id="messageListener" class="jmsexample.ExampleListener" />
|
||||
<bean id="messageListener" class="jmsexample.ExampleListener"/>
|
||||
|
||||
<!-- and this is the message listener container -->
|
||||
<bean id="jmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
|
||||
<property name="connectionFactory" ref="connectionFactory"/>
|
||||
<property name="destination" ref="destination"/>
|
||||
**<property name="messageListener" ref="messageListener" />**
|
||||
**<property name="messageListener" ref="messageListener"/>**
|
||||
</bean>
|
||||
----
|
||||
|
||||
|
|
@ -2163,7 +2163,7 @@ POJO that we will make into an MDP via the following configuration.
|
|||
<bean id="jmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
|
||||
<property name="connectionFactory" ref="connectionFactory"/>
|
||||
<property name="destination" ref="destination"/>
|
||||
**<property name="messageListener" ref="messageListener" />**
|
||||
**<property name="messageListener" ref="messageListener"/>**
|
||||
</bean>
|
||||
----
|
||||
|
||||
|
|
@ -5930,49 +5930,37 @@ behavior, it is possible to use this abstraction for your own needs.
|
|||
==== TaskExecutor types
|
||||
|
||||
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`
|
||||
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
|
||||
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`
|
||||
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.
|
||||
are looking for true pooling, see `ThreadPoolTaskExecutor` below.
|
||||
* `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`
|
||||
configuration parameters as bean properties. It is rare to need to use the
|
||||
`ConcurrentTaskExecutor`, but if the `ThreadPoolTaskExecutor` isn't flexible
|
||||
enough for your needs, the `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.
|
||||
configuration parameters as bean properties. There is rarely a need to use
|
||||
`ConcurrentTaskExecutor` directly, but if the `ThreadPoolTaskExecutor` is not
|
||||
flexible enough for your needs, then `ConcurrentTaskExecutor` is an alternative.
|
||||
* `ThreadPoolTaskExecutor`
|
||||
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`.
|
||||
If you need to adapt to a different kind of `java.util.concurrent.Executor`, it is
|
||||
recommended that you use a `ConcurrentTaskExecutor` instead.
|
||||
* `WorkManagerTaskExecutor`
|
||||
|
||||
+
|
||||
|
||||
****
|
||||
CommonJ is a set of specifications jointly developed between BEA and IBM. These
|
||||
specifications are not Java EE standards, but are standard across BEA's and IBM's
|
||||
Application Server implementations.
|
||||
****
|
||||
|
||||
+
|
||||
|
||||
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.
|
||||
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`
|
||||
This implementation uses a JNDI-obtained `ManagedExecutorService` in a JSR-236
|
||||
compatible runtime environment such as a Java EE 7+ application server,
|
||||
replacing a CommonJ WorkManager for that purpose.
|
||||
|
||||
|
||||
[[scheduling-task-executor-usage]]
|
||||
|
|
@ -6000,7 +5988,6 @@ out a set of messages.
|
|||
public void run() {
|
||||
System.out.println(message);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private TaskExecutor taskExecutor;
|
||||
|
|
@ -6014,7 +6001,6 @@ out a set of messages.
|
|||
taskExecutor.execute(new MessagePrinterTask("Message" + i));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
----
|
||||
|
||||
|
|
@ -6029,13 +6015,13 @@ been exposed.
|
|||
[subs="verbatim,quotes"]
|
||||
----
|
||||
<bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
|
||||
<property name="corePoolSize" value="5" />
|
||||
<property name="maxPoolSize" value="10" />
|
||||
<property name="queueCapacity" value="25" />
|
||||
<property name="corePoolSize" value="5"/>
|
||||
<property name="maxPoolSize" value="10"/>
|
||||
<property name="queueCapacity" value="25"/>
|
||||
</bean>
|
||||
|
||||
<bean id="taskExecutorExample" class="TaskExecutorExample">
|
||||
<constructor-arg ref="taskExecutor" />
|
||||
<constructor-arg ref="taskExecutor"/>
|
||||
</bean>
|
||||
----
|
||||
|
||||
|
|
@ -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, Instant 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, Duration 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, long delay);
|
||||
ScheduledFuture scheduleWithFixedDelay(Runnable task, Duration delay);
|
||||
|
||||
ScheduledFuture scheduleWithFixedDelay(Runnable task, long delay);
|
||||
}
|
||||
----
|
||||
|
||||
|
|
@ -6077,8 +6072,8 @@ much more flexible.
|
|||
[[scheduling-trigger-interface]]
|
||||
==== Trigger interface
|
||||
|
||||
The `Trigger` interface is essentially inspired by JSR-236, which, as of Spring 3.0, has
|
||||
not yet been officially implemented. The basic idea of the `Trigger` is that execution
|
||||
The `Trigger` interface is essentially inspired by JSR-236 which, as of Spring 3.0,
|
||||
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.
|
||||
If these determinations do take into account the outcome of the preceding execution,
|
||||
that information is available within a `TriggerContext`. The `Trigger` interface itself
|
||||
|
|
@ -6090,7 +6085,6 @@ is quite simple:
|
|||
public interface Trigger {
|
||||
|
||||
Date nextExecutionTime(TriggerContext triggerContext);
|
||||
|
||||
}
|
||||
----
|
||||
|
||||
|
|
@ -6109,7 +6103,6 @@ default). Here you can see what methods are available for `Trigger` implementati
|
|||
Date lastActualExecutionTime();
|
||||
|
||||
Date lastCompletionTime();
|
||||
|
||||
}
|
||||
----
|
||||
|
||||
|
|
@ -6144,19 +6137,21 @@ could be configured externally and therefore easily modified or extended.
|
|||
==== TaskScheduler implementations
|
||||
|
||||
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
|
||||
scheduler implementation. The flexibility this provides is particularly relevant when
|
||||
running within Application Server environments where threads should not be created
|
||||
directly by the application itself. For such cases, Spring provides a
|
||||
`TimerManagerTaskScheduler` that delegates to a CommonJ TimerManager instance, typically
|
||||
configured with a JNDI-lookup.
|
||||
arrangement is that an application's scheduling needs are decoupled from the deployment
|
||||
environment. This abstraction level is particularly relevant when deploying to an
|
||||
application server environment where threads should not be created directly by the
|
||||
application itself. For such scenarios, Spring provides a `TimerManagerTaskScheduler`
|
||||
delegating to a CommonJ TimerManager on WebLogic/WebSphere as well as a more recent
|
||||
`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
|
||||
thread management is not a requirement. Internally, it delegates to a
|
||||
`ScheduledExecutorService` instance. `ThreadPoolTaskScheduler` actually implements
|
||||
Spring's `TaskExecutor` interface as well, so that a single instance can be used for
|
||||
asynchronous execution __as soon as possible__ as well as scheduled, and potentially
|
||||
recurring, executions.
|
||||
Whenever external thread management is not a requirement, a simpler alternative is
|
||||
a local `ScheduledExecutorService` setup within the application which can be adapted
|
||||
through Spring's `ConcurrentTaskScheduler`. As a convenience, Spring also provides a
|
||||
`ThreadPoolTaskScheduler` which internally delegates to a `ScheduledExecutorService`,
|
||||
providing common bean-style configuration along the lines of `ThreadPoolTaskExecutor`.
|
||||
These variants work perfectly fine for locally embedded thread pool setups in lenient
|
||||
application server environments as well, in particular on Tomcat and Jetty.
|
||||
|
||||
|
||||
|
||||
|
|
@ -7377,8 +7372,7 @@ Alternatively for XML configuration use the `cache:annotation-driven` element:
|
|||
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd">
|
||||
|
||||
<cache:annotation-driven />
|
||||
|
||||
<cache:annotation-driven/>
|
||||
</beans>
|
||||
----
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue