Server Help

Trash Talk - Java Timer/Threads

CypherJF - Wed Jun 22, 2005 10:54 pm
Post subject: Java Timer/Threads
http://cypherjf.sscentral.com/

Quote:
06.22.2005 - Java, not as good as it should be?

Ive been trying to get my Java groove on, programming a bunch of prototypes - testing this and that. One of the applications was a Calendar that would highlight the current day - that should run 24/7 etc. However, after some testing I noticed a huge issue with Java that I would consider a "bug". I've been e-mailing my Java professor over the past few days trying to come up w/ a solution but here it is in short.

If you have a Thread or Runnable instance, including Timer, and you set your system time backwards (say by a day) - the application completely stops. If you set it forward, the thread will try and catch up to the system time - so it executes the appropriate event several rapid times (essentially going bezerk). I should mention here that .NET appears not to have this issue - but that is because I think it uses the GetTickCount() - or the API to determine how long the system has been running.

I'm not the only one who had this issue but it's been in existence since Java 1.3 from what I gather from this bug report:
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4290274

A sample block of code and it's run of when I set the system time forward:
Code: Show/Hide
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
public void run() {
System.out.println("---TIME---");
System.out.println("TIME:" + new Date());
System.out.println("//---TIME---");
} }, 10000, 10000);

Quote:
---TIME---
TIME:Tue Jun 21 14:08:33 EDT 2005
//---TIME---
---TIME---
TIME:Thu Jun 23 14:08:35 EDT 2005
//---TIME---
---TIME---
TIME:Thu Jun 23 14:08:35 EDT 2005
//---TIME---
---TIME---
TIME:Thu Jun 23 14:08:35 EDT 2005
//---TIME---

(same repeating - very very rapidly scrolling text - about 40 same entries)

//---TIME---
TIME:Thu Jun 23 14:08:36 EDT 2005
//---TIME---
---TIME---

(same repeating - very very rapidly scrolling text)

---TIME---
TIME:Thu Jun 23 14:08:37 EDT 2005
//---TIME---

(same repeating - very very rapidly scrolling text)

---TIME---
TIME:Thu Jun 23 14:08:38 EDT 2005
//---TIME---

(same repeating - very very rapidly scrolling text)

---TIME---
TIME:Thu Jun 23 14:08:38 EDT 2005
//---TIME---
---TIME---
TIME:Thu Jun 23 14:08:39 EDT 2005
//---TIME---

(same repeating - very very rapidly scrolling text)


Reference URLS:
http://java.sun.com/j2se/1.5.0/docs/api/javax/swing/Timer.html
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4290274
Cyan~Fire - Wed Jun 22, 2005 11:39 pm
Post subject:
Eh, Java sucks. Hey, I'm going to hijack your topic. Anybody know of an easy way to do function timing in Java?
Cerium - Thu Jun 23, 2005 3:32 am
Post subject:
Well, the Timer class doesnt do anything that cant be duplicated. Since a fix may be a while off (and would no doubt break backwards comatibility with previous versions of java), youre left writing a custom Timer class.

You could copy/paste most of the code directly from Timer, but youd need to change the sched code. The bug page you posted already has a fairly good example of a workaround for the time being set backwards, but it needs to be updated.

wait time = ( Math.min( <calculated wait time>, <length between most frequent task executions>) );

That way at most, it would only wait the amount of time specified by the task that executes the most often.

Ignoring forward skips may be a bit harder, since a timer task could end up making the timer sleep for a very long time. Perhaps change the timer body it knows how long each iteration takes. Then, only sleep for a maximum of say 10 seconds each time it sleeps. If the 'iteraiton' time is longer than 10 seconds, you can assume the clock was set forward, and handling it accordingly.
The downside, is this may make some timers off by a few milliseconds, but hell, the Timer class shouldnt be used when you need tasks to be that accurate, anyway.

---

Cyan, I dunno if this is the best, or easiest, but this is what I use:

Code: Show/Hide

      int            intChecks      = 50;
      int            intIterations   = 25000;
      long[]         lngDuration      = new long[intChecks];
      double[]      dblRuntime      = new double[intChecks];
      DecimalFormat   objFormat      = new DecimalFormat("#.#####");

      // Setup variables and stuff here

      for(int intUpper = 0; intUpper < intChecks; ++intUpper)
      {
         long lngStart = System.currentTimeMillis();

         for(int intCounter = 0; intCounter < intIterations; ++intCounter)
         {
            // Code to time goes here
         }

         lngDuration[intUpper] = System.currentTimeMillis() - lngStart;
         dblRuntime[intUpper] = (double) lngDuration[intUpper] / (double) intIterations;

         System.out.println("Duration: " + lngDuration[intUpper]);
         System.out.println("Runtime:  " + objFormat.format(dblRuntime[intUpper]));
      }

      long   lngTotal = 0;
      double   dblTotal = 0;
      for(int intCounter = 0; intCounter < intChecks; ++intCounter)
      {
         lngTotal += lngDuration[intCounter];
         dblTotal += dblRuntime[intCounter];
      }


      System.out.println("-----");
      System.out.println();
      System.out.println("Avg Duration: " + (lngTotal / intChecks));
      System.out.println("Avg Runtime:  " + objFormat.format((dblTotal / intChecks)));


