我知道Thread.sleep()可以使java线程挂起一段时间,比如某些毫秒和某些纳秒。但问题是这个函数的调用也会带来开销。
例如,如果我希望线程挂起 100 纳秒,我会调用 Thread.sleep(0, 100)。这个过程的总成本是incall_cost + 100 纳秒,这可能比我想要的要大得多。我怎样才能避免这个问题并达到我的目的?
我需要这个的原因是我想离线进行模拟。我分析了任务的执行时间;现在我想通过在同一时间段内挂起一个线程来模拟这个执行时间。
谢谢!
睡眠的粒度通常受线程调度程序的中断周期的限制。在Linux中,这个中断周期在最近的内核中一般为1ms。在 Windows 中,调度程序的中断周期通常约为 10 或 15 毫秒
如果我必须暂停线程的时间少于此时间,我通常会使用繁忙等待
编辑:我怀疑您会在 jrockit +Solaris 上获得最佳结果。 Windows 盒子上的数字很可怕。
@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);
}
对于模拟,我不会尝试实时模拟,因为这不会给您提供可重现的结果。即您无法测试您的模拟。
相反,我会使用数据驱动的模拟时钟,并尽可能快地运行所有内容。这将为您提供可重现的结果,并允许您比实时更快地进行模拟(例如快 2 倍到 100 倍)
怀疑一个线程大约需要 10 微秒。尝试将线程挂起的时间少于此时间是没有意义的。
要忙等一小段时间,可以尝试一下。
long start = System.nanoTime();
while(start + delay >= System.nanoTime());
注意:正如 @EugeneBeresovsky 评论的那样,在你的机器运行了 292 年之后,这可能会溢出,所以你可以选择将其写为
while(System.nanoTime() - start < delay);
如果延误时间少于 292 年,则会罚款。 您可以使用 System.currentTimeMillis() 来实现更长的延迟。
然而,即使这样也是不可靠的,因为 System.nanoTime() 在 Centos 5.x 上可能需要长达 300 ns 的时间,因此调用它两次将花费比 100 ns 更长的时间。此外,许多操作系统的分辨率仅为 1000 ns(1 微秒),因此无论您要寻找的延迟如何,此循环都会等待最多 1 微秒。
相反,你可以做的是在一个短循环中忙碌等待,这不是优化的方式。
对于 100 ns 的延迟,我怀疑最好忙等待您正在等待的任何内容,而不是创建一个单独的忙循环。
public static void busySleep(long nanos)
{
long elapsed;
final long startTime = System.nanoTime();
do {
elapsed = System.nanoTime() - startTime;
} while (elapsed < nanos);
}
进行繁忙的等待(即有一个 while 循环循环遍历这么多数字而不执行任何操作)。在程序开始时,您可以计算执行此繁忙等待所花费的时间,并增加或减少它以达到 5 纳秒
我发现 object.wait 在这个频率下变得毛茸茸的,还请注意,繁忙的等待解决方案很可能是依赖于机器的,因此为什么你应该在程序开始时有一个校准步骤
Thread.sleep()
的另一个问题是它不能保证在指定时间后唤醒。睡眠线程保证睡眠指定的纳秒/微秒,但不保证在此之后立即唤醒。既然您正在谈论纳秒,您可能想尝试Object.wait(long, int)
。
我用上面的方法已经和10纳秒量级相当一致了。
为了等待 UDP 请求的答复,我想使用 Threads.leep(millis, nanos),如 sleep(0,10)。 当调试 java 的 sleep(...) 源代码时,我发现在 windows java 中 nanos 被忽略了。如果 nanos > 0,millis 将增加,然后 sleep(millis) 将被调用! 在 Windows 中睡眠 1 毫秒是最短的睡眠方式。
在Java 21中,有一个新特性:
Thread.sleep(millis, nanos)
假设生产者线程正在填充工作缓冲区,例如链表。 可以调整缓冲区的大小,使其在睡眠-唤醒周期内不会清空,并且 CPU 可以支持在睡眠时清空缓冲区的消费者线程。 您甚至可以增加缓冲区大小,直到您醒来时它不为空。 现在,睡眠时间是一个业务决策,因为存在切换开销。 上面有很多关于计算这一点的提示!
当然,有几个阻塞并发类,但通常它们的容量是固定的。 我必须相信,阻塞并不比线程挂起便宜。