@Асинхронно с Spring 3.0.6

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

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

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

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

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


person Aman Mohammed    schedule 26.10.2016    source источник


Ответы (3)


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

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

person PaulNUK    schedule 26.10.2016
comment
Я не использовал с ним исполнителя задач. Я ничего не настраивал в applicationContext.xml или любых файлах spring. - person Aman Mohammed; 26.10.2016
comment
Иногда другие части приложения настраивают его, и аннотации Async просто подхватывают его. Возможно, вам потребуется явно настроить bean-компонент ThreadPoolTaskExecutor, а затем, предполагая, что вы используете XML в Spring 3, а не программную настройку, привяжите поддержку Asynch к этому исполнителю следующим образом: <task:annotation-driven executor="myExecutor" /> - person PaulNUK; 26.10.2016

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

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

Такое поведение асинхронной обработки реализуется с помощью прокси для вашего класса во время выполнения. Когда bean-компонент вашего класса внедряется через 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 заключаются в том, что прокси-сервер никогда не вступает в игру, а вместо этого запускается как обычный метод.

person mhasan    schedule 26.10.2016

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

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

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

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

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

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

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

person dieter    schedule 26.10.2016
comment
я не совсем понимаю часть задачи: исполнитель. Я предоставил аннотацию только к методу, который вызывается асинхронно. Все приводит к тому, что создается новый поток, который выполняется сам по себе независимо, позволяя возобновить управление с этого момента. Я не использовал исполнителя задач - person Aman Mohammed; 26.10.2016