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

Java 一个@Async方法中使用的线程池与其他异步方法执行共享,java,spring,multithreading,spring-boot,spring-async,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.setMaxPoolSi

我有一个初始化为@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 pool的类,如:

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发行版
JDK 1.8.0

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

在这种情况下,代理方法只能在类上调用时使用,而不能在类内调用。关于主题,请参见

引用一段评论:


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


尝试从上下文中的另一个类重构并调用这些
@Async
方法,或者由类本身重构并调用这些异步方法。

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

在这种情况下,代理方法只能在类上调用时使用,而不能在类内调用。关于主题,请参见

引用一段评论:


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


尝试从上下文中的另一个类重构并调用这些
@Async
方法,或者由该类本身重构并调用这些异步方法。

[除了关于Spring如何与代理方法一起工作的内容之外,还有调用@Async方法的正确上下文:]

引用Spring官方文档: 默认情况下,Spring将搜索关联的线程池定义:上下文中唯一的TaskExecutor bean,否则将搜索名为“TaskExecutor”的执行器bean。如果两者都不可解析,则将使用SimpleAsyncTaskExecutor来处理异步方法调用

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

方法1:覆盖默认实现(来自官方文档) 方法2:提供自定义和默认实现:
注意:如果您的
getExecutor()
是用
@Bean
注释的:

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


[除了关于Spring如何与代理方法一起工作的内容之外,还有调用@Async方法的正确上下文:]

引用Spring官方文档: 默认情况下,Spring将搜索关联的线程池定义:上下文中唯一的TaskExecutor bean,否则将搜索名为“TaskExecutor”的执行器bean。如果两者都不可解析,则将使用SimpleAsyncTaskExecutor来处理异步方法调用

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

方法1:覆盖默认实现(来自官方文档) 方法2:提供自定义和默认实现:
注意:如果您的
getExecutor()
是用
@Bean
注释的:

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


你确定你看到的就是这些日志吗因为他们说适当的类在正确的池中运行;但是,然后从每个打印错误的声明…是的,我打印了确切的日志。我不知道spring boot是如何为异步调用混合线程池的,不管您可以在@async(“bean name”)注释中定义bean名称,我可以看到它也使用了正确的池,但也会间歇性地混合它们。我并不否认日志也是这样打印的:[myPool][]c.c.a.m.p.e.c.MyHandler-做我的事[pool-1-thread-1][]c.c.a.m.p.e.c.OtherScheduledTask-做那件事你怎么调用这两个呢
 @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();
     }
 }
@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();
     }
 }