Thread.sleep ведет себя странно

У меня есть следующий код:

public Move chooseMove(Board board) {

    // start parallel thread
    this.tn = new TreeNode(this.myboard, this, null);
    tn.stop = false;
    this.curT = (new Thread(tn));
    this.curT.start();


    try {
        long startTime = System.currentTimeMillis();
        Thread.sleep(4000 );
        System.out.println(System.currentTimeMillis() - startTime);
    } catch (InterruptedException e) {
        e.printStackTrace();
    } finally {
        tn.stop=true;
        return getBestMove();
    }
}

Вывод иногда представляет собой значение, которое намного превышает 4000 мс, например 5400 мс, что означает, что поток спит больше, чем должен. Любая помощь? Спасибо.

РЕДАКТИРОВАТЬ: я понимаю, что НЕТ гарантии остановки Thread#sleep именно после указанной задержки. Однако дополнительные 1400 мс — это большая задержка. По сути, я реализую агент игрового игрока, и мне нужен способ запустить задачу, а затем вернуть значение на сервер через 5 секунд (иначе сервер завершит игру). Сервер использует java.util.Timer.schedule (задача TimerTask, большая задержка). Существует только один поток, работающий одновременно с основным потоком, который является this.curT в приведенном выше коде, поэтому многопоточность не очень тяжелая.


person Mouhyi    schedule 21.04.2013    source источник
comment
Процессор сильно занят другими делами? Если процессор действительно работал с большим количеством одновременных потоков, поток некоторое время не мог получить циклы.   -  person Gray    schedule 21.04.2013
comment
Как часто вы сталкиваетесь с таким поведением? Попробуйте запустить только свой поток со спящим вызовом без какого-либо другого кода.   -  person michael nesterenko    schedule 22.04.2013
comment
Если я запускаю Thread.sleep один в одном потоке, он ведет себя правильно. но у меня есть только 2 потока, работающих в моем реальном коде, как показано выше.   -  person Mouhyi    schedule 22.04.2013


Ответы (3)


Из docs.oracle.com:

Предусмотрены две перегруженные версии спящего режима: одна указывает время спящего режима с точностью до миллисекунды, а другая — с точностью до наносекунды. Однако точное время перехода в спящий режим не гарантируется, поскольку оно ограничено возможностями базовой ОС. Кроме того, период сна может быть прерван прерываниями, как мы увидим в следующем разделе. В любом случае вы не можете предполагать, что активация спящего режима приостановит поток точно на указанный период времени.

person Vito Gentile    schedule 21.04.2013
comment
Да, но по моему опыту это делает @Vito. Любое объяснение того, почему он ждет дополнительных 1400 мс? - person Gray; 21.04.2013
comment
1400 мс - это долго, но это может объяснить такая деятельность, как сборка мусора. Суть, однако, в том, что время паузы в Thread.sleep не может быть точным. - person DaveH; 21.04.2013

Это обычное поведение, описанное в Thread#sleep javadoc:

Переводит выполняющийся в данный момент поток в спящий режим (временно прекращает выполнение) на указанное количество миллисекунд, в зависимости от точности системных таймеров и планировщиков.

Исходя из этого, нет гарантии, что Thread#sleep остановит работу потока на количество миллисекунд, указанное в параметре.

person Luiggi Mendoza    schedule 21.04.2013

Thread#sleep переводит ваш поток в спящий режим на ровно 4 секунды, а затем пробуждается.
После того, как ваш поток проснется, планировщик ОС помещает его в очередь runnable.
Когда он в следующий раз будет выбран планировщиком, он станет работающим потоком, т. е. будет занимать ЦП.
Таким образом, возникают дополнительные задержки из-за планировщика ОС, которые могут варьироваться в зависимости от ОС, системы. загрузка и т. д. Это не связано с Java

person Cratylus    schedule 21.04.2013
comment
Есть ли способ заставить поток запускаться ровно через 4 секунды, влияя на приоритеты запускаемой очереди планировщика ОС? - person Mouhyi; 22.04.2013
comment
Вы можете назначить MAX_PRIORITY, но все равно не гарантируется точный уровень точности, который вы ожидаете. Если вам нужно ровно 4 секунды, вы должны выполнить опрос вместо sleep. вернет его за 4 секунды. Гарантируется, что ваш поток проснется через 4 секунды, но не более того. - person Cratylus; 22.04.2013
comment
что вы имеете в виду под опросом? - person Mouhyi; 22.04.2013
comment
Я пробовал это, но если проверка выполняется, скажем, [System.currentTimeMillis() - startTime = 3990], тогда она будет проходить более 4000 мс, если код внутри цикла занимает много времени (чего не следует делать, но у меня есть несколько потоки работают, поэтому я предполагаю, что это может быть причиной) - person Mouhyi; 22.04.2013
comment
@Mouhyi: Вы должны останавливаться после выполнения обработки, чтобы обработка не увеличивала время задержки. т.е. сделать работу, а затем спин-петля в течение 4 секунд. ЕСЛИ вы говорите, что вам нужно, чтобы работа длилась ровно 4 секунды - person Cratylus; 22.04.2013