我正在写一个java代码,它可以根据给定的时区在每个午夜打印一些行。例如,如果我在IST时区运行我的应用程序,我想根据CET时区的午夜打印数据,那么我给出的时间转换为CET。为此,我使用了ScheduledExecutorService方法scheduleAtFixedRate(),根据时区计算延迟。
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.TimeZone;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class MainClass {
private ScheduledExecutorService executor = null;
private static final long TOLERANCE_DELAY_TO_MIDNIGHT = 120000L;
private static final int SCHEDULE_HOUR = 0;
private static final int SCHEDULE_MINUTE = 0;
final int ONE_DAY_MILLIS = 24 * 60 * 60 * 1000;
public MainClass() {
executor = Executors.newScheduledThreadPool(1);
final Schedule schedule = new Schedule();
this.executor.scheduleAtFixedRate(schedule, schedule.getScheduleDelay(), ONE_DAY_MILLIS, TimeUnit.MILLISECONDS);
}
private void printTime(final long delay) {
final long millis = delay % 1000;
final long second = (delay / 1000) % 60;
final long minute = (delay / (1000 * 60)) % 60;
final long hour = (delay / (1000 * 60 * 60)) % 24;
final String time = String.format("%02d:%02d:%02d.%d", hour, minute, second, millis);
System.out.println(time);
}
private long convertDateTimeZone(final long lngDate, final String fromTimeZone, final String toTimeZone) {
final TimeZone toTZ = TimeZone.getTimeZone(toTimeZone);
final Calendar toCal = Calendar.getInstance(toTZ);
final TimeZone fromTZ = TimeZone.getTimeZone(fromTimeZone);
final Calendar fromCal = Calendar.getInstance(fromTZ);
fromCal.setTimeInMillis(lngDate);
toCal.setTimeInMillis(fromCal.getTimeInMillis() + toTZ.getOffset(fromCal.getTimeInMillis())
- TimeZone.getDefault().getOffset(fromCal.getTimeInMillis()));
return toCal.getTimeInMillis();
}
private final class Schedule implements Runnable {
private Schedule() {
System.out.println("Scheduler started");
}
public void waitForMidnight() {
long shift = getShiftToMidnight();
System.out.println("shift to midnight = " + shift + "ms");
while (shift > 0) {
try {
Thread.sleep(shift);
} catch (final InterruptedException e) {
// ignore
}
shift = getShiftToMidnight();
}
}
//return the shift to midnight with tolerance value 2 minutes
private long getShiftToMidnight() {
final Calendar tomorrow = new GregorianCalendar();
tomorrow.add(Calendar.DATE, 1);
final Calendar tomorrow0000 = new GregorianCalendar(tomorrow.get(Calendar.YEAR),
tomorrow.get(Calendar.MONTH), tomorrow.get(Calendar.DATE), SCHEDULE_HOUR, SCHEDULE_MINUTE);
final long nowTime = convertDateTimeZone(System.currentTimeMillis(), "IST", "CET");
final long delay = tomorrow0000.getTimeInMillis() - nowTime;
if (delay > TOLERANCE_DELAY_TO_MIDNIGHT) {
return 0L;
}
return delay;
}
private final long getScheduleDelay() {
System.out.println("running");
final Calendar today = new GregorianCalendar();
final Calendar todayMidnight = new GregorianCalendar(today.get(Calendar.YEAR), today.get(Calendar.MONTH),
today.get(Calendar.DATE), 24, 0, 0);
final long currentTime = convertDateTimeZone(System.currentTimeMillis(), "IST", "CET");
long delay = todayMidnight.getTimeInMillis() - currentTime;
printTime(delay);
delay = (delay < 0) ? 0 : delay;
return delay;
}
@Override
public void run() {
System.out.println("hit");
waitForMidnight();
System.out.println("midnight);
}
}
public static void main(final String[] args) {
final MainClass scheculer = new MainClass();
System.out.println("exit from main");
}
}
问题是applicaiton在等待调用run方法之前退出main()。延迟是正确计算的,我没有得到它为什么会发生这样的情况。
你失去了executor.scheduleAtFixedRate的结果,它返回一个Future。你应该从你的main中调用future.get来停止退出,但是注意这个get()调用不会返回来允许正常退出,直到你整理出什么时候在其他地方取消你的计划任务。