使用@Scheduling在@Scheduled(fixedRate = 10000)运行方法并通过实现SchedulingConfigurer设置@Scheduling线程
@Bean(destroyMethod="shutdown")
public Executor taskExecutor() {
return Executors.newScheduledThreadPool(10);
}
如果我使用Thread.sleep或Lock,除非Thread.sleep唤醒或锁定被清除,否则Executor不会创建其他线程。
如果我有10个游泳池大小,他们可以解释内部工作,他们应该以10000毫秒的速度创建10个线程。
答案 0 :(得分:0)
在您使用threadpool的情况下: 默认情况下,您的池中将有10个线程(已初始化)。 @scheduled第一次执行时,这个函数将在你的池中的一个线程中执行(现在剩下9个线程),如果函数已经完成并再次执行@scheduled,你的函数将在你的其他线程中执行你的游泳池,所以现在游泳池里剩下8个线程。 (8个空闲,2个正在运行的线程)
如果您不使用线程池,则只使用一个线程。
spring文档:
如果您没有提供游泳池大小的'属性,默认线程池 将只有一个线程。没有其他配置 调度程序的选项。
https://docs.spring.io/spring/docs/4.3.x/spring-framework-reference/html/scheduling.html
答案 1 :(得分:0)
基本上这种行为来自ScheduledExecutorService
实现,它在spring内部使用。如果您将运行此代码,您会注意到相同的行为:
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();
}
当您向预定的线程池提交任务时,它将被RunnableScheduledFuture
包装,并传递给delayedExecute
方法。如果当前工作人员数小于corePoolSize
,此方法会将任务添加到任务队列并启动新工作人员。 Worker尝试从队列中获取任务并处理它调用run
方法。有一个专用的DelayedWorkQueue
实现,只有在它们准备好执行时才返回任务。以下是run
的{{1}}方法:
RunnableScheduledFuture
正如您所见,它在 /**
* 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);
}
}
中调用实际任务逻辑,计算下一个运行时间并再次将相同的更新任务提交到队列(runAndReset
几乎与reExecutePeriodic
相同)。对于所有执行只有一个周期性任务,在上一次执行完成后,一次又一次地重新提交更新时间。因此,这样的线程池在任何给定时刻只运行每个任务类型的单个实例,并且仅针对不同类型的任务进行扩展。
如果您对春季计划任务如何看待schedule
课程,特别是ScheduledTaskRegistrar
方法感兴趣。