一种@Async方法中使用的线程池与其他异步方法执行共享

时间:2018-06-22 08:43:49

标签: java spring multithreading spring-boot spring-async

我有一个初始化为@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之上,如下所示:

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线程池执行

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

2 个答案:

答案 0 :(得分:1)

关于Spring和代理的一件事是,许多带注释的功能都使用代理来提供功能。即@Transactional@Cacheable@Async都依赖于Spring检测这些注释并将这些bean包装在代理bean中。

在这种情况下,仅当在类中的调用该代理方法时,才可以使用该方法。有关该主题,请参见this

引用评论:

  

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

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

答案 1 :(得分:1)

[除了关于Spring如何与代理方法一起使用的说法之外-还有从以下位置调用@Async方法的正确上下文:]

引用Spring官方文档

  

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

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

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

 @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();
     }
 }

P.S:如果您的getExecutor()带有@Bean注释:

  

不再需要手动调用executor.initialize()   方法,因为当Bean是   初始化。