-1

I am looking for some Timer() that runs a process for a given time, then waits some time , then repeats ...

The Timer.scheduleAtFixedRate() does not wait-Stop- for sometime. enter image description here

  • Could we please get some insight how you tried to solve your problem so far? – Marco Forberg Jul 01 '21 at 11:48
  • I didn't try because I knew there must be a typical way to do it.. –  Jul 01 '21 at 11:50
  • this might look stupid , but does it work ? I didn't test it because it's a long way ahead to run the project : `timer.scheduleAtFixedRate(new TimerTask(){ @Override public void run(){ Run(); timer.schedule(new TimerTask(){ @Override public void run(){ Stop(); } } ,50); } },0,200);` –  Jul 01 '21 at 11:59
  • By the way, the `Timer`/`TimerTask` classes have been supplanted by the Executors framework, as noted in their Javadoc. – Basil Bourque Jul 01 '21 at 16:48

1 Answers1

1

Computers aren't that accurate.

Thus, what you want is not clear (or if you prefer, not possible).

'wait 50msec' is not quite possible but something close to it is. However, 'run for 200msec', that is weird and not really possible. Do you perhaps mean: "I have some task and it takes about 200 msec"? Or do you perhaps mean: I have a task that is very fast. I want to do it continuously with no interruptions for 200 msec and then stop doing it for a while? That's not possible either, but something close to it is possible. Or did you mean: I have a long-running job that takes many seconds. I would like the job to run for 200msec, then freeze in its tracks, then 50 msec later, unfreeze it and let it continue chugging, and so on and so forth? That is bizarre, and not really possible.

'wait 50msec' in java or any other language on a modern OS is a hint. That will wait about 50msec. Not quite exactly 50msec. You need to deal with the fact that you get 'drift'. If you ask a computer to wait 50msec a few million times, you'll be nowhere near the time you'd have expected that to take. It'll have been 51msec a few times, maybe a 52msec here and there.

Here are the things you can do:

  • Instead of 'wait 50msec', you can also 'wait until X'. This is the right answer if you want to build a little GUI widget that shows a stopwatch: If you write that as, in pseudocode:
int time = 0;
while (true) {
    String formattedTime = formatTime(time);
    renderToWidget(formattedTime);
    time++;
    Thread.sleep(1000L); // wait one second
}

The above is completely wrong. As the stopwatch runs it'll drift away further and further. Instead, you should do something like this:

private static final long NANOS_IN_SECOND = 1000000000;
...


long start = System.nanoTime();
while (true) {
    long secondsPassed = (System.nanoTime() - start) / NANOS_IN_SECOND;
    String formattedTime = formatTime(secondsPassed);
    renderToWidget(formattedTime);
    Thread.sleep(500L); // why not update a little more often?
}

Another important idea is instead of 'wait 50 msec', many problems are better served by the idea of 'calculate the next wakeup time then wait however long it will be until that moment has arrived'. For example, if you want to write a 'framerate limiter' for a game so that the game does not bother rendering frames at a rate higher than 60fps, you'd do something like this:

private static final long NANOS_PER_FRAME = 1000000000 / 60; // 60 fps
...


long now = System.nanoTime();
long done = now + NANOS_PER_FRAME;

Frame frame = renderFrame();
screen.show(frame);
long toWait = System.nanoTime() - done;
if (toWait > 0) waitNanos(toWait);

In other words, instead of 'wait a set amount of time', this model says that every x milliseconds, an event occurs, which inherently means that this event has 1/x time maximum to run, and you write the loop to wait however long it needs to wait to 'fill up the remainder' if the event runs faster than that.

Which one is appropriate for you? No idea - your question didn't specify.

  • Interrupt a long running process

Java doesn't have a 'just freeze the thread out' feature. Instead, the code in the thread itself needs to check in from time to time and then you can freeze there. For example, if you have a bitcoin miner that needs to stop every roughly 200msec, that can work, as long as the code that needs to wait explicitly 'checks in' (calls some method under the timing framework's control) very often. That code can use the above techniques to check if freezing should be done, and if it should be, just use Thread.sleep(time) to wait however long your calculations state you should wait. If the code that runs in the thread isn't written by you and can't be changed by you, a java thread is not the tool for the job.

NB: Note that System.currentTimeMillis() is a tricky one. That value can drift and even go backwards if the user messes with the system clock. Most computers these days run time daemons that keep the clock in sync with some time server, but this too means that drift can occur. Thus, using System.cTM to measure passed time is a bad idea.

rzwitserloot
  • 85,357
  • 5
  • 51
  • 72