Реализация Thread.sleep () - PullRequest
       27

Реализация Thread.sleep ()

28 голосов
/ 31 января 2012

Сегодня у меня было интервью, на котором я задавал кандидату довольно обычный и базовый вопрос о разнице между Thread.sleep() и Object.wait(). Я ожидал, что он ответит что-то вроде , например, , но он сказал, что эти методы в основном одно и то же, и, скорее всего, Thread.sleep использует Object.wait() внутри него, но сам sleep не требует внешний замок Это не совсем правильный ответ, потому что в JDK 1.6 этот метод имеет следующую подпись.

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);
            }
        }

В этом случае sleepLock - это объект, который используется, в частности, для блока синхронизации внутри метода sleep. Я предполагаю, что инженеры Sun / Oracle знают о бритве Оккама, поэтому sleep имеет встроенную реализацию специально, поэтому мой вопрос заключается в том, почему она использует собственные вызовы.

Единственная идея, которая мне пришла в голову - это предположение, что кто-то может найти полезный вызов, такой как Thread.sleep(0). Имеет смысл для управления планировщиком согласно этой статье:

Это имеет специальный эффект очистки кванта текущего потока и помещения его в конец очереди для его уровня приоритета. Другими словами, все выполняемые потоки с одинаковым приоритетом (и потоки с более высоким приоритетом) получат возможность запустить до того, как полученному потоку в следующий раз дадут время ЦП.

Таким образом, synchronized блок даст ненужные накладные расходы.

Знаете ли вы какие-либо другие причины не использовать синхронизированное ожидание в реализации Thread.sleep()?

Ответы [ 3 ]

9 голосов
/ 31 января 2012

Можно легко сказать, что бритва Оккама режет по-другому.Предполагается, что нормальная / ожидаемая реализация JVM, лежащего в основе JDK, большую часть времени связывает java-потоки с собственными потоками, а перевод потока в спящий режим является фундаментальной функцией базовой платформы.Зачем переопределять это в Java, если код потока все равно будет нативным?Самое простое решение - использовать уже существующую функцию.

Некоторые другие соображения: неоспоримая синхронизация незначительна в современных JVM, но это не всегда было так.Раньше это была довольно «дорогая» операция для получения этого объектного монитора.

Если вы реализуете спящий поток внутри java-кода, и способ его реализации не привязывает также к собственному ожиданию потока, операционная системадолжен продолжать планировать этот поток, чтобы запустить код, который проверяет, пора ли проснуться.Как было отмечено в комментариях, это, очевидно, было бы неверно для вашего примера на современной JVM, но сложно сказать 1) что, возможно, было на месте и ожидалось в то время, когда класс Thread был впервые указан таким образом.и 2) Если это утверждение работает для каждой платформы, возможно, кто-то когда-либо хотел внедрить JVM.

7 голосов
/ 31 января 2012

Знаете ли вы какие-либо другие причины не использовать синхронизированное ожидание в реализации Thread.sleep()?

Поскольку нативные библиотеки потоков обеспечивают отличную функцию сна: http://www.gnu.org/software/libc/manual/html_node/Sleeping.html

Чтобы понять, почему собственные потоки важны, начните с http://java.sun.com/docs/hotspot/threads/threads.html

Версия 1.1 основана на зеленых потоках и здесь не рассматривается.Зеленые потоки - это смоделированные потоки внутри виртуальной машины, которые использовались до перехода к модели потоков в собственной операционной системе версии 1.2 и выше.Зеленые потоки, возможно, имели преимущество в Linux в один момент (поскольку вам не нужно создавать процесс для каждого собственного потока), но технология VM значительно продвинулась с версии 1.1, и любые преимущества, которые зеленые потоки имели в прошлом, стираютсяпроизводительность увеличивается с годами.

2 голосов
/ 31 января 2012

Thread.sleep () не проснется рано из-за ложных пробуждений .Если вы используете Object.wait (), чтобы сделать это правильно (т. Е. Обеспечить достаточное время ожидания), вам потребуется цикл с запросом к истекшему времени (например, System.currentTimeMillis ()), чтобы убедиться, что вы достаточно подождете.

Технически вы могли бы достичь той же функциональности Thread.sleep () с Object.wait (), но вам нужно было бы написать больше кода, чтобы сделать это правильно.

Это такжеактуальное и полезное обсуждение.

...