How to suspend a java thread for a small period of time, like 100 nanoseconds?
Asked Answered
F

7

37

I know Thread.sleep() can make a java thread suspend for a while, like certain milliseconds and certain nanoseconds. But the problem is the invocation of this function also causes overhead.

For example, if I want a thread to suspend for 100 nanoseconds, and I call Thread.sleep(0, 100). The whole cost for this process is invocation_cost + 100 nanosceonds, which may be much larger the what I want. How could I avoid this problem, and achieve my purpose?

The reason I need this is that I want to do simulation offline. I profiled the execution time of a task; Now I want to simulate this execution time by suspending a thread in the same time period.

Thanks!

Fibrinolysis answered 16/7, 2012 at 5:35 Comment(6)
Do you have a particular reason why you want to do this? If so, it may be solved a different way...Cupriferous
This is an unusual requirement. It sounds like you need a back off strategy or similar.Alkalinity
@gt FYI, it's annoying to post questions on stackoverflow and have replies that question you rather than provide an answer. There are many valid reasons for wanting to do this that have arisen in projects over the years. One practical reason would be for maintaining realtime behavior in applications that record audio from hardware, since the hardware may behave inconsistently, or you may be simulating hardware behavior for testing purposes .Fado
@Fado Thanks for providing an example. I don't doubt there are good reasons for doing this. I find the best answers will often take into account the context in which the question has been asked. Look at Peter Lawrey's answer below to see an example of this, once the OP provided a some background info.Cupriferous
There are cases where very short sleeps are useful, such as when talking to hardware that can only take messages at a rate slower than the controller code can deliver them to it (but still well more than a thousand messages a second). This question (and its answers) is useful in those circumstances.Perjury
By the way, as of Java 19, you can pass a java.time.Duration to Thread.sleep.Unni
O
32

The granularity of sleeps is generally bound by the thread scheduler's interrupt period. In Linux, this interrupt period is generally 1ms in recent kernels. In Windows, the scheduler's interrupt period is normally around 10 or 15 milliseconds

If I have to halt threads for periods less than this, I normally use a busy wait

EDIT: I suspect you'll get best results on jrockit + solaris. The numbers on a windows box are terrible.

@Test
public void testWait(){
    final long INTERVAL = 100;
    long start = System.nanoTime();
    long end=0;
    do{
        end = System.nanoTime();
    }while(start + INTERVAL >= end);
    System.out.println(end - start);
}
Ogburn answered 16/7, 2012 at 5:40 Comment(8)
Thanks. If use a busy wait, how could you control the waiting length? like 100 nanoseconds.Fibrinolysis
Should the >= be <= ?Fibrinolysis
Do you realize that this loop eats 100% of a single CPU core? This is an anti-pattern to wait/sleep.Diluent
You should probably make clear in this answer that it does thrash the CPU.Rearrange
You'd have to search a lot for a single core CPU these days. It obviously does hold up a CPU for a few nanoseconds. Please comment if you have an alternative that solves the question askedOgburn
@Diluent But if the the thread is supposed to sleep only a microseconds or you can not bare any latency there might just not be a way around it. It's ugly but not avoidableCodfish
There is a way to improve this situation in 2020. You can call java.lang.Thread.onSpinWait() within the loop, which indicates to the CPU that you are in fact busy-waiting. This at least theoretically allows the CPU to do other things such as run other hardware threads (as in hyperthreading).Nickelson
Correct me if I'm wrong, but one difference between this solution and sleep is that sleep also yields the thread so that other threads can get work done, whereas this busy wait will not. Worth noting if doing concurrent work.Chen
S
17

For simulation, I would not attempt to simulate in real-time as this doesn't give you reproducible results. i.e. you can't test your simulation.

Instead, I would use a data-driven, simulated clock, and run everything as fast as possible. This gives you reproducible results and allows you to simulate faster than real-time (e.g. 2x to 100x faster)


Suspecting a thread takes around 10 microseconds. There is no point trying to suspend a thread for less time than this.

To busy wait for a short period of time, you can try.

long start = System.nanoTime();
while(start + delay >= System.nanoTime());

Note: as @EugeneBeresovsky comments, after your machine has been running for 292 years this could overflow so you might choose to write this as

while(System.nanoTime() - start < delay);

This will fine for delays of less than 292 years instead. You can use System.currentTimeMillis() for much longer delays.

However, even this is not reliable as System.nanoTime() can take up to 300 ns on Centos 5.x so calling it twice is going to take much longer than 100 ns. Also many OS only have a resolution of 1000 ns (1 micro-second) so this loop will wait up to 1 micro-second regardless of the delay you are looking for.

