Делает ли Thread.yield() что-нибудь, если у нас достаточно процессоров для обслуживания всех потоков?

Если мы находимся в ситуации с двумя запущенными потоками на машине с двумя процессорами, и мы вызываем Thread.yield() в одном из этих потоков, то Thread.yield() ли, что ничего не произойдет (планировщик по существу проигнорирует запрос), потому что мы достаточно процессоров для обслуживания запущенных потоков?

Ответы

Ответ 1

Всякий раз, когда поток вызывает метод Thread.yield(), он дает подсказку планировщику потока, что он готов приостановить выполнение. Планировщик потока может игнорировать эту подсказку.

Если какой-либо поток выполняет метод yield, планировщик потока проверяет, существует ли какой-либо выполняемый (ожидающий выполнения) поток с таким же или высоким приоритетом, чем у этого потока. Если процессор обнаружит какой-либо поток с более высоким или одинаковым приоритетом, он переключится на новый поток. Если нет, текущий поток продолжает выполняться.

Так как в вашем примере у вас достаточно процессоров для обслуживания всех потоков (они работают, не ожидая в работоспособном состоянии); Thread.yield() ничего не сделает, и ваши потоки продолжат свое выполнение.

Примечание о Windows, от Microsoft DOTNet:

Этот метод эквивалентен использованию вызова платформы для вызова встроенной функции Win32 SwitchToThread.

Уступка ограничена процессором, который выполняет вызывающий поток. Операционная система не будет переключать выполнение на другой процессор, даже если этот процессор простаивает или использует поток с более низким приоритетом. Если на текущем процессоре нет других потоков, готовых к выполнению, операционная система не приводит к выполнению

Так что в некоторых ситуациях могут быть оговорки.

Ответ 2

Thread.yield() устарел. Если ваша программа не будет работать на платформе, которая реализует совместную многозадачность, или на JVM, в которой все еще используются зеленые потоки, то нет смысла вызывать ее.

Стандартная библиотека Javadoc для Thread.yield() фактически говорит, что yield() вообще ничего не должен делать.

Ответ 3

Я всегда думал, что Thread::yield должен быть заменен Thread::onSpinWait (начиная с java 9) - это всего лишь форма "более слабого" выхода, пока я не увидел использование обоих в StampedLock:

    else if ((LockSupport.nextSecondarySeed() & OVERFLOW_YIELD_RATE) == 0)
        Thread.yield();
    else
        Thread.onSpinWait();
    return 0L;

Поэтому я не думаю, что это устарело. Внутренне в исходниках jdk он имеет много применений, даже относительно новый ForkJoinPool имеет использование Thread::yield.

На практике я использовал Thread::onSpinWait внутри занятых спинов - потому что, как минимум, по названию - очень ясно, когда его использовать; с другой стороны, уступать - нет, поэтому я не могу точно сказать, когда и как его использовать.

Просто мои 0,02 $.