By Default, the Spring boot scheduler runs using default thread pool of size one. ThreadPoolTaskScheduler allows to create a custom thread pool with any pool size. The size of the pool must be set to 1 or higher. The size of the pool must be set higher if you are using lot of schedulers in your application or if the frequency of the scheduler is higher.

2019-12-21 05:51:24.747 ERROR 13915 --- [           main] o.s.boot.SpringApplication               : Application run failed
 java.lang.IllegalArgumentException: 'poolSize' must be 1 or higher
     at org.springframework.util.Assert.isTrue(Assert.java:118) ~[spring-core-5.2.1.RELEASE.jar:5.2.1.RELEASE]
     at org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler.setPoolSize(ThreadPoolTaskScheduler.java:83) ~[spring-context-5.2.1.RELEASE.jar:5.2.1.RELEASE]
     at com.yawintutor.SchedulerCustomThread.configureTasks(SchedulerCustomThread.java:27) ~[classes/:na]
     at org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor.finishRegistration(ScheduledAnnotationBeanPostProcessor.java:248) ~[spring-context-5.2.1.RELEASE.jar:5.2.1.RELEASE]
     at org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor.onApplicationEvent(ScheduledAnnotationBeanPostProcessor.java:233) ~[spring-context-5.2.1.RELEASE.jar:5.2.1.RELEASE]
     at org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor.onApplicationEvent(ScheduledAnnotationBeanPostProcessor.java:105) ~[spring-context-5.2.1.RELEASE.jar:5.2.1.RELEASE]
     at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:172) ~[spring-context-5.2.1.RELEASE.jar:5.2.1.RELEASE]
     at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:165) ~[spring-context-5.2.1.RELEASE.jar:5.2.1.RELEASE]
     at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:139) ~[spring-context-5.2.1.RELEASE.jar:5.2.1.RELEASE]
     at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:403) ~[spring-context-5.2.1.RELEASE.jar:5.2.1.RELEASE]
     at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:360) ~[spring-context-5.2.1.RELEASE.jar:5.2.1.RELEASE]
     at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:897) ~[spring-context-5.2.1.RELEASE.jar:5.2.1.RELEASE]
     at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:553) ~[spring-context-5.2.1.RELEASE.jar:5.2.1.RELEASE]
     at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:747) [spring-boot-2.2.1.RELEASE.jar:2.2.1.RELEASE]
     at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397) [spring-boot-2.2.1.RELEASE.jar:2.2.1.RELEASE]
     at org.springframework.boot.SpringApplication.run(SpringApplication.java:315) [spring-boot-2.2.1.RELEASE.jar:2.2.1.RELEASE]
     at org.springframework.boot.SpringApplication.run(SpringApplication.java:1226) [spring-boot-2.2.1.RELEASE.jar:2.2.1.RELEASE]
     at org.springframework.boot.SpringApplication.run(SpringApplication.java:1215) [spring-boot-2.2.1.RELEASE.jar:2.2.1.RELEASE]
     at com.yawintutor.SpringSchedulerApplication.main(SpringSchedulerApplication.java:12) [classes/:na]


Root Cause

In the Spring boot, ThreadPoolTaskScheduler creates a pool of threads that are used to run schedulers. ThreadPoolTaskScheduler must have at least one thread. If you configure the size of the pool as zero or negative, then this exception is thrown by the application



How to reproduce this issue

If you configure the size of the pool to be zero or less, this issue will occur. This issue will be reproduced by the following code 

package com.yawintutor;

import java.text.SimpleDateFormat;
import java.util.Date;

import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import org.springframework.stereotype.Component;

@Component
public class SchedulerCustomThread implements SchedulingConfigurer {
	private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
	private int POOL_SIZE = 0;
	
	@Scheduled(fixedRate = 5000)
	public void task() {
		System.out.println(Thread.currentThread().getName() + " Scheduler (Fixed Rate = 5000) task with duration : " + sdf.format(new Date()));
	}

	@Override
	public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
		ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler();


        threadPoolTaskScheduler.setPoolSize(POOL_SIZE);
        threadPoolTaskScheduler.setThreadNamePrefix("my-pool-");
        threadPoolTaskScheduler.initialize();

        taskRegistrar.setTaskScheduler(threadPoolTaskScheduler);
        
	}
}


Solution 1

Configure the size of the pool as one or more in the ThreadPoolTaskScheduler. This configuration will resolve this exception. This issue will be resolved by the code below.

package com.yawintutor;

import java.text.SimpleDateFormat;
import java.util.Date;

import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import org.springframework.stereotype.Component;

@Component
public class SchedulerCustomThread implements SchedulingConfigurer {
	private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
	private int POOL_SIZE = 10;
	
	@Scheduled(fixedRate = 5000)
	public void task() {
		System.out.println(Thread.currentThread().getName() + " Scheduler (Fixed Rate = 5000) task with duration : " + sdf.format(new Date()));
	}

	@Override
	public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
		ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler();


        threadPoolTaskScheduler.setPoolSize(POOL_SIZE);
        threadPoolTaskScheduler.setThreadNamePrefix("my-pool-");
        threadPoolTaskScheduler.initialize();

        taskRegistrar.setTaskScheduler(threadPoolTaskScheduler);
        
	}
}


Solution 2

Use the default thread pool task created by spring boot. By default, a pool with a size of one will be created.

package com.yawintutor;

import java.text.SimpleDateFormat;
import java.util.Date;

import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

@Component
public class SchedulerCustomThread {
	private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
	private int POOL_SIZE = 10;
	
	@Scheduled(fixedRate = 5000)
	public void task() {
		System.out.println(Thread.currentThread().getName() + " Scheduler (Fixed Rate = 5000) task with duration : " + sdf.format(new Date()));
	}
}



Leave a Reply