Spring Framework предусматривает абстракции для асинхронного выполнения и планирования задач с помощью интерфейсов TaskExecutor
и TaskScheduler
, соответственно. Spring также имеет реализации этих интерфейсов, которые поддерживают пулы потоков или делегирование полномочий CommonJ в серверном окружении приложений. В конечном итоге, использование этих реализаций за общими интерфейсами абстрагирует различия между окружениями Java SE 5, Java SE 6 и Java EE.
Spring также имеет классы интеграции для поддержки планирования с помощью Timer
(входит в состав JDK с версии 1.3) и Quartz Scheduler (https://www.quartz-scheduler.org/). Можно установить оба этих планировщика, используя FactoryBean
с дополнительными ссылками на экземпляры Timer
или Trigger
, соответственно. Кроме того, для планировщика Quartz и Timer
доступен вспомогательный класс, позволяющий вызывать метод существующего целевого объекта (аналогично обычной операции MethodInvokingFactoryBean
).
Абстракция TaskExecutor
в Spring
Исполнители (executors) – это JDK-наименование понятия пулов потоков. Именование "исполнитель" связано с тем, что отсутствует гарантия, что базовая реализация на самом деле является пулом. Исполнитель может быть однопоточным или даже синхронным. Абстракция Spring скрывает детали реализации между окружениями Java SE и Java EE.
Интерфейс TaskExecutor
в Spring идентичен интерфейсу java.util.concurrent.Executor
. На самом деле, изначально основной причиной его существования было абстрагирование от необходимости использования Java 5 при использовании пулов потоков. Интерфейс имеет единственный метод (execute(Runnable task)
), который принимает задачу к выполнению, основываясь на семантике и конфигурации пула потоков.
TaskExecutor
был первоначально создан для того, чтобы предоставить другим компонентам Spring абстракцию для объединения потоков, когда это необходимо. Такие компоненты, как ApplicationEventMulticaster
, AbstractMessageListenerContainer
из JMS и интеграция Quartz, используют абстракцию TaskExecutor
для объединения потоков. Однако если для бинов требуется применение логики работы пула потоков, можно использовать эту абстракцию для собственных нужд.
Типы TaskExecutor
Spring содержит ряд готовых реализаций TaskExecutor
. Скорее всего, внедрять собственные вам никогда не придется. Варианты, которые предусматривает Spring, следующие:
-
SyncTaskExecutor
: Эта реализация не выполняет вызовы асинхронно. Вместо этого каждый вызов происходит в вызывающем потоке. Эта реализация используется в основном в ситуациях, когда многопоточность не требуется, например, в простых тестовых сценариях. -
SimpleAsyncTaskExecutor
: Эта реализация не использует повторно ни один поток. Скорее, она запускает новый поток для каждого вызова. Тем не менее эта реализация поддерживает механизм ограничения параллелизма, который блокирует все вызовы, превышающие лимит, пока не освободится слот. Если требуется настоящее объединение в пул, см.ThreadPoolTaskExecutor
далее в этом списке. -
ConcurrentTaskExecutor
: Эта реализация является адаптером для экземпляраjava.util.concurrent.Executor
. Существует альтернатива (ThreadPoolTaskExecutor
), которая открывает параметры конфигурацииExecutor
как свойства бина. Нeобходимость использоватьConcurrentTaskExecutor
напрямую возникает крайне редко. Однако, еслиThreadPoolTaskExecutor
недостаточно гибок для ваших нужд, альтернативным вариантом будетConcurrentTaskExecutor
. -
ThreadPoolTaskExecutor
: Эта реализация используется наиболее часто. Она открывает свойства бина для конфигурированияjava.util.concurrent.ThreadPoolExecutor
и оборачивает его вTaskExecutor
. Если необходима адаптация к другому типуjava.util.concurrent.Executor
, мы рекомендуем использовать вместо неё реализациюConcurrentTaskExecutor
. -
WorkManagerTaskExecutor
: Эта реализация используетWorkManager
из CommonJ в качестве базового поставщика служб и является центральным вспомогательным классом для настройки интеграции пула потоков на основе CommonJ в WebLogic или WebSphere в контексте приложения Spring. -
DefaultManagedTaskExecutor
: Эта реализация использует полученный через JNDI экземплярManagedExecutorService
в JSR-236-совместимом окружении выполнения (таком как сервер приложений на Java EE 7+), заменяя для этой цели WorkManager из CommonJ.
Использование TaskExecutor
Реализации TaskExecutor
из Spring используются как простые классы JavaBeans. В следующем примере определяется бин, который использует ThreadPoolTaskExecutor
для асинхронного вывода набора сообщений:
import org.springframework.core.task.TaskExecutor;
public class TaskExecutorExample {
private class MessagePrinterTask implements Runnable {
private String message;
public MessagePrinterTask(String message) {
this.message = message;
}
public void run() {
System.out.println(message);
}
}
private TaskExecutor taskExecutor;
public TaskExecutorExample(TaskExecutor taskExecutor) {
this.taskExecutor = taskExecutor;
}
public void printMessages() {
for(int i = 0; i < 25; i++) {
taskExecutor.execute(new MessagePrinterTask("Message" + i));
}
}
}
Как можно заметить, вместо того, чтобы извлекать поток из пула и выполнять его самостоятельно, вы добавляете свой Runnable
в очередь. Затем TaskExecutor
использует свои внутренние правила, чтобы решить, когда выполнять задачу.
Для конфигурирования правил, которые использует TaskExecutor
, мы открываем простые свойства бина:
<bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<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"/>
</bean>
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