I am using Spring boot with @EnableScheduling
and @EnableAsync
.
I have a method which is annotated with @Scheduled
.
I have a few more methods, which are annotated with @Async
.
Now I am calling these @Async
methods in the @Scheduled
method and printing out the name of the current thread in the async methods. What I see is they all have same thread name, which in fact is the thread that is running the @Scheduled
method.
I don't see asynchronous method execution. What is wrong here?
Here is my application boot class
@SpringBootApplication
@EnableScheduling
@EnableAsync
public class ApplicationBoot {
public static void main(String[] args) {
SpringApplication.run(ApplicationBoot.class, args);
}
}
Here is my scheduler class
@Component
public class TaskScheduler {
private static final Logger logger = Logger.getLogger(TaskScheduler.class);
@Scheduled(fixedDelay = 10000)
public void ScheduledMethod() {
methodOne();
methodTwo();
methodThree();
}
@Async
private void methodOne() {
logger.info("Method one called by Thread : " + Thread.currentThread().getName() + " at " + new Date());
}
@Async
private void methodTwo() {
logger.info("Method two called by Thread : " + Thread.currentThread().getName() + " at " + new Date());
}
@Async
private void methodThree() {
logger.info("Method three called by Thread : " + Thread.currentThread().getName() + " at " + new Date());
}
}
Output
Method one called by Thread : pool-1-thread-1 at Tue Apr 04 16:32:27 IST 2017
Method two called by Thread : pool-1-thread-1 at Tue Apr 04 16:32:27 IST 2017
Method three called by Thread : pool-1-thread-1 at Tue Apr 04 16:32:27 IST 2017
Never use @Async on top of a private method. In runtime, it will not able to create a proxy and, therefore, not work. 3. Never write an Async method in the same class where the caller method invokes the same Async methodAsync method in the same class where the caller method invokes the same Async method.
To enable the asynchronous processing, add the @EnableAsync annotation to the configuration class. The @EnableAsync annotation switches on Spring's ability to run @Async methods in a background thread pool.
self-invocation - calling the async method from within the same class. It won't work. Because in this case, although it creates a proxy, the call bypasses the proxy and directly call the method so that Thread will not be spawned.
Explanation
Spring creates a proxy around your instance. ScheduledMethod
calls internally 3 methods, which are not proxified and thus not asynchronous.
cf. the documentation:
If you invoke a method on an object reference, the method is invoked directly on that object reference, as can be seen below.
See this question Spring AOP not working, when the method is called internally within a bean
for a workaround, but the best is the one proposed in the doc The best approach (the term best is used loosely here) is to refactor your code such that the self-invocation does not happen...
Note that, private method is not supported too:
Due to the proxy-based nature of Spring’s AOP framework, protected methods are by definition not intercepted, neither for JDK proxies (where this isn’t applicable) nor for CGLIB proxies (where this is technically possible but not recommendable for AOP purposes). As a consequence, any given pointcut will be matched against public methods only!
Workaround example
@Component
public class ServiceMethod {
private static final Logger logger = Logger.getLogger(ServiceMethod .class);
@Async
public void methodOne() {
logger.info("Method one called by Thread : " + Thread.currentThread().getName() + " at " + new Date());
}
@Async
public void methodTwo() {
logger.info("Method two called by Thread : " + Thread.currentThread().getName() + " at " + new Date());
}
@Async
public void methodThree() {
logger.info("Method three called by Thread : " + Thread.currentThread().getName() + " at " + new Date());
}
}
@Component
public class TaskScheduler {
private static final Logger logger = Logger.getLogger(TaskScheduler.class);
@Autowired
private ServiceMethod serviceMethod;
@Scheduled(fixedDelay = 10000)
public void ScheduledMethod() {
serviceMethod.methodOne();
serviceMethod.methodTwo();
serviceMethod.methodThree();
}
}
You might have not configured Thread Pool
with more Threads
for your Scheduler
.
From the docs
If you do not provide a pool-size attribute, the default thread pool will only have a single thread.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With