【问题标题】:Spring @Async vs completable future run asyncSpring @Async 与可完成的未来运行异步
【发布时间】:2019-05-20 20:13:57
【问题描述】:

我可能做错了什么。所以,我有 Spring 的@Async

假设我有这段代码

@Async("poolbeanname") 
Function () {
     // some code 
}

我还有一个,假设我有这段代码

@Async("poolbeanname") 
Function () {
     CompletableFuture.runAsync{ new Runnable ()...} 
} 

现在我可以看到第二个代码,产生了一些线程,但第一种方法似乎没有产生多个线程?

【问题讨论】:

  • 那么,你想知道为什么第一种方法创建一个线程,第二种方法创建多个吗?
  • 是的,应该创建不止一个吧? @coder-croc
  • 你能展示真实的代码吗?你启用异步了吗?
  • 是的,它已启用
  • 因为那里runAsync 再次创建线程...基本上,你用它异步运行异步代码几乎没用。

标签: java spring spring-boot asynchronous


【解决方案1】:

正如@M.Deinum 在他的评论中强调的那样,这样做:

@Async("poolbeanname") 
Function () {
  CompletableFuture.runAsync{ new Runnable ()...} 
} 

除非你真的需要它,否则它是无用的,因为:@Async 将你的方法的执行发送到poolbeanname 线程池中,CompletableFuture.runAsync{ new Runnable ()...} 将从你的poolbeanname 中生成新线程。

你可以这样做:

@Async("poolbeanname") 
Function () {
  CompletableFuture.completedFuture( futureResult); 
} 

请注意,由于 spring 的对象代理,如果你这样做:

@Service
class YourService {

   callAsyncFunction(){
      function(); //@Async will not work here 
   }

   @Async("poolbeanname") 
   function () {
      CompletableFuture.completedFuture( futureResult);
    } 
}

但是您可以通过自动注入 bean 来使用此解决方法。

@Service
class YourService {
   @Autowired
   @Lazy
   YourService  self;         

   callAsyncFunction(){
      self.function(); //@Async will work here 
   }

   @Async("poolbeanname") 
   function () {
      CompletableFuture.completedFuture( futureResult);
   } 
}

【讨论】:

  • CompletableFuture.runAsync{ new Runnable ()...} will spawn new thread out of your poolbeanname -> 这是错误的;这将产生于Forkjoin.commonPool
  • Error creating bean with name 'applicationServiceImpl': Bean with name 'applicationServiceImpl' has been injected into other beans [applicationServiceImpl] in its raw version as part of a circular reference -> 您的解决方法无效。
  • 抱歉,我忘记了@Lazy 注释。我编辑了答案
  • @BOTJr。 @Lazy 注释的结果是什么?
  • 但是CompletableFuture.supplyAsync( () -> ...)CompletableFuture.cimpletedFuture()有什么区别呢?
【解决方案2】:
@Async("poolbeanname") 
Function () {
}

如果配置类中有@EnableAsync,上述sn-p 将使用线程池异步执行。

@Configuration
@EnableAsync

@SpringBootApplication
@EnableAsync

当启用异步时,spring会搜索自定义的taskExecutor或者executor bean,如果没有找到则默认为自己的taskExecutor。

检查您的日志中显示Initializing ExecutorService.... 的行 开箱即用,它说它初始化了o.s.s.concurrent.ThreadPoolTaskExecutor,默认情况下,核心池大小为 1。

要覆盖执行器,只需将工厂方法添加到Executor 的配置类。

@Bean
public Executor threadPoolTaskExecutor() {
    ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
    threadPoolTaskExecutor.setCorePoolSize(10);
    threadPoolTaskExecutor.setMaxPoolSize(50);
    //etc...
    return threadPoolTaskExecutor;
}

如果执行程序被覆盖,可能是指定了一个线程池大小或使用了Executors.newSingleThreadExecutor();

CompletableFuture:

代码CompletableFuture.runAsync{ new Runnable ()} 将创建一个CompletableFuture 实例并在每次调用时异步执行代码(创建一个线程)。

CompletableFuture<Void> future
  = CompletableFuture.runAsync(() -> "This is processed asynchronously");

【讨论】:

  • 如果一个方法上面有 Async 注解,总是返回一个 completableFuture 对象?我在一些文章中读到它应该,但 Async 足以启动一个新线程。你能解释一下吗?
【解决方案3】:

要启用@Async,您应该使用@EnableAsync

让我们从使用 Java 配置启用异步处理开始 - 只需将 @EnableAsync 添加到配置类:

@Configuration
@EnableAsync
public class SpringAsyncConfig { ... }

您必须使用从其他类调用的public 方法:

@Async 有两个限制:

  • 只能应用于公共方法

  • 自调用 - 从同一类中调用异步方法 - 不起作用

【讨论】:

  • 请注意,这些限制来自于 Spring 通常如何实现通知(通过代理对象);适用于各种建议,而不仅仅是@Async;并且通常可以通过使用 AspectJ weaving 来避免。
  • 自调用——从同一个类中调用异步方法——不起作用这个^完全忘记了。 :(
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-10-25
  • 1970-01-01
  • 2023-03-12
相关资源
最近更新 更多