java - 从主程序退出的应用程序未停止运行

标签 java timezone runnable scheduledexecutorservice

我正在编写一个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()。延迟是正确计算的,我没有得到它为什么会这样发生。

最佳答案

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

关于java - 从主程序退出的应用程序未停止运行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62387563/

相关文章:

java - setOnClickListener 在简单的 Android 中不起作用

java - NetBeans 平台 : Toolbar and Actions

c# - 如果时区规则更改,以前保存的日期时间的 UTC 到本地时间转换

android - 7 个线程/runnable 是不是太多了?是什么让我的应用程序变慢了?

java - 如何让图像随机移动?

java - 使 JDBC 插入查询更快

Java Android 相机

ios - iPhone-XMPP离线消息时间戳导致聊天列表困惑

java - Java 8 和 Java 7 中的时区差异

Java extends Thread 不起作用,但 implements Runnable 起作用。我不明白为什么?