Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

spring-boot @scheduled not running in different threads?

I am configuring a scheduled task to run in different threads. Here is the configuration code

@Configuration
@EnableScheduling
public class SchedulerConfig implements SchedulingConfigurer {
    private final int POOL_SIZE = 10;

    @Override
    public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
        ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler();
        threadPoolTaskScheduler.setPoolSize(POOL_SIZE);
        threadPoolTaskScheduler.setThreadNamePrefix("my-sched-pool-");
        threadPoolTaskScheduler.initialize();
        scheduledTaskRegistrar.setTaskScheduler(threadPoolTaskScheduler);
    }
}

Here is the code that uses it

@Scheduled(fixedRateString = "2000" )
    public void testaMethod() {

         log.debug("here is the message");
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }

I am sleeping the thread for 10s with fixedRate of 2s. so I expect to see different threads in the log but I see only one

logs are here

{"thread":"my-sched-pool-1","level":"DEBUG","description":"here is the message"}
{"thread":"my-sched-pool-1","level":"DEBUG","description":"here is the message"}
{"thread":"my-sched-pool-1","level":"DEBUG","description":"here is the message"}
{"thread":"my-sched-pool-1","level":"DEBUG","description":"here is the message"}
like image 295
brain storm Avatar asked Jan 12 '18 20:01

brain storm


People also ask

How does spring boot handle multiple threads?

⚡Dual Threaded ApplicationsAn ExecutorService produced by the Executors. newSingleThreadExecutor() static method can be used to create a single additional thread. The ExecutorService includes the execute() method, which accepts any class implementing the Runnable interface or a lambda expression as an input.

Does @scheduled create a new thread?

@Scheduled causes the code to be run in a separate thread, not necessarily new as it might come from a thread pool.

Is Spring scheduler single threaded?

By default, Spring uses a local single-threaded scheduler to run the tasks. As a result, even if we have multiple @Scheduled methods, they each need to wait for the thread to complete executing a previous task.

How do Spring boots handle threads?

To run asynchronous tasks in your Spring Boot application by using CICS enabled threads, there are two options. You can either set an Asynchronous Executor for the whole application, or you can choose to specify an AsyncExecutor on a per method basis.


1 Answers

@Scheduled(fixedRateString = "2000" ) does not gurantee testaMethod be executed every 2 seconds, if the time cost is more than 2s, such as Thread.sleep(10000), the new task will be put in a queue. Only when the old one has been executed, the scheduler will fetch the new task from queue and execute it. Since the new task is now the only task in the scheduler, it could be run without creating a new Thread.

To solve this problem, you can combile @Async and @Scheduled

SchedulerConfig

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;

@Configuration
@EnableScheduling
public class SchedulerConfig implements SchedulingConfigurer {
    private final int POOL_SIZE = 10;

    @Override
    public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
        scheduledTaskRegistrar.setTaskScheduler(poolScheduler());
    }

    @Bean
    public TaskScheduler poolScheduler() {
        ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
        scheduler.setThreadNamePrefix("poolScheduler");
        scheduler.setPoolSize(POOL_SIZE);
        return scheduler;
    }

}

SchedulerTask

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

@Component
public class SchedulerTask {

    @Autowired
    private AsyncTask asyncTask;

    @Scheduled(fixedRateString = "2000" )
    public void testaMethod() {
        asyncTask.asyncMethod();
    }
}

AsyncTask

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.stereotype.Component;

@Component
@EnableAsync
public class AsyncTask {

    private Log log = LogFactory.getLog(AsyncTask.class);

    @Async
    public void asyncMethod() {
        log.debug("here is the message");
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

Test results

11:20:54.682 [poolScheduler1] DEBUG com.test.AsyncTask - here is the message
11:20:56.668 [poolScheduler3] DEBUG com.test.AsyncTask - here is the message
11:20:58.668 [poolScheduler2] DEBUG com.test.AsyncTask - here is the message
11:21:00.669 [poolScheduler6] DEBUG com.test.AsyncTask - here is the message
11:21:02.669 [poolScheduler7] DEBUG com.test.AsyncTask - here is the message
11:21:04.669 [poolScheduler4] DEBUG com.test.AsyncTask - here is the message
like image 128
xingbin Avatar answered Oct 21 '22 05:10

xingbin