Instead what you can do is to busy wait in a short loop which is not optimised way.

For a delay of 100 ns, I suspect it would be better to busy wait on whatever you are waiting for instead of creating a separate busy loop.

Siler answered 16/7, 2012 at 6:49 Comment(6)
Good post. I edited < to >= to correct the code (in retrospect, ">" is even better). I made a few other trivial changes to reach the minimum character edit of 6 (argh). Thanks.Shyster
Your while condition suffers from an integer overflow bug. You have to compare the difference of two nanoTime() results against some absolute value, as done e.g. by @EntangledLoops, rather than comparing two absolute nanoTime values against each other.Barm
@EugeneBeresovsky The long value will overflow after your machine has been running for 292 years... I will update my answer.Siler
Have you seen the uptime of MY box yet? ;) But seriously, there is no guarantee that nanoTime starts at 0: The value returned represents nanoseconds since some fixed but arbitrary origin time (perhaps in the future, so values may be negative). The same origin is used by all invocations of this method in an instance of a Java virtual machine; other virtual machine instances are likely to use a different origin. So it wraps every 292 years, but potentially much earlier than 292 years after booting up.Barm
The docs - linked to in the last comment - are also explicit about this: To compare two nanoTime values, one should use t1 - t0 < 0, not t1 < t0, because of the possibility of numerical overflow. Reading your edit, one might (or might not) get the impression that time intervals longer than 292 years are the problem (they are, but no program runs that long). That is not what I was talking about. It's the - still highly unlikely, but actually possible - case when the nanoTime overflows between two calls - theoretically even if the calls are just milliseconds or less apart.Barm
@EugeneBeresovsky correct however the System.nanoTime() is the uptime of the machine on Windows, Linux, MacOSX, so this won't happen until your machine has been up for 292 years.Siler
F
6
public static void busySleep(long nanos)
{
  long elapsed;
  final long startTime = System.nanoTime();
  do {
    elapsed = System.nanoTime() - startTime;
  } while (elapsed < nanos);
}
Fado answered 22/10, 2015 at 14:56 Comment(0)
B
2

Do a busy wait , ( ie have a while loop cycle through so many numbers doing nothing ). A the start of your program you can time the amount of time it took it execute this busy wait and increase or decrease it to get to 5 nano seconds

I have found object.wait gets hairy with this frequency also make note that a busy wait solution would most likely be machine dependent Hence why you should have a calibration step at the start of your program

Bookmobile answered 16/7, 2012 at 6:37 Comment(0)
H
1

One more problem with Thread.sleep() is that it is not guaranteed to wakeup after the specified time. A sleeping thread is guarenteed to sleep for the specified nano/micro seconds but not guarenteed to wakeup immediately after that. Since you are talking interms of nanoseconds, you might want to try Object.wait(long, int).

I ve been quite consistent with the order of 10s of nanoseconds with the above method.

Hymnody answered 16/7, 2012 at 6:36 Comment(2)
In both cases, when you invoke Thread.sleep() and Object.wait() the currently running thread goes into TIMED_WAITING mode. This implies the thread relinquish the CPU. In both cases, when the wait time ends, the CPU will, most likely be busy doing something else. There is no guarantee that the waking thread will receive the CPU at once, and even if it did, it still have to pay the context switching time, which, according to the question, this is what the inquirer wants to avoid.Arteriovenous
Moreover, in code of Object.wait(timeout, nanos) you can see that if nanos > 0 it only increases timeout by 1.Satterfield
S
0

For waiting for an answer of a UDP request I wanted to use Threads.leep(millis, nanos) like sleep(0,10). When debugging into java source of sleep(...) I saw that nanos is ignored in windows java. If nanos > 0, millis will be incremented and then sleep(millis) will be called! In windows sleep 1 ms is the shortest way to sleep.

Shandashandee answered 4/5, 2022 at 8:49 Comment(0)
J
-1

Suppose a producer thread is filling a work buffer, say a linked list. The buffer can be sized so it does not empty in less than a sleep-wake period, and the cpu can support the consumer threads that empty the buffer while you sleep. You might even up the buffer size until it is not empty when you wake. Now, how much sleep is a business decision, as there is switching overhead. Lots of hints on figuring that in the above!

Of course, there are several Blocking Concurrent Classes but generally their capacity is fixed. Blocking is no less expensive a thread suspend, I have to believe.

Jail answered 9/12, 2019 at 23:53 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.