我想每天早上5点执行某项任务。因此,我决定使用ScheduledExecutorService它,但到目前为止,我已经看到了一些示例,这些示例显示了如何每隔几分钟运行一次任务。
ScheduledExecutorService
而且我找不到任何示例来说明如何每天在特定时间(上午5点)每天运行任务,并且还考虑了夏时制的事实-
以下是我的代码,每15分钟运行一次-
public class ScheduledTaskExample { private final ScheduledExecutorService scheduler = Executors .newScheduledThreadPool(1); public void startScheduleTask() { /** * not using the taskHandle returned here, but it can be used to cancel * the task, or check if it's done (for recurring tasks, that's not * going to be very useful) */ final ScheduledFuture<?> taskHandle = scheduler.scheduleAtFixedRate( new Runnable() { public void run() { try { getDataFromDatabase(); }catch(Exception ex) { ex.printStackTrace(); //or loggger would be better } } }, 0, 15, TimeUnit.MINUTES); } private void getDataFromDatabase() { System.out.println("getting data..."); } public static void main(String[] args) { ScheduledTaskExample ste = new ScheduledTaskExample(); ste.startScheduleTask(); } }
有什么办法,我可以ScheduledExecutorService考虑兼顾夏时制的事实,安排一个任务在每天的凌晨5点运行?
而且TimerTask对于这个还是更好ScheduledExecutorService?
TimerTask
与当前的Java SE 8版本一样,它具有出色的日期时间API,与java.time使用java.util.Calendarand相比,可以更轻松地完成这些计算 java.util.Date。
java.time
java.util.Calendarand
java.util.Date
ZonedDateTime now = ZonedDateTime.now(ZoneId.of("America/Los_Angeles")); ZonedDateTime nextRun = now.withHour(5).withMinute(0).withSecond(0); if(now.compareTo(nextRun) > 0) nextRun = nextRun.plusDays(1); Duration duration = Duration.between(now, nextRun); long initalDelay = duration.getSeconds(); ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); scheduler.scheduleAtFixedRate(new MyRunnableTask(), initalDelay, TimeUnit.DAYS.toSeconds(1), TimeUnit.SECONDS);
该initalDelay计算问调度延迟在执行TimeUnit.SECONDS。对于此用例,单位毫秒及以下的时差问题似乎可以忽略不计。但是你还是可以使用的duration.toMillis(),并TimeUnit.MILLISECONDS以毫秒为单位处理调度computaions。
initalDelay
TimeUnit.SECONDS
duration.toMillis()
TimeUnit.MILLISECONDS
computaions
而且TimerTask对此或ScheduledExecutorService更好吗?
NO: ScheduledExecutorService似乎比更好TimerTask。StackOverflow已经为你提供了答案。
TimerTask。StackOverflow
从@PaddyD,
你仍然遇到问题,如果希望它在正确的本地时间运行,则需要每年重新启动两次。scheduleAtFixedRate不会削减它,除非你对全年相同的UTC时间感到满意。
确实如此,@ PaddyD已经给出了解决方法(给他+1),我提供了一个Java8日期时间API和的工作示例ScheduledExecutorService。使用守护程序线程很危险
class MyTaskExecutor { ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1); MyTask myTask; volatile boolean isStopIssued; public MyTaskExecutor(MyTask myTask$) { myTask = myTask$; } public void startExecutionAt(int targetHour, int targetMin, int targetSec) { Runnable taskWrapper = new Runnable(){ @Override public void run() { myTask.execute(); startExecutionAt(targetHour, targetMin, targetSec); } }; long delay = computeNextDelay(targetHour, targetMin, targetSec); executorService.schedule(taskWrapper, delay, TimeUnit.SECONDS); } private long computeNextDelay(int targetHour, int targetMin, int targetSec) { LocalDateTime localNow = LocalDateTime.now(); ZoneId currentZone = ZoneId.systemDefault(); ZonedDateTime zonedNow = ZonedDateTime.of(localNow, currentZone); ZonedDateTime zonedNextTarget = zonedNow.withHour(targetHour).withMinute(targetMin).withSecond(targetSec); if(zonedNow.compareTo(zonedNextTarget) > 0) zonedNextTarget = zonedNextTarget.plusDays(1); Duration duration = Duration.between(zonedNow, zonedNextTarget); return duration.getSeconds(); } public void stop() { executorService.shutdown(); try { executorService.awaitTermination(1, TimeUnit.DAYS); } catch (InterruptedException ex) { Logger.getLogger(MyTaskExecutor.class.getName()).log(Level.SEVERE, null, ex); } } }
注意:
MyTask
execute
awaitTermination
shutdown