현재 Java SE 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에 더 낫습니까?
NO : ScheduledExecutorService
겉보기보다 나은 TimerTask
. StackOverflow는 이미 답을 가지고 있습니다 .
@PaddyD에서
올바른 현지 시간에 실행하려면 1 년에 두 번 다시 시작해야하는 문제가 있습니다. scheduleAtFixedRate는 일년 내내 동일한 UTC 시간에 만족하지 않는 한 그것을 자르지 않을 것입니다.
사실이고 @PaddyD가 이미 해결 방법 (+1)을 제공 했으므로 .NET과 함께 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의 불만에 따라 솔루션을 업데이트했습니다.