32

我知道Thread.sleep()可以使 java 线程暂停一段时间,例如某些毫秒和某些纳秒。但问题是这个函数的调用也会导致开销。

例如,如果我想让一个线程挂起 100 纳秒,我调用Thread.sleep(0, 100)。这个过程的全部成本是invocation_cost + 100 nanosceonds,这可能比我想要的要大得多。我怎样才能避免这个问题,并达到我的目的?

我需要这个的原因是我想离线进行模拟。我分析了一个任务的执行时间;现在我想通过在同一时间段内挂起一个线程来模拟这个执行时间。

谢谢!

4

6 回答 6

25

睡眠的粒度通常受线程调度程序的中断周期限制。在 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);
}
于 2012-07-16T05:40:54.370 回答
15

对于模拟,我不会尝试实时模拟,因为这不会给您可重复的结果。即你不能测试你的模拟。

相反,我会使用数据驱动的模拟时钟,并尽可能快地运行所有内容。这为您提供了可重现的结果,并允许您比实时更快地模拟(例如快 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 的延迟,我怀疑最好是忙于等待您正在等待的任何内容,而不是创建一个单独的忙循环。

于 2012-07-16T06:49:25.597 回答
5
public static void busySleep(long nanos)
{
  long elapsed;
  final long startTime = System.nanoTime();
  do {
    elapsed = System.nanoTime() - startTime;
  } while (elapsed < nanos);
}
于 2015-10-22T14:56:50.347 回答
2

做一个忙碌的等待,(即有一个while循环循环通过这么多数字什么都不做)。在您的程序开始时,您可以计算执行此繁忙等待所花费的时间,并增加或减少它以达到 5 纳秒

我发现 object.wait 会因为这个频率而变得毛茸茸,还要注意繁忙的等待解决方案很可能是依赖于机器的因此为什么你应该在程序开始时有一个校准步骤

于 2012-07-16T06:37:42.713 回答
1

另一个问题Thread.sleep()是不能保证在指定时间后唤醒。睡眠线程保证在指定的纳秒/微秒内睡眠,但不保证在此之后立即唤醒。由于您在谈论纳秒,您可能想尝试Object.wait(long, int).

使用上述方法,我已经非常符合 10s 纳秒的顺序。

于 2012-07-16T06:36:01.767 回答
-1

假设一个生产者线程正在填充一个工作缓冲区,比如一个链表。可以调整缓冲区的大小,使其在睡眠-唤醒周期内不会清空,并且 cpu 可以支持在您睡眠时清空缓冲区的消费者线程。您甚至可以增加缓冲区大小,直到您醒来时它不为空。现在,多少睡眠是一个业务决策,因为存在切换开销。上面有很多关于计算的提示!

当然,有几个阻塞并发类,但通常它们的容量是固定的。我不得不相信,阻塞与线程挂起一样昂贵。

于 2019-12-09T23:53:31.640 回答