1. 未指定线程池
需要注意的@Scheduled默认情况下只有一个线程,并不能同时运行多个任务,分析源码可以看到
运行demo 在控制台我们可以看到打印出来的线程名称
2. 指定线程池运行定时任务
自定义一个线程工厂继承ThreadFactory进行线程配置
package com.example.demo;
import lombok.extern.log4j.Log4j;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicLong;
/**
* @author jianglinmao
*/
@Log4j
public class MyThreadFactory implements ThreadFactory {
private final String namePrefix;
private final int priority;
/**
* 线程池线程命名编号
*/
private final AtomicLong sequenceNo = new AtomicLong(0);
/**
* 定义线程优先级
* @param namePrefix
* @param priority
*/
public MyThreadFactory(String namePrefix, int priority) {
this.namePrefix = namePrefix;
if (priority < Thread.MIN_PRIORITY) {
this.priority = Thread.MIN_PRIORITY;
} else if (priority > Thread.MAX_PRIORITY) {
this.priority = Thread.MAX_PRIORITY;
} else {
this.priority = priority;
}
}
/**
* 定义线程名称
* @param runnable
* @return
*/
@Override
public Thread newThread(Runnable runnable) {
String threadName = String.format("%s-%d", namePrefix, sequenceNo.getAndIncrement());
Thread thread = new Thread(runnable, threadName);
thread.setDaemon(false);
thread.setPriority(priority);
thread.setUncaughtExceptionHandler((t, e) -> log.info( "UNCAUGHT in thread " + t.getName(), e));
return thread;
}
}
自定义一个定时线程池继承ScheduledThreadPoolExecutor
package com.example.demo;
import org.springframework.scheduling.support.DelegatingErrorHandlingRunnable;
import org.springframework.scheduling.support.ScheduledMethodRunnable;
import java.util.concurrent.Callable;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* @author jianglinmao
*/
public class MySystemScheduledThreadPoolExecutor extends ScheduledThreadPoolExecutor {
public MySystemScheduledThreadPoolExecutor(int corePoolSize, String namePrefix, int priority) {
super(corePoolSize, new MyThreadFactory(namePrefix, priority));
super.setMaximumPoolSize(corePoolSize * 4);
}
@Override
public ScheduledFuture<?> schedule(Runnable command,
long delay, TimeUnit unit) {
return super.schedule(wrapScheduledRunnable(command), delay, unit);
}
@Override
public <V> ScheduledFuture<V> schedule(Callable<V> callable,
long delay, TimeUnit unit) {
return super.schedule(callable, delay, unit);
}
@Override
public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
long initialDelay,
long period,
TimeUnit unit) {
return super.scheduleAtFixedRate(wrapScheduledRunnable(command), initialDelay, period, unit);
}
@Override
public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,
long initialDelay,
long delay,
TimeUnit unit) {
return super.scheduleWithFixedDelay(wrapScheduledRunnable(command), initialDelay, delay, unit);
}
/**
* 仅对@Scheduled的代理runnable再包装一层代理
*/
private Runnable wrapScheduledRunnable(Runnable runnable) {
if (runnable instanceof DelegatingErrorHandlingRunnable || runnable instanceof ScheduledMethodRunnable) {
return new StatisticableRunnable(runnable);
}
return runnable;
}
}
重写配置项
package com.example.demo;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import java.util.concurrent.ScheduledExecutorService;
/**
* @author jlm
* @date 2021-01-28 16:08
*/
@Configuration
public class ScheduledConfig implements SchedulingConfigurer {
private static final int SCHEDULE_POOL_SIZE = 64;
@Override
public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
scheduledTaskRegistrar.setScheduler(taskExecutor());
}
@Bean(destroyMethod = "shutdown")
public ScheduledExecutorService taskExecutor() {
return new MySystemScheduledThreadPoolExecutor(SCHEDULE_POOL_SIZE, "my-schedule-pool", Thread.MAX_PRIORITY);
}
}
测试:
两个方法执行的时间相同,线程名称也不相同,并且线程名称是我们所定义的,说明已经成功指定使用自己定义的线程池