@Async с Spring 3.0.6

Я пытаюсь реализовать асинхронный вызов с использованием аннотации @Async. Очевидно, что поскольку это унаследованный проект, версия Spring является 3.0.6, поэтому он не поддерживает более новые интерфейсы (AsyncConfigurer) и прослушиватели, представленные в более поздних версиях Spring.

На данный момент вызов @Async прекрасно работает с методом, который необходим для отправки электронных писем. Код вызова вызывает метод и возвращается для возобновления нормального управления. Затем вызов @Async вызывается как отдельный поток. Все это очень хорошо и служит цели.

Вызов @Async относится к методу, который предназначен для отправки электронных писем в приложении. Тем не менее, иногда могут быть запущены тысячи электронных писем. Я предполагаю, что это поднимет 1000 или около того потоков. Не приведет ли это к проблеме в приложении с таким количеством активных потоков? Эти темы заканчиваются самостоятельно? Что происходит в JVM с точки зрения использования памяти и пространства кучи?

Кроме того, я пытался вызвать этот метод из другого метода, пометив этот метод как @Async, но похоже, что поток не создан, и элемент управления фактически ожидает завершения всех операций в этом методе. Почему у него другое поведение? Не уверен, почему это происходит.

Заранее спасибо!

3 ответа

Сколько потоков он порождает и как обстоят дела с очередями в зависимости от того, как вы определяете ваш бин taskExecutor.

Документация здесь: http://docs.spring.io/spring/docs/3.1.x/spring-framework-reference/htmlsingle/spring-framework-reference.html

Ваши почтовые задания будут храниться в очереди (по умолчанию неограниченно).

По умолчанию очередь не ограничена, но это редко является желаемой конфигурацией, поскольку она может привести к ошибкам OutOfMemoryErrors, если в эту очередь добавлено достаточно задач, когда все потоки пула заняты.

Если вы используете только аннотацию, по умолчанию будет создан исполнитель по умолчанию. Этот исполнитель использует настройки по умолчанию, которые можно изменить, настроив свойства исполнителя в файле конфигурации или в классе конфигурации:

<task:executor
        id="emailSenderExecutor"
        pool-size="5-25"
        queue-capacity="100"/>

а затем в вашем коде:

@Async(value = "emailSenderExecutor")
public void sendEmail(Email email) {
    [...]
}

Узнайте больше и как настроить исполнителя: docs.spring.io

@Async: аннотация @Async может быть предоставлена ​​для метода, так что вызов этого метода будет происходить асинхронно. Другими словами, вызывающая сторона вернется сразу после вызова, и фактическое выполнение метода произойдет в задаче, которая была передана Spring TaskExecutor.

Как работает @Async:

Такое поведение асинхронной обработки реализуется с использованием прокси для вашего класса во время выполнения. Когда бин вашего класса внедряется через Spring в какой-то другой класс, Spring действительно внедряет прокси вместо этого. Поэтому соответствующий метод прокси называется.

Не приведет ли это к проблеме в приложении с таким количеством активных потоков?

Да, это может быть очень специфично при определении конфигурации исполнителя задач. например, о том, как настроить исполнителя задач (если вы используете конфигурацию Spring XML).

> <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>

Эти темы заканчиваются самостоятельно?

Эти нити регулируются контейнером Spring.

Что происходит в JVM с точки зрения использования памяти и пространства кучи?

Очевидно, что чем больше будет создано прокси, тем больше памяти будет использовано.

Почему у него другое поведение?

Я предполагаю, что вы создали 2 асинхронных метода в одном классе и вызвали один в другом. Поэтому, когда вы вызываете метод изнутри класса, есть ограничения Spring AOP, что прокси никогда не вступает в игру, а вместо этого он запускается как обычный метод.

Другие вопросы по тегам