1

我有一个初始化为@Bean 的线程池,用于专门执行特定的@Async 方法

class MyConfig {
    @Bean(name="myPool")
    public static TaskExecutor getExecutor(){
        ThreadPooltaskExecutor exec = new ThreadPoolTaskExecutor();
        exec.setCorePoolSize(1);
        exec.setMaxPoolSize(1);
        exec.setThreadNamePrefix("my-thread");
        exec.initialize();
        return exec;
    }
}

上面的线程池作为 bean 用于 Async 方法调用,如下所示:

public class MyHandler {
    ...
    @Async("myPool")
    public void handle(){
        ...
        logger.INFO("do my thing");
        ...
    }
    ...
}

还有其他类也使用默认的 Spring @Async 池,例如:

public class OtherScheduledTask {
    ...
    @Async
    public void doThat() {
        logger.INFO("doing that thing");
    }
    ...
}

在运行应用程序时,我可以在日志中看到以下内容:

[pool-1-thread-1] [] c.c.a.m.p.e.c.OtherScheduledTask - do my thing
[myPool] [] c.c.a.m.p.e.c.MyHandler - doing that thing
....

我看到上面的日志片段随机打印出来,异步方法被默认线程池和自定义线程池间歇性地执行

我确实有从非异步方法调用 @Async 方法的场景

但是,我只在 MyHandler 中使用了一个 @Async 方法 handle() 并且没有其他地方使用我的自定义线程池

为什么 spring 混合线程池(自定义和默认)来执行 @async 方法?

在 @Async 方法注解中传递 bean 名称有什么用?

我如何使用一种特定的异步方法拥有专用的线程池,以便在它不执行时让线程池处于空闲状态并且不用于其他异步方法,这些方法应该只在默认弹簧线程池中执行

关于我的环境的详细信息:Spring boot 版本 1.4.2 RELEASE JDK 1.8.0

4

2 回答 2

3

关于 Spring 和代理的一个关键是,许多带注释的特性使用代理来提供功能。也就是说@Transactional,所有这些都依赖于 Spring 检测这些注释并将这些 bean 包装在代理 bean 中@Cacheable@Async

在这种情况下,代理方法只能在类上调用时使用而不能从类调用。看到这个关于这个话题。

引用评论:

@Dovmo我正在从同一个类中的非异步方法调用一个带有自定义池的异步方法。其他异步方法正在从它们各自的类中调用,并且没有从其他类调用这些方法

尝试重构并@Async从上下文中的另一个类调用这些方法,或者通过将类自动装配到自身中并以这种方式调用异步方法。

于 2018-06-22T13:19:40.380 回答
2

[除了关于 Spring 如何与代理方法一起工作的说法——以及从以下位置调用 @Async 方法的正确上下文:]

引用 Spring 官方文档:

默认情况下,Spring 将搜索关联的线程池定义:要么是上下文中唯一的 TaskExecutor bean,要么是名为“taskExecutor”的 Executor bean。如果两者都无法解析,则将使用 SimpleAsyncTaskExecutor 来处理异步方法调用。

假设您的代码片段中缺少一些注释,代码只会添加另一个可能的执行程序供 Spring 查找和使用。您需要显式覆盖 Spring 的默认SimpleAsyncTaskExecutor实现:

方法一:覆盖默认实现(来自官方文档)

 @Configuration
 @EnableAsync
 public class AppConfig implements AsyncConfigurer {

     @Override
     public Executor getAsyncExecutor() {
         ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
         executor.setCorePoolSize(7);
         executor.setMaxPoolSize(42);
         executor.setQueueCapacity(11);
         executor.setThreadNamePrefix("MyExecutor-");
         executor.initialize();
         return executor;
     }

     @Override
     public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
         return MyAsyncUncaughtExceptionHandler();
     }
 }

方法 2:提供自定义和默认实现:

@Configuration
 @EnableAsync
 public class AppConfig implements AsyncConfigurer {

     // Provide an Executor implementation in lieu of the default Spring implementation
    @Override
    @Bean
    @Primary
    public Executor getAsyncExecutor() {        
        SimpleAsyncTaskExecutor executor = new SimpleAsyncTaskExecutor("pool1-");
        return executor;
    }

     @Bean(name="myCustomExecutor")
     public Executor getAsyncExecutor() {
         ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
         executor.setCorePoolSize(7);
         executor.setMaxPoolSize(42);
         executor.setQueueCapacity(11);
         executor.setThreadNamePrefix("MyExecutor-");
         executor.initialize();
         return executor;
     }

     @Override
     public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
         return MyAsyncUncaughtExceptionHandler();
     }
 }

PS:如果您getExecutor()的注释为@Bean

不再需要手动调用 executor.initialize() 方法,因为这将在 bean 初始化时自动调用。

于 2018-06-22T14:34:03.153 回答