It gets more and more accurate the longer its allowed to run, but if anyone knows an even better way, lemme know =)
Dr Brain - Thu Jun 23, 2005 7:21 am
Post subject:
Can't you just make yourself a Thread that has a sleep(10000); at the end of run()?
Cerium - Thu Jun 23, 2005 8:18 am
Post subject:
Would work fine if your app only requires the one task. But when you start adding lots of tasks that need to be done at different intervals, you start running into problems.
Bak - Thu Jun 23, 2005 10:07 am
Post subject:
perhaps a cool linkedlist with sleep times and methods to run when the time runs out... so like If I wanted to run something in 10 seconds and something else in 7 seconds it would look like:


(7, func1) -> (3, func2) ->

then after func1 runs it could reschedule itself to run 10 seconds later which would be inserted into the linkedlist as:

(3, func2) -> (7, func1) ->
CypherJF - Thu Jun 23, 2005 1:01 pm
Post subject:
No one is understanding what I am saying.

If you even have a "Thread", or a class that implements Runnable, it fails to work. Example:

Code: Show/Hide
import java.util.Date;

public class TestThread implements Runnable {
   private Thread thisThread;
   
   public static void main(String[] args) {
      TestThread tt = new TestThread();
      
      System.out.println("A test of a Thread that should sleep for 1 second.");
      tt.run();
   }
   
   public TestThread() {
      thisThread = new Thread(this, "Test");
      //thisThread.start();
   }
   
   public void run() {
      while (true) {
         System.out.println("" + new Date());
         try {
            Thread.sleep(1000);
         } catch (InterruptedException e) {
            e.printStackTrace();
         }
      }
   }
}


Quote:
A test of a Thread that should sleep for 1 second.
Thu Jun 23 12:56:41 EDT 2005
Thu Jun 23 12:56:42 EDT 2005
Thu Jun 23 12:56:43 EDT 2005
Thu Jun 23 12:56:44 EDT 2005
Thu Jun 23 12:56:45 EDT 2005
Thu Jun 23 12:56:46 EDT 2005


When I switch my system clock to say June 21rst, it stops - because it uses the system time to calculate when it should notify the thread, etc.

edit:
I reset my clock back to today, and ran it then set it forward and backwards but it didn't appear to break anything. Grr. :shrug:
Cerium - Thu Jun 23, 2005 1:26 pm
Post subject:
Well, sleep is a native function, so I would hope that its a bit more safe. But even still, it could be a race condition of sorts, in that when you were changing the time, you were getting lucky and the time was getting updated during the System.out.println call...

And bak, what you described is basicly how Timer works. Theres a list of objects to run. After an object is run, it iterates through the list and finds the object that should be run next. It uses System.currentTimeMillis() - (next runtime) to determine how far off the execution is, then sleeps.
CypherJF - Thu Jun 23, 2005 2:31 pm
Post subject:
I don't trust the exact Date print, but eh for all I care I could have just had an incremental integer going. Its just a way to see that it was doing it's thing.

But I still find it funky the above Runnable code didn't work but then it now works. :shrug:. And it didn't work prior either because I had writen my own timer to throw "CypherTimerEvent" icon_smile.gif. But the thread wasn't executing right. :shrug:
Dr Brain - Thu Jun 23, 2005 5:14 pm
Post subject:
Code: Show/Hide

import java.util.*;

public class TimerTest {
   public static void main(String[] args) {
      BrainsTimer testTimer = new BrainsTimer(1000, 1000) {
         public boolean timerEventFired() {
            System.out.println("---TIME---");
            System.out.println("TIME:" + new Date());
            System.out.println("//---TIME---");
            return true;
         }
      };
   }
}

abstract class BrainsTimer extends Thread {
   private long delay;
   private long period;

   public BrainsTimer(long delay, long period) {
      this.delay = delay;
      this.period = period;
      this.start();
   }

   //returns true if it wishes to continue being scheduled
   public abstract boolean timerEventFired();

   public void run() {
      try {
         Thread.sleep(delay);
         while (timerEventFired()) {
            Thread.sleep(period);
         }
      }
      catch (InterruptedException e) {
         e.printStackTrace();
      }
   }
}

All times are -5 GMT
View topic
Powered by phpBB 2.0 .0.11 © 2001 phpBB Group