Thread.sleep() 实现

2022-09-01 10:04:08

今天我有一个面试,我问了候选人关于和之间的区别的非常平常和基本的问题。我本以为他会回答这样的事情,但他说这些方法基本上是一回事,很可能是在里面使用,但本身并不需要外部锁。这并不是一个正确的答案,因为在JDK 1.6中,此方法具有以下签名。Thread.sleep()Object.wait()Thread.sleepObject.wait()sleep

public static native void sleep(long millis) throws InterruptedException;

但我的第二个想法是,这并不那么荒谬。可以使用定时等待来达到相同的效果。请看以下代码片段:

public class Thread implements Runnable {
       private final Object sleepLock = new Object();

     // other implementation details are skipped

       public static void sleep(long millis) throws InterruptedException {
            synchronized (getCurrentThread().sleepLock){
                getCurrentThread().sleepLock.wait(millis);
            }
        }

在这种情况下,是一个对象,它特别用于方法内部的同步块。我假设 Sun/Oracle 的工程师知道 Occam 的剃刀,所以有意实现原生,所以我的问题是为什么它使用原生调用。sleepLocksleepsleep

我想出的唯一想法是假设有人可能会发现有用的调用,例如.根据本文,对于调度程序管理是有意义的Thread.sleep(0)

这具有清除当前线程的量程并将其置于队列末尾以达到其优先级的特殊效果。换句话说,所有具有相同优先级的可运行线程(以及具有更高优先级的线程)将有机会在下次给定 CPU 时间之前运行生成的线程。

因此,块将产生不必要的开销。synchronized

您知道在 Thread.sleep() 实现中不使用定时等待的任何其他原因吗?


答案 1

人们可以很容易地说奥卡姆剃刀切向另一个方向。假设 JVM 底层 JDK 的正常/预期实现在大多数时间将 java“线程”绑定到本机线程上,而将线程置于休眠状态是底层平台的基本功能。如果线程代码无论如何都是本机的,为什么要在java中重新实现它?最简单的解决方案是使用已经存在的函数。

其他一些注意事项:在现代JVM中,无争议的同步可以忽略不计,但事实并非总是如此。获取该对象监视器曾经是一个相当“昂贵”的操作。

如果您在Java代码中实现线程休眠,并且实现它的方式也没有绑定到本机线程等待,则操作系统必须继续调度该线程,以便运行检查是否该唤醒的代码。正如注释中所讨论的那样,对于您在现代JVM上的示例来说,这显然不是真的,但是很难说1)在Thread类首次以这种方式指定时可能已经到位和期望的内容。2)如果该断言适用于每个平台,那么人们可能曾经想要实现JVM。


答案 2

您知道在实施中不使用定时等待的任何其他原因吗?Thread.sleep()

因为本机线程库提供了完美的睡眠功能:http://www.gnu.org/software/libc/manual/html_node/Sleeping.html

要了解为什么本机线程很重要,请从 http://java.sun.com/docs/hotspot/threads/threads.html

版本 1.1 基于绿色线程,此处不作介绍。绿色线程是 VM 中的模拟线程,在 1.2 及更高版本中转到本机 OS 线程模型之前已使用。绿色线程可能曾经在 Linux 上具有优势(因为您不必为每个本机线程生成一个进程),但自 1.1 版以来,VM 技术已经取得了显著的进步,并且绿色线程过去具有的任何好处都会被多年来的性能提升所抹去。