Spring Java @Scheduling配置

时间:2017-12-19 16:39:18

标签: java spring multithreading spring-java-config spring-scheduled

使用@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个线程。

2 个答案:

答案 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方法感兴趣。