Java bug in sleep() when changing OS time : any workaround?

The bug that annoys me is the same than this ticket. Basically, if you change the OS clock to a date in the past, all the thread that were sleeping at the time of the change won't wake up.

The application I am developping is meant to be running 24/24, and we would like to be able to change the OS date without stopping it (for example, to switch from summer time to winter time). What happens for the moment is that when we change the date to the past, then some parts of the application just freeze. I observed that on multiple machine, on Windows XP and Linux 2.6.37, and with a recent JVM (1.6.0.22).

I tried many Java sleeping primitives, but they all have the same behavior :

  • Thread.sleep(long)
  • Thread.sleep(long, int)
  • Object.wait(long)
  • Object.wait(long, int)
  • Thread.join(long)
  • Thread.join(long, int)
  • LockSupport.parkNanos(long)
  • java.util.Timer
  • javax.swing.Timer

Now, I am out of idea to work around this problem. I think there is nothing I can do to prevent the sleeping threads to freeze. But I would like, at least, to warn the user when a dangerous system clock change is detected.

I came up with a monitoring thread that detects such changes :

    Thread t = new Thread(new Runnable() {
        @Override
        public void run() {
            long ms1 = System.currentTimeMillis();
            long ms2;
            while(true) {
                ms2 = ms1;
                ms1 = System.currentTimeMillis();
                if (ms1 < ms2) {
                    warnUserOfPotentialFreeze();
                }
                Thread.yield();
            }                    
        }
    });
    t.setName("clock monitor");
    t.setPriority(Thread.MIN_PRIORITY);
    t.setDaemon(true);
    t.start();

The problem is that this makes the application grow from 2% CPU usage to 15% when idle.

Do you have an idea to work around the original problem, or can you think of another way to monitor the appearance of thread freeze ?

Edit

Ingo suggested not to touch the system clock. I agree that it's generally not needed. The problem is that we don't control what our clients do with their computers (we plan to sell hundred of copies).

Worse : one of our machine exhibits this problem without any manual intervention. I guess the OS (Windows XP) regularly synchronizes its clock to the RTC clock, and this makes the OS clock go back in time naturally.

Epilogue

I found out that some statements in my question were wrong. There are actually two separate causes involved in my initial problem. Now, I can say two things for sure :

  1. On my machine only (archlinux with kernel 2.6.37 with an OpenJDK 64 bits 1.6.0_22), Thread.sleep, Object.wait, Thread.join, LockSupport.parkNanos have the same problem : they wake up only when the system clock reaches the "target" time of awakening. However, a simple sleep in my shell does not exhibit the problem.

  2. On all the machines I tested (included mine), java.util.Timer and java.swing.Timer have the same problem (they are blocked until the "target" time is reached).

So, what I've done is that I replaced all the java's Timer by a simpler implementation. This solves the problem for all the machines but mine (I just hope my machine is an exception more than a rule).

16
задан Kara 6 December 2013 в 02:19
поделиться