เช่นเดียวกับการเปิดตัว java SE 8 ในปัจจุบันพร้อมด้วย API วันเวลาที่ยอดเยี่ยมพร้อมjava.time
การคำนวณประเภทนี้สามารถทำได้ง่ายขึ้นแทนที่จะใช้ 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
StackOverflow มีคำตอบให้คุณแล้วTimerTask
จาก @PaddyD,
คุณยังคงมีปัญหาอยู่โดยที่คุณต้องรีสตาร์ทปีละสองครั้งหากคุณต้องการให้มันทำงานในเวลาท้องถิ่นที่ถูกต้อง ScheduleAtFixedRate จะไม่ตัดออกเว้นแต่คุณจะพอใจกับเวลา UTC เดียวกันตลอดทั้งปี
ในฐานะที่มันเป็นความจริงและ @PaddyD แล้วได้รับการแก้ปัญหา (+1 กับเขา) ผมกำลังให้เป็นตัวอย่างการทำงานร่วมกับ Java8 ScheduledExecutorService
วันเวลากับ การใช้ daemon thread เป็นสิ่งที่อันตราย
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
: มีความเป็นไปได้ที่งานของคุณจะติดขัด / หยุดชะงักและผู้ใช้จะรอตลอดไป
ตัวอย่างก่อนหน้านี้ที่ฉันให้กับปฏิทินเป็นเพียงความคิดที่ฉันได้กล่าวถึงฉันหลีกเลี่ยงปัญหาการคำนวณเวลาที่แน่นอนและการประหยัดเวลาตามฤดูกาล อัปเดตวิธีแก้ปัญหาตามคำร้องเรียนของ @PaddyD