java在指定时间运行程序_Java 如何使用ScheduledExecutorService每天在特定时间运行某些任务?...

小编典典

与当前的Java SE 8版本一样,它具有出色的日期时间API,与java.time使用java.util.Calendarand相比,可以更轻松地完成这些计算 java.util.Date。

使用此新API的日期时间类,即LocalDateTime

使用ZonedDateTime类处理时区特定的计算,包括夏令时问题。你将在此处找到教程和示例。

现在作为使用你的用例计划任务的示例示例:

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。

而且TimerTask对此或ScheduledExecutorService更好吗?

NO: ScheduledExecutorService似乎比更好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。

在停止时ScheduledExecutorService,请始终awaitTermination在调用后使用shutdown:始终有可能你的任务被卡死/死锁,并且用户将永远等待。

我给Calender给出的上一个示例只是我提到的一个想法,避免了精确的时间计算和夏时制问题。根据@PaddyD的抱怨更新了解决方案

2020-03-18

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
`java.util.concurrent.ScheduledExecutorService`是Java提供的用于执行定时任务的接口。它可以通过线程池来管理任务的执行,并提供了更灵活和功能更强大的定时任务调度机制。下面是一个示例: ```java import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; public class TaskScheduler { public static void main(String[] args) { ScheduledExecutorService executor = Executors.newScheduledThreadPool(1); Runnable task = new Runnable() { @Override public void run() { // 在这里编写要定时执行的任务逻辑 System.out.println("任务执行中..."); } }; // 延迟1秒后执行任务,之后每隔1秒执行一次 executor.scheduleAtFixedRate(task, 1, 1, TimeUnit.SECONDS); // 等待一段时间后关闭线程池 try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } executor.shutdown(); } } ``` 在上面的示例中,我们使用`Executors.newScheduledThreadPool(int)`方法创建了一个大小为1的线程池,然后通过`executor.scheduleAtFixedRate(Runnable, initialDelay, period, TimeUnit)`方法来安排任务的执行。其中,`Runnable`表示要执行的任务,`initialDelay`表示延迟执行的时间,`period`表示任务的执行间隔,`TimeUnit.SECONDS`表示时间单位为秒。 在`Runnable`的`run()`方法中,编写了要定时执行的任务逻辑。在这个示例中,任务逻辑是简单地输出一条信息。 通过调用`executor.shutdown()`方法,可以手动关闭线程池,停止任务的执行。 需要注意的是,`scheduleAtFixedRate()`方法是按固定的时间间隔执行任务,不受任务执行时间的影响。如果任务执行时间超过了执行间隔,那么下一次任务将会立即开始,而不会等待上一次任务执行完毕。如果希望任务在上一次执行结束后再延迟一段时间再执行,可以使用`scheduleWithFixedDelay()`方法。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值