2

How can I make a loop that executes about 10000 times per second with regular(!) intervals?

(duplicate of continuous data acquisition from parallel port in Java but that one's hard-to-find and isn't answered and very old)

I looked at Thread.sleep(long millis) and Thread.sleep(long millis, int nanos) but Oracle's J2SE virtual machine on Windows always sleeps 1 millesecond longer than what I specify. Besides, the nanos field seems to be rounded up to the next whole millisecond (verified, this is hardcoded in the source code of Thread.java).

Experimantal results:

  • Thread.sleep(0) sleeps not (100% cpu)
  • Thread.sleep(1) sleeps 1.95ms on average
  • Thread.sleep(2) sleeps 2.95ms on average
  • Thread.sleep(0, 0) sleeps not (100% cpu)
  • Thread.sleep(0, 1) sleeps 1.95ms on average

So how can I make a loop that iterates more than even 500 times per second with regular intervals?

Edit: I loosen the 'regular' requirement a little. It is not a big problem if one delay is like 4 times shorter than another delay (ie. jitter is not a problem), as long as the longest delay is deterministic and below 0.1ms. (which isn't the case with ScheduledExecutorService)

Community
  • 1
  • 1
Mark Jeronimus
  • 9,278
  • 3
  • 37
  • 50
  • For context, why do you need to do this? – Oliver Charlesworth Jan 06 '13 at 13:17
  • _loop that executes about 10000 times per second with regular(!) intervals_ why you want to such a number of loops per second??!! – Pradeep Simha Jan 06 '13 at 13:18
  • 5
    If you need hard guarantees, you need to consider the OS as well as your code. Telling the thread to sleep 1ms merely means that (1) it goes to sleep and (2) it tells its boss (the JVM or the OS, depending on the threading implementation) not to wake it up before 1ms has passed. However, if your OS thinks there is more important stuff to do, your thread *will* sleep longer than that. – us2012 Jan 06 '13 at 13:25
  • Zom-B what you want is a REALTIME application java is not very good for this. – Nahum Jan 06 '13 at 13:26
  • I want this for data aquisition of unbuffered events. An application can't be REALTIME if the OS isn't a REAL-TIME OS. (Windows isn't) – Mark Jeronimus Jan 06 '13 at 13:58
  • @Zom-B Other similar questions mention the use of `Multimedia timers`, look them up on MSDN. However, if your events are unbuffered and you can't miss a single one, this still won't work. Are these events generated by hardware? If so, try using an interrupt for them and let the interrupt handler write them into a buffer. (I'm pretty sure you can do that on Windows as well, although I only have some experience on linux with this.) – us2012 Jan 06 '13 at 14:04
  • The data I wish to acquire is not sample-based. I want to record changes to the input only, but some changes *do* occur with 0.01ms interval. When I make a loop without delay and accept 100% cpu it works fine. When i use a 1ms delay I miss about 50% of the changes. – Mark Jeronimus Jan 06 '13 at 14:07
  • btw, I've written interrupt routines in linux and dos but in windows it is afaik impossible. The events are software-generated. – Mark Jeronimus Jan 06 '13 at 14:11
  • If they are software-generated, why can you not buffer them? – us2012 Jan 06 '13 at 14:12
  • Software-generated is in this case OS-generated. And I'm not big on writing device drivers. – Mark Jeronimus Jan 06 '13 at 14:13
  • Unfortunately though, that is the easiest solution, and most likely the only one on your system. Your requirements ("deterministic delay below 0.1ms") cannot be fulfilled by your platform. – us2012 Jan 06 '13 at 14:33

3 Answers3

2

I believe you're looking for ScheduledExecutorService (see the usage example).

Specifically

scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit)

Creates and executes a periodic action that becomes enabled first after the given initial delay, and subsequently with the given period; that is executions will commence after initialDelay then initialDelay+period, then initialDelay + 2 * period, and so on.

Using TimeUnit.MICROSECONDS.

Mike
  • 2,434
  • 1
  • 16
  • 19
  • I tried it and concluded it just uses Thread.sleep() internally, and after every delay it catches up on missed calls (so it isn't regular) – Mark Jeronimus Jan 06 '13 at 13:50
  • 1
    @Zom-B see my comment to your question above. You need everything in between your application and the OS core to respect your threading needs, in the case of Java that includes tha JVM and the OS scheduler at least. This is *not* an easy task at all, as the scheduler granularity of your standard out-of-the-box OS is about 10ms. You need something like 1ms for requests to occur every 2ms and other processes to run as well, AND your OS and hardware has to be very frugal with interrupts and similar things. Your problem requires more work than finding a nice Java lib that does it for you. – us2012 Jan 06 '13 at 13:55
0

When timing loops in Java, never ever ever ever ever use Thread.sleep(long), as this is a very imprecise method of looping. Try using javax.swing.Timer instead. A link is here. http://docs.oracle.com/javase/tutorial/uiswing/misc/timer.html

imulsion
  • 8,820
  • 20
  • 54
  • 84
0

If you are ok pegging a core at 100%, you can get fairly evenly distributed events in a sub-microsecond spacing using this. Of course if you hit the max throughput rate using this, then replacing the System.nanoTime() with a less costly timing call would be desirable.

long nanosBetweenMessages = getSpacing();
long lastSendTime = 0l;
while (true) {
   final long curTimeNanos = System.nanoTime();
   if (curTimeNanos - lastSendTime < nanosBetweenMessages) {
       continue;
   }
   lastSendTime = curTimeNanos;
   sendEvent();
   if (done()) {
       break;
   }
}

I just noticed your 10k/sec requirement... I'm currently using this with a decent amount of calculation in the sendEvent() method, pushing at a max rate of about 20k/second.

  • Good call. I forgot to put that requirement in my post. What I'm making is a background service that shouldn't be noticeable in any way, so 100% cpu is out of the question. In the mean time, I already implemented a JNA function that buffers the inputs so java can receive them at it's own pace. – Mark Jeronimus Jul 25 '13 at 15:16