Обнаружение разрывов в часах Windows в Java

Просмотрите приведенный ниже код, который обнаруживает нарушения работы системных часов Windows в долго работающих программах.

/*
 * Created on Apr 16, 2015
 *
 * The purpose of this class is to periodically check to see if the time of the Thread.sleep() agrees with the system clock.
 * If it does not, we need to send an interrupt to the ***.
 * 
 * This is because after Windows 7, Thread.sleep does not count down in S3 or S4 mode.
 * http://stackoverflow.com/questions/29394222/java-thread-sleep-on-windows-10-stops-in-s3-sleep-status
 * 
 */
package com.sengsational.clockchecker;

import java.io.IOException;
import java.net.Socket;
import java.util.Date;

public class ClockChecker implements Runnable{

    private static boolean runFlag = false;
    private static Thread runningThread;
    private static ClockChecker singleton;
    private static Thread runThread;
    private static boolean mSimulateClockProblem;
    public static long pollIntervalMs = 15000;
    public static final int ACCURACY_MS = 1000;
    
    public static ClockChecker getInstance(){
        if (singleton == null) {
            singleton = new ClockChecker();
        }
        return singleton;
    }
    
    private ClockChecker(){
        runningThread = new Thread(this);
        runningThread.start();
        try {Thread.sleep(100);} catch (Throwable t){};
    }    

    @Override
    public void run() {
        if (isRunning()) {
            System.out.println(new Date() + " ERROR: ClockChecker should only have one run thread.");
            return;
        } else {
            System.out.println(new Date() + " ClockChecker run() is starting.");
            setRunning(true);
        }
        long wakePoint = 0;
        long msAccuracy = 0;
        ClockChecker.runThread = Thread.currentThread();
        while (isRunning()) {
            try {
                wakePoint = ((new Date().getTime() + pollIntervalMs));
                Thread.sleep(pollIntervalMs); // Blocks
                if(ClockChecker.mSimulateClockProblem && Math.random() < 0.2d){
                    wakePoint = wakePoint - 2000;
                   System.out.println(new Date() + " Simulating a clock problem.");
                }
                msAccuracy = Math.abs(new Date().getTime() - wakePoint);
                if (msAccuracy > ACCURACY_MS) {
                    System.out.println(new Date() + " ClockChecker has detected a clock accuracy issue of " + msAccuracy + "ms.");
                    System.out.println(new Date() + " >> Here is where you alert your waiting tasks that depend upon wall-clock accuacy <<");
                }
            } catch (InterruptedException e) {
                System.out.println(new Date() + " ClockChecker run() has been interrupted.");
                setRunning(false);
            }
        } 
        System.out.println(new Date() + " ClockChecker run() is ending.");
        setRunning(false);
    }
    
    public synchronized boolean isRunning(){
        return runFlag;
    }
    
    public synchronized void setRunning(boolean running){
        ClockChecker.runFlag = running;
    }
    
    private static void setSimulateClockProblem(boolean simulateClockProblem) {
        mSimulateClockProblem = simulateClockProblem;
    }

    public static void shutDown() {
        runThread.interrupt();
        try {Thread.sleep(100);} catch (Throwable t){}
    }

    public static void main(String[] args) throws InterruptedException {
        
        System.out.println("nMAIN: Simulate starting the main app.");
        ClockChecker.getInstance();
        ClockChecker.setSimulateClockProblem(false);  // Set to true on Windows 7 to have a roughly 40% chance of simulating a clock discontinuity.
        System.out.println("nMAIN: Now we have a ClockChecker object. Put Win10 machine into S3 sleep mode NOW!" +
                           "n      (you have fewer than 30 seconds to do so).  Leave in S3 for 1 or more minutes.");
        Thread.sleep(30 * 1000);
        System.out.println("nMAIN: Examine the above messages (if any) about clock accuracy after S3 sleep.");
        System.out.println("nMAIN: We will now shutdown.");
        ClockChecker.shutDown();  
        System.out.println(new Date() + " ClockChecker main() ending.");
    }
}

В качестве фона при запуске в версиях Windows 8 и 10, но не в более ранних версиях, Java Thread.sleep (X) будет спать в течение X миллисекунд, плюс количество миллисекунд, в течение которых машина находилась в спящем режиме S3 или S4. Другими словами, когда Windows снова проснется, она будет действовать так, как будто время не прошло, поэтому любую программу, требующую привязки к времени настенных часов, потребуется исправить. Я хотел бы понять, есть ли какие-либо идеи по улучшению вышеуказанного решения этой проблемы.

1 ответ
1

Добро пожаловать на codereview.se и спасибо, что поделились своим кодом.

Вот что я думаю об этом. Учтите, что это мой личный взгляд в теме.

Не используйте шаблон Java Singelton.

В образец Сингелтона просто другое название для глобальная переменная, который мы считаем вредным и плохим с самого начала программирования.

Кроме того, шаблон не так просто реализовать правильно, и поэтому даже ваш подход не является потокобезопасным.

Для получения дополнительной информации о статическом доступе образец Сингелтона требуется прочитать: https://williamdurand.fr/2013/07/30/from-stupid-to-solid-code/

Не работайте в конструкторах

Конструкторы должны назначать только его параметры к переменные-члены. Любая проверка параметров должна производиться в первую очередь перед вызовом конструктора.

Также не создавайте экземпляры других классов внутри конструктора, так как это еще один плохой случай статический доступ что затрудняет расширение, повторное использование и тестирование вашего кода.

В частности, конструктор не должен передавать текущий объект любому другому методу, поскольку объект еще не полностью настроен, пока конструктор не завершит работу.

Не иметь классов верхнего уровня, реализующих простые (функциональные) интерфейсы.

Эта привычка исключает возможность разделения клей код из фактического бизнес-кода.

    Добавить комментарий

    Ваш адрес email не будет опубликован. Обязательные поля помечены *