Spring调度任务 - 只运行一次

时间:2015-05-20 10:39:07

标签: java spring cron scheduled-tasks

是否可以在指定时间仅安排一次Spring服务方法?例如,当前时间是下午2点,但是当我点击操作按钮时,我希望我的服务方法在晚上8点开始。我熟悉@Scheduled注释,我不知道如何编写cron表达式而不是定期运行。这一private void ListView_Loaded(object sender, RoutedEventArgs e) { var test = GridViewInstance.Columns[0].ActualWidth; } 每天晚上8点开火 有什么建议吗?

5 个答案:

答案 0 :(得分:25)

您可以使用Spring的TaskScheduler实现之一。我在下面提供了一个示例,其中一个不需要太多配置(ConcurrentTaskScheduler包装单线程预定执行程序)。

  

最简单的方法是名为 schedule 的方法,它采用Runnable   和日期。这将导致任务之后运行一次   指定时间。所有其他方法都能够进行调度   任务重复运行。

详细了解task execution & scheduling

简单的工作示例:

private TaskScheduler scheduler;

Runnable exampleRunnable = new Runnable(){
    @Override
    public void run() {
        System.out.println("Works");
    }
};

@Async
public void executeTaskT() {
    ScheduledExecutorService localExecutor = Executors.newSingleThreadScheduledExecutor();
    scheduler = new ConcurrentTaskScheduler(localExecutor);

    scheduler.schedule(exampleRunnable,
            new Date(1432152000000L));//today at 8 pm UTC - replace it with any timestamp in miliseconds to text
}

...

executeTaskT() //call it somewhere after the spring application has been configured

注意

  

启用对@Scheduled和@Async注释的支持添加   @EnableScheduling和@EnableAsync到你的@Configuration之一   类

更新 - 取消预定任务

TaskScheduler的schedule方法返回ScheduledFuture,这是一个延迟的结果承载动作,可以取消

因此,为了取消它,您需要保留计划任务的句柄(即保留ScheduledFuture返回对象)。

更改上述代码以取消任务:

  1. 在executeTaskT方法之外声明ScheduledFuture。 private ScheduledFuture scheduledFuture;

  2. 将您的调用修改为schedule以保持返回对象: scheduledFuture = scheduler.schedule(exampleRunnable, new Date(1432152000000L));

  3. 在代码中的某处调用scheduledFuture对象取消 boolean mayInterruptIfRunning = true; scheduledFuture.cancel(mayInterruptIfRunning);

答案 1 :(得分:5)

死人的解决方案:

@Scheduled(ini​​tialDelay = 1000 * 30,fixedDelay = Long.MAX_VALUE)

在再次开火之前,您已经死了。

答案 2 :(得分:1)

为了不在每个方法调用中创建ScheduledExecutorServiceConcurrentTaskScheduler,在服务创建时初始化TaskScheduler会很方便,例如

private final TaskScheduler taskScheduler = 
              new ConcurrentTaskScheduler(Executors.newScheduledThreadPool(10));

@Async毫无意义,因为我们只是安排任务并退出方法。

答案 3 :(得分:0)

您可以按如下方式扩展PeriodicTrigger - 它会检查lastCompletionTime:如果任务以前从未运行过,它将为null。如果您想在某个给定时间运行一次任务,可以尝试对此进行更改。

class RunOnceTrigger extends PeriodicTrigger {
    public RunOnceTrigger(long period) {
        super(period);
        setInitialDelay(period);
    }

    @Override
    public Date nextExecutionTime(TriggerContext triggerContext) {
        if(triggerContext.lastCompletionTime() == null) {   // hasn't executed yet
            return super.nextExecutionTime(triggerContext);
        }
        return null;
    }
}

答案 4 :(得分:0)

该问题的标题表示需要一口气完成任务。这是一个任务类,该类将在延迟后运行一次(或在OP请求时以一个时期代替)。另外,您可以在 application.properties/yaml 或使用配置文件中启用/禁用它。

@Slf4j
@Component
@ConditionalOnProperty({ "app.scheduler.onceRunner" })
public class RunOnceTask
{
    public static final long INITIAL_DELAY_SECS = 5L;  // As you wish

    @Autowired
    @Qualifier("mainTaskScheduler") // You could set a custom TPTS to set threads, name, etc.
    private ThreadPoolTaskScheduler poolTaskScheduler;

    @PostConstruct
    public void run()
    {
        poolTaskScheduler.scheduleWithFixedDelay( () -> {

            log.info( "Once-runner ran once" );

        }, new Date( System.currentTimeMillis() + (INITIAL_DELAY_SECS * 1000) ), Long.MAX_VALUE );    // Run once
    }
}