为每次迭代安排任务的新日期-Java Spring

时间:2019-01-04 18:36:58

标签: java spring-boot task schedule

每次执行任务时,我都需要安排新的日期。 我已经看到许多示例,其中周期或间隔由毫秒定义,并在每次迭代中保持不变,但是我找不到任何需要日期参数的下一次执行

由于我正在使用Spring,所以尝试了@Scheduled批注,但是我不知道是否可以传递参数。

我见过的例子

示例1:

@Scheduled(fixedRate = 20000)
    public void scheduler() {
        log.info("scheduler");
        log.info("Current Thread " + Thread.currentThread().getName());
        log.info("Current Thread " + Thread.currentThread().getId());
}

示例2:

ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
        scheduler.scheduleAtFixedRate(myRunnable, 10, 10, TimeUnit.MINUTES);

我希望从数据库表中读取日期,以安排任务进行新的迭代

请帮忙!

修改

注意:还有一段时间,我需要决定在哪里停止下一次迭代,因此我试图通过一种方法调用调度任务

2 个答案:

答案 0 :(得分:1)

您可以注册新的TimerTask,执行所需的逻辑,并在所需逻辑完成时注册新的TimerTask

public class Starter {

    public void execute() {
        Timer timer = new Timer();
        Date firstExecutionDate = // ... compute ...
        timer.schedule(
            new RepeatedTimerTask(timer, this::toDoUponEachExecution, this::findNextExecutionDate),
            firstExecutionDate
        );
    }

    private Date findNextExecutionDate() {
        // ... compute ...
    }

    private void toDoUponEachExecution() {
        // ... do something ...
    }
}

public class RepeatedTimerTask extends TimerTask {

    private final Timer timer;
    private final Runnable logic;
    private final Supplier<Date> nextExecution;

    public RepeatedTimerTask(Timer timer, Runnable logic, Supplier<Date> nextExecution) {
        this.timer = timer;
        this.logic = logic;
        this.nextExecution = nextExecution;
    }

    @Override
    public void run() {
        logic.run();
        timer.schedule(this, nextExecution.get());
    }
}

答案 1 :(得分:1)

我避免使用Spring,因此在这里我无法为您提供帮助。但是我可以指导您使用ScheduledExecutorService来实现您的目标。

ScheduledExecutorService::schedule​( Runnable command, long delay, TimeUnit unit )

您对ScheduledExecutorService的看法是部分正确的:它的三种调度策略中的两种旨在保持每次运行之间的定期间隔:

但是,第三种策略使您可以设置任意延迟的下一次运行。

如果您希望重复执行一个任务而不是同时执行,请使用single-thread executor

ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor() ;

在该ScheduledExecutorService上安排您的任务。并且使该任务的最后一步成为安排下一次事件的繁琐工作。我们有一台永动机,每次运行任务时,它都会无限期地计划下一次运行。

定义您的Runnable任务。

    Runnable runnable = new Runnable() {
        @Override
        public void run ( ) {
            // Do the work of this task.
            ZonedDateTime zdt = ZonedDateTime.now( ZoneId.systemDefault() ); // Capture the current moment.
            System.out.println( "Current moment: " + zdt ); // Report the current moment.
            // Schedule the next run of this task.
            scheduledExecutorService.schedule( this , 10L , TimeUnit.SECONDS );  // Delay will not be *exactly* this amount of time due to interruptions of scheduling cores on CPU and threads by the JVM and host OS.
        }
    };

然后运行它。

    // Jump-start this perpetual motion machine.
    scheduledExecutorService.schedule( runnable , 0L , TimeUnit.SECONDS );  // Start immediately, no delay.

让执行者在一定时间内重复执行其工作。当执行程序服务在后台线程上运行时,请使主线程休眠。

    try {
        Thread.sleep( TimeUnit.MINUTES.toMillis( 2 ) );  // Let our app, and the executor, run for 2 minutes, then shut them both down.
    } catch ( InterruptedException e ) {
        e.printStackTrace();
    }

记住要始终关闭执行程序。否则,其后台线程可能会在您的主应用退出后很长时间继续运行。

    scheduledExecutorService.shutdown();
    System.out.println( "INFO - Executor shutting down. App exiting. " + ZonedDateTime.now( ZoneId.systemDefault() ) );

