简体   繁体   中英

Spring Java @Scheduling configuration

Using @Scheduling to run method at @Scheduled(fixedRate = 10000) and set up @Scheduling threading by implementing SchedulingConfigurer

    @Bean(destroyMethod="shutdown")
    public Executor taskExecutor() {
        return Executors.newScheduledThreadPool(10);
    }

if I used Thread.sleep or Lock , no other thread is created by Executor unless Thread.sleep wake up or lock is cleared.

Can someone explain internal working if i have 10 pool size they 10 threads should be created at rate of 10000 millisec.

In the case that you use threadpool: By default you going to have 10 threads in your pool(already initialized). The first time that @scheduled is executed, this function is going to execute in a thread from your pool (now remaining 9 threads), if the function yet finished and @scheduled is executed again, your function going to executed in other thread from you your pool, so now you have 8 thread remaining in your pool. (8 idle, 2 running threads)

If you aren`t use threadpool only one thread is used.

spring documentation:

If you do not provide a 'pool-size' attribute, the default thread pool will only have a single thread. There are no other configuration options for the scheduler.

https://docs.spring.io/spring/docs/4.3.x/spring-framework-reference/html/scheduling.html

Basically such behavior comes from ScheduledExecutorService implementation which is used internally by spring. If you will run this code you will notice the same behavior:

public static void main(String[] args) throws Exception {
    ScheduledExecutorService executor = Executors.newScheduledThreadPool(10);
    executor.schedule(() -> {
        System.out.println("Running task in thread " + Thread.currentThread().getId());
        try {
            Thread.sleep(Integer.MAX_VALUE);
        } catch (InterruptedException e) {
            System.out.println("interrupted while sleeping");
        }
    }, 1000, TimeUnit.MILLISECONDS);
    Thread.sleep(10000);
    executor.shutdownNow();
}

When you submit task to scheduled thread pool it is wrapped with RunnableScheduledFuture which is passed to delayedExecute method. This method adds the task to the tasks queue and starts new worker if current number of workers is less than corePoolSize . Worker tries to get a task from the queue and process it invoking run method. There is a dedicated DelayedWorkQueue implementation which returns tasks only if they are ready for execution. Here is how run method of RunnableScheduledFuture looks like:

    /**
     * Overrides FutureTask version so as to reset/requeue if periodic.
     */
    public void run() {
        boolean periodic = isPeriodic();
        if (!canRunInCurrentRunState(periodic))
            cancel(false);
        else if (!periodic)
            ScheduledFutureTask.super.run();
        else if (ScheduledFutureTask.super.runAndReset()) {
            setNextRunTime();
            reExecutePeriodic(outerTask);
        }
    }

As you can see it invokes actual task logic in runAndReset , calculates the next running time and submits the same updated task to the queue again ( reExecutePeriodic is almost the same as schedule ). There is only a single periodic task for all executions which is resubmitted again and again with updated time after the previous execution is finished. So such thread pool runs only a single instance of each task type in any given moment and scales only for different type of tasks.

If you are interesting in how spring schedules tasks take a look at ScheduledTaskRegistrar class and particularly at scheduleFixedDelayTask method.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM