【问题标题】:Applicaiton exiting from main not stopping for runnable run从 main 退出的应用程序没有停止以进行可运行的运行
【发布时间】:2020-06-15 11:48:12
【问题描述】:

我正在编写一个 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");
    }

}

问题是应用程序在等待 run 方法调用之前退出 main()。延迟计算正确,我不明白为什么会这样。

【问题讨论】:

  • 我建议你不要使用TimeZoneCalendarGregorianCalendar。这些课程设计不佳且早已过时。而是使用来自java.time, the modern Java date and time APIZoneIdZonedDateTime。也可以代替this.executor.scheduleAtFixedRate(schedule, schedule.getScheduleDelay(), ONE_DAY_MILLIS, TimeUnit.MILLISECONDS); 使用this.executor.scheduleAtFixedRate(schedule, schedule.getScheduleDelay(), 1, TimeUnit.DAYS);

标签: java timezone runnable scheduledexecutorservice


【解决方案1】:

您正在丢失返回 Future 的 executor.scheduleAtFixedRate 结果。您应该从 main 调用 future.get 以停止退出,但请注意,此 get() 调用不会返回以允许正常退出,直到您确定何时在其他地方取消您的计划任务。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-04-14
    • 1970-01-01
    • 2011-08-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-05
    相关资源
    最近更新 更多