Tilak Raj
Tilak Raj

Reputation: 1499

Spring @Async vs completable future run async

I might have been doing something really wrong. So, I have Spring's @Async

Let's say I have this piece of code

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

I have one more, let's say I have this piece of code

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

Now with the second code I can see, some threads got spawned but the first approach doesn't seem to spawn more than one?

Upvotes: 4

Views: 11952

Answers (3)

akuma8
akuma8

Reputation: 4691

As @M.Deinum underlined in his comment, doing this:

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

Is useless unless you really need it, because: @Async sends the execution of your method in the poolbeanname thread pool and CompletableFuture.runAsync{ new Runnable ()...} will spawn new thread out of your poolbeanname.

You can simply do this:

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

Note that because of spring's object proxies, if you do this:

@Service
class YourService {

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

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

But you can use this workaround by auto-injecting the bean.

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

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

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

Upvotes: 1

Rentius2407
Rentius2407

Reputation: 1148

@Async("poolbeanname") 
Function () {
}

The above snippet will execute asynchronously using a thread pool, if you have @EnableAsync in a configuration class.

@Configuration
@EnableAsync

or

@SpringBootApplication
@EnableAsync

When asynchronous is enabled, spring will search for a custom taskExecutor or a executor bean, if it is not found it will default to its own taskExecutor.

Check your log for the line where it says Initializing ExecutorService.... Out of the box it says that it initialized o.s.s.concurrent.ThreadPoolTaskExecutor which will give you a core pool size of 1 by default.

To override the executor one only has to add a factory method to a configuration class for the Executor.

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

If the executor was overridden, it might be that a one thread pool size was specified or Executors.newSingleThreadExecutor(); was used.

CompletableFuture:

The code CompletableFuture.runAsync{ new Runnable ()} will create a CompletableFuture instance and execute the code asynchronously (create a thread) every time it is called.

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

Upvotes: 1

Ori Marko
Ori Marko

Reputation: 58882

To enable using @Async you should use @EnableAsync

Let’s start by enabling asynchronous processing with Java configuration – by simply adding the @EnableAsync to a configuration class:

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

And you must use a public method called from other class:

@Async has two limitations:

  • it must be applied to public methods only

  • self-invocation – calling the async method from within the same class – won’t work

Upvotes: 5

Related Questions