現在のjavaSE 8リリースと同様に、java.time
この種の計算を備えた優れた日時APIは、java.util.Calendar
とを使用する代わりに、より簡単に実行できます 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
を利用することはできます。
また、TimerTaskはこれまたはScheduledExecutorServiceに適していますか?
いいえ: ScheduledExecutorService
一見より良いですTimerTask
。StackOverflowにはすでに答えがあります。
@PaddyDから、
適切な現地時間で実行したい場合は、これを年に2回再起動する必要があるという問題がまだあります。年間を通して同じUTC時間に満足しない限り、scheduleAtFixedRateはそれをカットしません。
それは真実であり、@ 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の苦情に従ってソリューションを更新しました