提示:对于所有异常,请始终将您的Runnable代码包装在try-catch中。到达执行者服务的任何未捕获的异常都将导致执行者立即停止并默默停止。

    Runnable runnable = new Runnable() {
        @Override
        public void run ( ) {
            try {
                // Do the work of this task.
                ZonedDateTime zdt = ZonedDateTime.now( ZoneId.systemDefault() ); // Capture the current moment.
                System.out.println( "Current moment: " + zdt ); // Report the current moment.
                // Schedule the next run of this task.
                scheduledExecutorService.schedule( this , 10L , TimeUnit.SECONDS );  // Delay will not be *exactly* this amount of time due to interruptions of scheduling cores on CPU and threads by the JVM and host OS.
            } catch ( Exception e ) {
                // TODO: Handle unexpected exeption.
                System.out.println( "ERROR - unexpected exception caught on its way to reaching a scheduled executor service. Message # 55cbae82-8492-4638-9630-60c5b28ad876." );
            }
        }
    };
  

我希望从数据库表中读取日期,以安排任务进行新的迭代

请勿使用DateCalendar。几年前, java.time 取代了这些可怕的类,并采用了JSR 310。

从JDBC 4.2及更高版本开始,我们可以直接与数据库交换 java.time 对象。

OffsetDateTime now = OffsetDateTime.now( ZoneOffset.UTC ) ;
OffsetDateTime later = myResultSet.getObject( … , OffsetDateTime.class ) ;
if( ! now.isBefore( later ) ) { … } // Verify the future moment is indeed in the future.

计算经过的时间,这是我们要延迟到下一次计划运行的时间。

Duration d = Duration.between( now , odt ) ;
long seconds = d.toSeconds() ; // Truncates any fractional second.

使用该秒数来安排下一次运行。

scheduledExecutorService.schedule( this , seconds , TimeUnit.SECONDS ); 

所以Runnable现在看起来像这样。

    Runnable runnable = new Runnable() {
        @Override
        public void run ( ) {
            try {
                // Do the work of this task.
                ZonedDateTime zdt = ZonedDateTime.now( ZoneId.systemDefault() ); // Capture the current moment.
                System.out.println( "Current moment: " + zdt ); // Report the current moment.
                // Schedule the next run of this task.
                OffsetDateTime now = OffsetDateTime.now( ZoneOffset.UTC ) ;
                … do your database query …
                OffsetDateTime later = myResultSet.getObject( … , OffsetDateTime.class ) ;
                if( ! now.isBefore( later ) ) { … } // Verify the future moment is indeed in the future.
                Duration d = Duration.between( now , odt ) ;
                long seconds = d.toSeconds() ; // Truncates any fractional second.
                scheduledExecutorService.schedule( this , seconds , TimeUnit.SECONDS );  // Delay will not be *exactly* this amount of time due to interruptions of scheduling cores on CPU and threads by the JVM and host OS.
            } catch ( Exception e ) {
                // TODO: Handle unexpected exeption.
                System.out.println( "ERROR - unexpected exception caught on its way to reaching a scheduled executor service. Message # 55cbae82-8492-4638-9630-60c5b28ad876." );
            }
        }
    };

这是单个.java文件中的完整示例,但没有数据库查询。

package work.basil.example;

import java.util.concurrent.*;
import java.time.*;

public class ScheduleNextTaskExample {
    public static void main ( String[] args ) {
        ScheduleNextTaskExample app = new ScheduleNextTaskExample();
        app.doIt();
    }

    private void doIt ( ) {
        ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();

        Runnable runnable = new Runnable() {
            @Override
            public void run ( ) {
                try {
                    ZonedDateTime zdt = ZonedDateTime.now( ZoneId.systemDefault() ); // Capture the current moment.
                    System.out.println( "Current moment: " + zdt ); // Report the current moment.
                    scheduledExecutorService.schedule( this , 10L , TimeUnit.SECONDS );  // Delay will not be *exactly* this amount of time due to interruptions of scheduling cores on CPU and threads by the JVM and host OS.
                } catch ( Exception e ) {
                    // TODO: Handle unexpected exeption.
                    System.out.println( "ERROR - unexpected exception caught on its way to reaching a scheduled executor service. Message # 55cbae82-8492-4638-9630-60c5b28ad876." );
                }
            }
        };

        // Jump-start this perpetual motion machine.
        scheduledExecutorService.schedule( runnable , 0L , TimeUnit.SECONDS );  // Start immediately, no delay.
        try {
            Thread.sleep( TimeUnit.MINUTES.toMillis( 2 ) );  // Let our app, and the executor, run for 2 minutes, then shut them both down.
        } catch ( InterruptedException e ) {
            e.printStackTrace();
        }
        scheduledExecutorService.shutdown();
        System.out.println( "INFO - Executor shutting down. App exiting. " + ZonedDateTime.now( ZoneId.systemDefault() ) );

    }
}