2012-01-30 2 views
28

Сегодня у меня было интервью, на котором я задал кандидату довольно обычный и основной вопрос о разнице между Thread.sleep() и Object.wait(). Я ожидал, что он ответит на что-то вроде like this, но он сказал, что эти методы в основном одно и то же, и, скорее всего, Thread.sleep использует в нем Object.wait(), но sleep сам по себе не требует внешней блокировки. Это не совсем правильный ответ, потому что в JDK 1.6 этот метод имеет следующую подпись.Thread.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); 
      } 
     } 

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

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

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

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

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

+1

wait (millis) может просыпаться ложно (рано), тогда как сон не просыпается рано, если не прерывается. –

+0

Проверен ли прерванный флаг во время вызова sleep(), чтобы исключить и вернуть? Или каким-то образом этот вызов идет и к планировщику, а затем планировщик знает, как закончить сон потока? –

+0

Мне было бы больше интересно узнать, знают ли они, как правильно обрабатывать InterruptedException. –

ответ

9

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

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

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

+0

@ruakh, я бы предположил, что когда собственные потоки реализованы поверх pthreads, которые ['pthread_cond_ * wait'] (http://pubs.opengroup.org/onlinepubs/7908799/xsh/pthread_cond_wait.html) лежат в основе' Object. wait'. –

+0

Можно было бы ожидать, что современные JVM и современные платформы обязательно сделают это. Тем не менее, вопрос OPs «Каковы некоторые причины, по которым некоторые инженеры Sun более 10 лет назад, возможно, приняли это решение?», А не о том, как сейчас все работает. :) – Affe

+0

@руах, я не получаю такого впечатления, когда я читаю ответ Аффе. –

7

Знаете ли вы какие-либо другие причины не использовать время ожидания в 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

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

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

This также является актуальным и полезным обсуждением.

+0

Две функции имеют разные цели. Вы можете использовать его для подражания другому, но это было бы сложно и, несомненно, уступало бы уже реализованной реализации. –

+0

Да, это имеет смысл. Я foorgot о побочных пробуждениях, и похоже, что Thread.sleep() не влияет на это явление. – wax

Смежные вопросы