0

I'd like to create MIDI clock which works basically like a normal clock. It simply ticks and counts its ticks. Now I have read quite a few times that Thread.sleep() isn't accurate at all. So correcting it every every few cycles ensures that it is stable in the long term?

My Clock Class

public class Clock implements Runnable { long beatsPassed = 0; double bpm = 120; // default double beatLength; // default boolean running = false; Clock(int bpm) { this.bpm = bpm; this.beatLength = 60.0 / bpm; this.running = true; } public void run() { int beatLengthInMS = (int) (this.beatLength * 1000); long baseTime = System.currentTimeMillis(); // long corrected = 1; try { while (running) { // check delay every 9 beats // mod == 0 lets it the first time through which causes a negative timeout if (this.beatsPassed % 10 == 9) { // corrected = (System.currentTimeMillis() - baseTime) - (beatLengthInMS * 9); Thread.sleep(beatLengthInMS + ((System.currentTimeMillis() - baseTime) - (beatLengthInMS * 9))); baseTime = System.currentTimeMillis(); } else { Thread.sleep(beatLengthInMS); } this.beatsPassed++; // System.out.println(corrected); } } catch (InterruptedException e) { e.printStackTrace(); } } } 

Now I have measured actually quite steady times. It always adds about 6-9ms. Am I forgetting something fundamental or is my approach wrong? Also great would be if you could tell me a more performant way to this?

3
  • what exactly is your question? Commented Jul 1, 2014 at 8:07
  • If you're trying to produce a reliable clock based on sleep() then you're attacking the problem from the wrong direction. Use sleep(), but on each tick measure the time elapsed from your start time and update your clock according to the time passed. Commented Jul 1, 2014 at 8:08
  • My question is in the end of the post. If my approach is wrong or if there's a better? Because my results are contrary to what my research on this topic suggests. Commented Jul 1, 2014 at 8:09

1 Answer 1

1

The simplest approach (apart from using Timer, there are AFAIK two of them in the JDK) is a method

void sleepUntil(long absoluteTime) throw InterruptedException { while (true) { long now = System.currentTimeMillis(); if (now >= absoluteTime) break; Thread.sleep(absoluteTime - now); } } 

The loop is used because of spurious wakeups (which may never occur in practice, but better safe than sorry). The absoluteTime gets computed in advance (basically, you only look at the current time at the very beginning).

Sign up to request clarification or add additional context in comments.

3 Comments

This won't prevent sleep from sleeping too long. For something like sleep(1), one has to assume that it may sleep 5ms or even 10ms... (I don't have a solution either, except for some busy waiting with System.nanotime() ... millisecond-precise timing is hard to achieve in Java...)
@Marco13 if your computer is cpu bound and nothing is moving, then is some cases you may never be able to get the precision you want. Better just to print the time now.
@Marco13 AFAIK, there's nothing what could help in this direction. AFAIK assuming that 1. a core is free, 2. the time resolution is sufficient, 3. the system is not overloaded otherwise, it doesn't take longer. The nanotime busy waiting is a good idea.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.