我知道 Thread.sleep()可以让java线程暂停一段时间,比如某些毫秒和某个纳秒。但问题是这个函数的调用也会导致开销。
例如,如果我想要一个线程暂停100纳秒,我调用 Thread.sleep(0,100)。这个过程的全部成本是 invocation_cost + 100 nanosceonds ,这可能比我想要的要大得多。我怎么能避免这个问题,实现我的目的呢?
我需要这个的原因是我想离线进行模拟。我描述了任务的执行时间;现在我想通过在同一时间段内挂起一个线程来模拟这个执行时间。
谢谢!
答案 0 :(得分:22)
睡眠的粒度通常受线程调度程序的中断周期的约束。在Linux中,这个中断周期在最近的内核中通常为1ms。在Windows中,调度程序的中断周期通常约为10或15毫秒
如果我必须暂停线程的时间少于此,我通常会使用忙等待
编辑:我怀疑你会在jrockit + solaris上获得最佳成绩。窗户上的数字很糟糕。
@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);
}
答案 1 :(得分:13)
对于模拟,我不会尝试实时模拟,因为这不会给你可重复的结果。即你无法测试你的模拟。
相反,我会使用数据驱动的模拟时钟并尽可能快地运行所有内容。这为您提供了可重复的结果,并允许您比实时更快地模拟(例如,快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的延迟,我怀疑忙于等待你正在等待的任何事情而不是创建一个单独的忙循环会更好。
答案 2 :(得分:3)
public static void busySleep(long nanos)
{
long elapsed;
final long startTime = System.nanoTime();
do {
elapsed = System.nanoTime() - startTime;
} while (elapsed < nanos);
}
答案 3 :(得分:1)
Thread.sleep()
的另一个问题是无法保证在指定时间后唤醒。保持睡眠线程能够在指定的纳秒/微秒内睡眠,但不能保证在此之后立即醒来。由于您正在谈论纳秒间隔,因此您可能需要尝试Object.wait(long, int)
。
使用上述方法,我已经非常符合10纳秒的数量级。
答案 4 :(得分:1)
做一个忙碌的等待,(即通过这么多数字做无所事事的循环周期)。在程序开始时,您可以计算执行此忙碌等待所需的时间,并将其增加或减少到5纳秒
我发现object.wait变得毛茸茸这个频率也注意到繁忙的等待解决方案很可能是机器相关的因此为什么你应该在程序开始时有一个校准步骤
答案 5 :(得分:-1)
假设生产者线程正在填充工作缓冲区,例如链表。可以调整缓冲区的大小,以使其在少于睡眠唤醒周期的时间内不会清空,并且CPU可以支持在您睡眠时清空缓冲区的使用者线程。您甚至可以增加缓冲区大小,直到唤醒后它不为空。现在,多少睡眠是业务决策,因为存在开销的切换。上面提到的很多提示!
当然,有几个阻塞并发类,但是通常它们的容量是固定的。我必须相信,阻塞并不会降低线程暂停的代价。