每次迭代为任务安排一个新日期 - Java Spring
Schedule a new Date for a task every iteration - Java Spring
每次执行任务时,我都需要安排一个新的日期。
我见过很多例子,其中周期或间隔由毫秒设置并在每次迭代中保持不变,但我找不到任何接受下一次执行的日期参数的例子
因为我正在使用 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);
我希望从数据库中读取一个日期 table 来安排我的任务进行新的迭代
谢谢你的帮助!
编辑
注意:还有一段时间我需要决定下一次迭代在哪里停止,所以我尝试通过方法调用调度任务
您可以注册一个新的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());
}
}
我避免使用Spring,所以我无法帮助你。但我可以指导您使用 ScheduledExecutorService
来实现您的目标。
ScheduledExecutorService::schedule( Runnable command, long delay, TimeUnit unit )
您对 ScheduledExecutorService
的部分正确:其三种调度策略中的两种旨在保持 运行 之间的固定间隔:
但是第三种策略可以让您设置下一个 运行 任意延迟。
schedule( Runnable command, long delay, TimeUnit unit )
schedule( Callable<V> callable, long delay, TimeUnit unit )
如果您希望重复执行单个任务但不是同时执行,请使用 single-thread executor。
ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor() ;
在那 ScheduledExecutorService
上,安排您的任务。并使该任务的最后一步成为安排下一次发生的苦差事。我们有一个永动机,每次任务运行s,它会无限期地调度下一个运行。
定义您的 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.
让执行器在一定时间内重复执行它的工作。使主线程休眠,而执行程序服务 运行s 在后台线程上。
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();
}
记住总是关闭执行器。否则它的后台线程可能会在您的主应用程序退出后继续 运行ning 很长时间。
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." );
}
}
};
I expect to read a Date from a db table to schedule my task for new iteration
切勿使用 Date
或 Calendar
。多年前,随着 JSR 310 的采用,java.time 取代了那些可怕的 类。
从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() ) );
}
}
每次执行任务时,我都需要安排一个新的日期。 我见过很多例子,其中周期或间隔由毫秒设置并在每次迭代中保持不变,但我找不到任何接受下一次执行的日期参数的例子
因为我正在使用 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);
我希望从数据库中读取一个日期 table 来安排我的任务进行新的迭代
谢谢你的帮助!
编辑
注意:还有一段时间我需要决定下一次迭代在哪里停止,所以我尝试通过方法调用调度任务
您可以注册一个新的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());
}
}
我避免使用Spring,所以我无法帮助你。但我可以指导您使用 ScheduledExecutorService
来实现您的目标。
ScheduledExecutorService::schedule( Runnable command, long delay, TimeUnit unit )
您对 ScheduledExecutorService
的部分正确:其三种调度策略中的两种旨在保持 运行 之间的固定间隔:
但是第三种策略可以让您设置下一个 运行 任意延迟。
schedule( Runnable command, long delay, TimeUnit unit )
schedule( Callable<V> callable, long delay, TimeUnit unit )
如果您希望重复执行单个任务但不是同时执行,请使用 single-thread executor。
ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor() ;
在那 ScheduledExecutorService
上,安排您的任务。并使该任务的最后一步成为安排下一次发生的苦差事。我们有一个永动机,每次任务运行s,它会无限期地调度下一个运行。
定义您的 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.
让执行器在一定时间内重复执行它的工作。使主线程休眠,而执行程序服务 运行s 在后台线程上。
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();
}
记住总是关闭执行器。否则它的后台线程可能会在您的主应用程序退出后继续 运行ning 很长时间。
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." );
}
}
};
I expect to read a Date from a db table to schedule my task for new iteration
切勿使用 Date
或 Calendar
。多年前,随着 JSR 310 的采用,java.time 取代了那些可怕的 类。
从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() ) );
}
}