18

Was using Java Timer, Then switched to ScheduledExecutorService, but my problem is not fixed. As Tasks scheduled before system time change (through ntpd) are not executed on delay specified. Have no logs for same as nothing happens :(.

using jre 1.6.0_26 64 bit in my target on 64 bit linux.

Update: ScheduledExecutorService works fine on Windows. Problem is only on 64 bit Linux based system running 64 bit JVM. It works fine on 64 bit linux running 32 bit JVM...strange. Have not found any reference of same on any blogs either.

IBM's JAVA SDK has same problem (ibm-java-sdk-7.0-0.0-x86_64-archive.bin).

I had filed defect against JDK 7139684,It was accepted but has been closed and marked duplicate of 6900441. Please vote for it , if you feel its worth to get it fixed... I have no idea why its not been fixed since more than couple of years

Here is sample code I used to test this issue:

package test;

import java.io.IOException;
import java.util.Date;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * @author yogesh
 *
 */
public class TimerCheck  implements Runnable {

    ScheduledExecutorService worker;


    public TimerCheck(ScheduledExecutorService worker) {
        super();
        this.worker = worker;
        this.worker.schedule(this, 1, TimeUnit.SECONDS);
    }

    private static void update() {
        System.out.println("TimerCheck.update() "+new Date(System.currentTimeMillis()));
    }

    @Override
    public void run() {
            update();
            worker.schedule(this, 1, TimeUnit.SECONDS);
    }

    /**
     * @param args
     */
    public static void main(String[] args) {
        ScheduledExecutorService worker = Executors.newScheduledThreadPool(1);
        new TimerCheck(worker);
    }

}
YoK
  • 14,329
  • 4
  • 49
  • 67
  • 1
    This sample code runs fine on my machine ubuntu 11.10 [32 bit], JVM 1.6.0_21 [32 bit]. Changing system clock does not affect execution. – Gopi Jan 28 '12 at 14:13
  • yes also checked it runs fine on 64 bit linux running 32 bit jvm :(. updated my question accordingly. – YoK Jan 28 '12 at 14:23
  • 1
    I'd just like to point out that specifying nanoseconds is meaningless in this case. Internally, the code changes to millis anyway. So `worker.schedule(this, 1000000000, TimeUnit.NANOSECONDS);` is identical to `worker.schedule(this, 1, TimeUnit.SECONDS);` – Chris Dolan Jan 28 '12 at 14:34
  • @ChrisDolan thanks. But I am focusing more on scheduling issue. – YoK Jan 28 '12 at 14:47
  • Can you set the system to GMT? GMT has no daylight savings time. – BillRobertson42 Feb 01 '12 at 06:08
  • @Bill its already set to UTC. But if you look at issue closely , you will see its not about timezone. – YoK Feb 01 '12 at 06:14
  • bounty is wasted due to lack of good answers :(. – YoK Feb 07 '12 at 11:00

2 Answers2

7

There is bug in JVM for overall scheduling during Sytem time changes backward, which also impacts very basic Object.wait & Thread.sleep methods. It becomes too risky to keep Java App running when system time switches back by even certain seconds. You never know what your Java App will end up to.

So we have decided to:

  • Write watch dog script (non Java :)) to check time change.
  • if time switches back by certain amount, shutdown and restart Java app.

Another possibility was to move to 32bit JVM, But we are using JNI and then native libraries used on target platform are not 32bit compatible. Also from our experience 32bit JVM limits our target to 1.6G heap, which is not at all sufficient for us.

I know ours is not most elegant solution, but untill JVM is fixed or some better solution is found, there doesn't seem to be any other way.

Edited: We are also considering 1st suggestion from Chris in addition to above solution:

  • Configure NTP to never have a big time jump. Only slew the time slowly. Only apply big time jumps manually during downtime.
YoK
  • 14,329
  • 4
  • 49
  • 67
  • Accepting this answer as workaround :(. While still waiting for proper solution. – YoK Feb 06 '12 at 08:42
  • I do not understand, how deeply does it affect JVM. From your aswer it seems like it is critical bug. For example, if I use Object.wait(1), and clocks moved back -- does it means that thread can be never waked up? – BegemoT Feb 06 '12 at 09:01
  • @BegemoT It doesn't mean that it will never wake up... But it will wake up after (time clock is moved back + 1). which is dangerous. And ya it only happening on 64 bit JVM on 64bit linux. – YoK Feb 06 '12 at 09:36
2

I worked against the same problem and have not found a solution. I looked at Quartz and all of the built-in JRE methods. The nanotime methods may use per-CPU monotonic clocks, but you risk big jumps if the threads are migrated to another CPU, I believe. My conclusions were the following:

  1. Configure NTP to never have a big time jump. Only slew the time slowly. Only apply big time jumps manually during downtime.
  2. Use multiple shorter timeouts, and require two timeouts to declare a remote machine dead. This won't help if you have just one system timing itself, but can help with multiple systems
  3. use a remote machine on purpose to send you periodic wakeups. If your own clock goes backward between wakeups, then you know all of your timers are going to fire late.

Basically, this is a huge pain but there are no silver bullets.

Chris Dolan
  • 8,905
  • 2
  • 35
  • 73
  • But did you eventually apply any of these solutions. For me these are impossible ones :). – YoK Jan 28 '12 at 14:49
  • 2
    @YoK, yes all three. My scenario was detecting if/when a primary service died so a backup could automatically take over. In all of the NTP configurations I've used the behavior has been: if the sync is within N minutes (say 2) then slowly slew the clock toward the correct time at a rate of X millis per minute (say 20). If the sync is more than N minutes off, then NTP issues a system log message warning of the error and goes passive. – Chris Dolan Jan 28 '12 at 14:57
  • Interesting ... will ask my NTP guys to look at it. – YoK Jan 28 '12 at 15:00
  • 1
    `nanoTime` should be consistent across CPUs - see http://stackoverflow.com/a/4588605/116639 – Tom Anderson Jan 30 '12 at 13:45
  • @TomAnderson cool, thanks for the update. My info was out of date. Are there any timer implementations that take advantage of this? – Chris Dolan Jan 30 '12 at 22:06
  • Not that i know of. It's merely an irrelevant fact! – Tom Anderson Jan 31 '12 at 00:50
  • @TomAnderson Don't think System.nanos help at all here... as even Thread.sleep() & Object's wait method has same problem. But I am really concerened as problem is only on 64bit JVM on 64bit linux. – YoK Jan 31 '12 at 05:42
  • @TomAnderson Also as you can see , I am using ScheduledExecutorService , ScheduledThreadPoolExecutor whic actually schedules based on nanoTime. – YoK Jan 31 '12 at 07:07
  • @TomAnderson unfortunately is not consistent across all platforms: "Hotspot only preserves monotonicity if the underlying OS does, and on linux, this requires clock_gettime, otherwise falling back to gettimeofday. System.nanoTime basically just makes the associated call and then returns scaled result." http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6458294 – Bruno Bossola Aug 30 '13 at 13:20