Java线程sleep()方法

时间:2013-10-21 18:02:45

标签: java multithreading sleep

我正在做一篇过去的Java考试试卷,我对下面列出的一个问题感到困惑:

当线程在run()方法中执行以下语句时会发生什么? (选择所有适用的选项。)

sleep(500);

一个。它将停止执行,并在500毫秒后开始执行。

B中。它将停止执行,并在500毫秒之后再次开始执行。

℃。它会导致编译器错误,因为你无法在run()方法中调用sleep(...)方法。

d。它会导致编译器错误,因为sleep(...)方法不接受任何参数。

我选择A,B。但关键答案只是B,是否存在A也可能发生的情况?有人可以请我澄清一下吗?非常感谢。

6 个答案:

答案 0 :(得分:2)

JVM不能保证正好500毫秒,但它会在~500毫秒或之后启动,因为它需要启动它的'引擎',因为没有其他线程阻止任何可能会延迟一点的资源。

阅读:Inside the Hotspot VM: Clocks, Timers and Scheduling Events

编辑正如Gray在评论中指出的那样 - 与其他线程的调度也是一个因素,从一个到另一个的交换可能需要一些时间。

答案 1 :(得分:2)

  

我选择A,B。但关键答案只是B,是否存在A也可能发生的情况?有人可以请我澄清一下吗?

是的,根据您的应用,您当然可能会获得500毫秒的睡眠时间,而不是更多的纳秒时间。

然而,B更好的答案是,无法保证何时再次运行任何线程。您可以拥有一个具有大量CPU绑定线程的应用程序。即使睡眠线程现在能够运行,它也可能在相当长的一段时间内没有任何周期。精确的睡眠时间也很大程度上取决于OS线程调度程序的详细信息和时钟精度。您的应用程序还可能必须与同一系统上的其他应用程序竞争,这可能会延迟其继续执行。

例如,我的极速8xi7 CPU Macbook Pro上的以下程序显示最大睡眠时间为604毫秒:

public class MaxSleep {

    public static void main(String[] args) throws Exception {
        final AtomicLong maxSleep = new AtomicLong(0);
        ExecutorService threadPool = Executors.newCachedThreadPool();
        // fork 1000 threads
        for (int i = 0; i < 1000; i++) {
            threadPool.submit(new Runnable() {
                @Override
                public void run() {
                    for (int i = 0; i < 10; i++) {
                        long total = 0;
                        // spin doing something that eats CPU
                        for (int j = 0; j < 10000000; j++) {
                            total += j;
                        }
                        // this IO is the real time sink though
                        System.out.println("total = " + total);
                        try {
                            long before = System.currentTimeMillis();
                            Thread.sleep(500);
                            long diff = System.currentTimeMillis() - before;
                            // update the max value
                            while (true) {
                                long max =  maxSleep.get(); 
                                if (diff <= max) {
                                    break;
                                }
                                if (maxSleep.compareAndSet(max, diff)) {
                                    break;
                                }
                            }
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            });
        }
        threadPool.shutdown();
        threadPool.awaitTermination(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
        System.out.println("max sleep ms = " + maxSleep);
    }
}

答案 2 :(得分:1)

根据Javadoc: -

  

<强>睡眠()

     

导致当前正在执行的线程进入休眠状态(暂时停止   执行)指定的毫秒数,受制于   系统定时器和调度程序的精度和准确性。线程   不会失去任何监视器的所有权。

所以它可能是~500ms

B中。它将停止执行,并在500毫秒之后再次开始执行。

看起来更加突出。

答案 3 :(得分:0)

这些睡眠时间不能保证精确,因为它们受底层操作系统提供的设施限制。 Option B: Not earlier than 500更正确。

答案 4 :(得分:0)

您无法选择A和B,因为它们彼此相反,主要区别为:exactly 500 milliseconds laternot earlier than 500 milliseconds later

首先意味着它的意思(仅500毫秒),第二意味着它可以睡501或502甚至50000000000000

下一个问题 - 为什么B是真的,不是那么简单的问题,你需要了解硬实时和软实时之间有什么不同,并且解释所有原因是相当偏离主题的,所以简单回答 - 因为许多技术原因java无法保证您的代码难以实时执行,这就是为什么它表示睡眠将完成not earlier than ...

你可以阅读有关线程调度,优先级,垃圾收集,抢占式多任务处理 - 所有这些都与此相关

答案 5 :(得分:0)

如您所知,Thread 中有两个非常密切相关的状态:RunningRunnable

  1. Running :表示当前正在执行的线程。目前正在执行中。
  2. Runnable :表示线程已准备好被处理或执行。但是正在等待 Thread Schedular 接收。现在这个线程调度,根据它自己的愿望/定义的算法,取决于 JVM(例如,切片算法)将选择可用/可运行线程之一来处理它们。

因此,每当您调用 sleep 方法时,它仅保证代码的执行由它运行的线程在参数中的指定毫秒内暂停(例如,threadRef.sleep(300); 中的 300 毫秒)。一旦定义的时间过去,它就会回到Runnable状态(意味着回到Available State以被Thread Schedular拾取)。

因此,不能保证您的剩余代码会在 sleep 方法完成后立即开始执行。