2

我正在尝试使用@Async注释实现异步调用。显然,由于它是一个遗留项目,Spring 版本是 3.0.6,因此它不支持更新的接口(AsyncConfigurer)和更高版本的 Spring 引入的侦听器。

目前,@Async调用在发送电子邮件所需的方法上工作得很好。调用代码调用该方法并返回以恢复正常控制。然后将@Async调用作为单独的线程调用。这一切都非常好,达到了目的。

@Async调用是在一个用于在应用程序中发送电子邮件的方法上。但是,有时可能会触发 1000 封电子邮件。我认为这会引发 1000 个左右的线程。这不会导致有这么多活动线程的应用程序出现问题吗?这些线程会自行终止吗?JVM 在内存使用和堆空间方面会发生什么?

此外,我试图通过将该方法标记为@Async从另一个方法调用此方法,但看起来线程没有创建,并且控件实际上在那里等待以完成该方法中的所有操作。为什么它有不同的行为?不知道为什么会这样。

提前致谢!

4

3 回答 3

1

它产生多少线程以及事物如何排队取决于您如何定义 taskExecutor bean。

这里的文档:http: //docs.spring.io/spring/docs/3.1.x/spring-framework-reference/htmlsingle/spring-framework-reference.html#scheduling

于 2016-10-26T14:38:58.273 回答
1

@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 Container 管理。

JVM 在内存使用和堆空间方面会发生什么?

显然,创建的代理数量越多,消耗的堆内存就越多。

为什么它有不同的行为?

我假设您在同一个类中创建了 2 个异步方法并在另一个类中调用了一个。因此,当您从类内部调用方法时,它是 Spring AOP 的一个限制,即代理永远不会发挥作用,而是作为常规方法触发。

于 2016-10-26T15:00:59.460 回答
1

您的 Emailtasks 将首先存储在(默认情况下无限制)队列中。

默认情况下,队列是无界的,但这很少是所需的配置,因为如果在所有池线程都忙时向该队列添加了足够多的任务,它可能会导致 OutOfMemoryErrors。

如果您只使用 Annotation,则 spring 将创建一个默认执行程序。此执行器使用默认设置,您可以通过在配置文件或配置类中配置执行器属性来更改它:

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

然后在您的代码中:

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

阅读更多以及如何配置执行器:docs.spring.io

于 2016-10-26T14:40:33.697 回答