Problems using spring @Scheduled

This happens because @Async task is submitted by default Scheduling executor and its size is 1 by default.

I have modified submit method of the AsyncTaskExecutor executor:

  @Bean
    AsyncConfigurer asyncConfigurer() {
        return new AsyncConfigurer() {
            @Override
            public AsyncTaskExecutor getAsyncExecutor() {
                ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(){
                    @Override
                    public <T> Future<T> submit(Callable<T> task) {
                        System.out.println("async task was started by thread -- "+Thread.currentThread().getName());
                        return super.submit(task);
                    }
                };
                executor.setThreadNamePrefix("custom-async-exec");
                executor.setCorePoolSize(2);
                executor.setQueueCapacity(100);
                executor.initialize();
                return executor;
            }
        };
    } 

And output.

async task was started by thread -- scheduling-1
async task was started by thread -- scheduling-1
async task was started by thread -- scheduling-1
async task was started by thread -- scheduling-1
async task was started by thread -- scheduling-1
async task was started by thread -- scheduling-1
async task was started by thread -- scheduling-1
async task was started by thread -- scheduling-1
async task was started by thread -- scheduling-1
async task was started by thread -- scheduling-1

So as there is 1 thread into default Shedulers pool scheduling-1 and whenever its busy can't start/submit new @Async tasks. define @Bean ThreadPoolTaskExecutor or add spring.task.scheduling.pool.size=x.

EDIT

Here is simple test for visualization:

@Component
    public static class Jobs{
        @Scheduled(fixedDelay = 1500)
        @Async
        public void job1(){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        @Scheduled(fixedDelay = 1500)
        @Async
        public void job2(){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        @Scheduled(initialDelay = 10000, fixedDelay = 5000)
        public void blocking(){
            try {
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

visualization from visualvm

enter image description here

Red 'arrows' shows the point blocking() job kicks in. and while scheduling-1 Thread blocked on this there is no way to submit job1() and job2() also


Scheduled tasks are processed by the ThreadPoolTaskScheduler, which has a default pool size of 1. Only when they are annotated as @Async, execution is passed into the AsyncTaskExecutor, which for you configured a dedicated executor with a larger pool size.

To configure the ThreadPoolTaskScheduler within a @Configuration class:

@Bean
public ThreadPoolTaskScheduler threadPoolTaskScheduler(){
    ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
    scheduler.setThreadNamePrefix("ThreadPoolTaskScheduler");
    scheduler.setPoolSize(50);
    return scheduler ;
}

All @Scheduled marked invocations will use the default single thread executor to schedule tasks (async or otherwise).

All @Async tasks are handed off to different aysnc threadpool executor for executions with AOP interceptor.

I think your confusion comes from the fact async methods return immediately but when deleteOldData is run, it is running synchronously as there is only one thread, it blocks the execution of any other scheduled tasks.

Because you have default threadpool (single thread) for the scheduled tasks they are scheduled one after the another.

The other methods annotated with @Async they execute even if it finishes or not. In some cases, I have two methods of executing at the same time. But when deleteOldData is executing, the async methods stop to run until it finishes. This what I'm not understanding, sorry :/ –

This is different from scheduling - This is where your async executor comes into play and they are run concurrently.

You can fix this in one of two ways:

You can use spring.task.scheduling.pool.size=10 in application properties to set the pool size of task scheduler.

Alternatively, use different tasks schedulers. Keep using default scheduler for @Scheduled task and configure something like below for async tasks ( remove scheduled annotation )

There is an enhancement requested to pass task scheduler to the @Scheduled annotation until then you have to schedule tasks manually.

Register a new task scheduler for async invocations and schedule the methods in the post construct stage. Something like

Configuration

@Bean("asyncTaskScheduler")
public TaskScheduler asyncTaskScheduler() {
  return new ThreadPoolTaskScheduler();
}

Services

@Autowired
private TaskScheduler asyncTaskScheduler;

@PostConstruct
void schedule() {
  asyncTaskScheduler.scheduleAtFixedRate(this::checkAvailableTasks, 20000L);
  asyncTaskScheduler.scheduleAtFixedDelay(this::checkBrokenEngines, 20000L);
}

@Async
public void checkBrokenEngines() {...}

@Async
public void checkAvailableTasks() throws Exception {...}