4

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

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

sleep(500);

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

B. 它将停止执行,并在不早于 500 毫秒后再次开始执行。

C. 这将导致编译器错误,因为您不能在 run() 方法中调用 sleep(...) 方法。

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

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

4

6 回答 6

2

JVM cannot guarantee exactly 500 ms but it will start on or after ~500 ms as it will need to start its 'engine' back considering no other threads are blocking any resources which may delay a bit.

Read: Inside the Hotspot VM: Clocks, Timers and Scheduling Events

Edit: As Gray pointed out in the comment - the scheduling with other threads also a factor, swapping from one to another may cost some time.

于 2013-10-21T18:05:13.247 回答
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);
    }
}
于 2013-10-21T18:55:40.143 回答
1

根据Javadoc:-

睡觉()

使当前执行的线程休眠(暂时停止执行)指定的毫秒数,取决于系统计时器和调度程序的精度和准确性。该线程不会失去任何监视器的所有权。

所以它可能是~500ms

B. 它将停止执行,并在不早于 500 毫秒后再次开始执行。

显得更加突出。

于 2013-10-21T18:06:42.657 回答
0

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

于 2013-10-21T18:07:21.490 回答
0

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

首先意味着它的含义(仅 500 毫秒),第二个意味着它可以休眠 501 或 502 甚至 50000000000000

下一个问题 - 为什么 B 是真的,这不是那么简单的问题,您需要了解硬实时和软实时之间的区别,并且解释所有原因是非常离题的,所以简单地回答 - 由于许多技术原因java不能保证你的代码的硬实时执行,这就是为什么它说sleep会完成not earlier than ...

您可以阅读有关线程调度、优先级、垃圾收集、抢占式多任务处理的信息——所有这些都与此相关

于 2013-10-21T18:10:13.630 回答
0

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

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

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

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

于 2021-05-06T16:20:25.423 回答