Что делает метод Thread.yield() в Java?

«Что делает метод Thread.yield() в Java?» — вопрос из категории Java Core, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

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

Ключевые характеристики:

  • Подсказка, а не команда: Планировщик потоков может проигнорировать этот вызов. Гарантий переключения контекста нет.
  • Цель: Позволить потокам с одинаковым или более высоким приоритетом получить время CPU. Потоки с более низким приоритетом могут не запуститься.
  • Состояние потока: Поток переходит из состояния RUNNING обратно в RUNNABLE, давая шанс запуститься другим потокам из очереди RUNNABLE.
  • Не освобождает мониторы: Поток не освобождает захваченные блокировки (synchronized) или другие ресурсы.

Пример использования:

public class YieldExample {
    public static void main(String[] args) {
        Thread producer = new Thread(() -> {
            for (int i = 0; i < 5; i++) {
                System.out.println("Producer: generating item " + i);
                Thread.yield(); // Подсказка: дать Consumer'у шанс обработать
            }
        });

        Thread consumer = new Thread(() -> {
            for (int i = 0; i < 5; i++) {
                System.out.println("Consumer: processing item " + i);
                Thread.yield(); // Подсказка: дать Producer'у шанс сгенерировать
            }
        });

        producer.start();
        consumer.start();
    }
}
// Вывод непредсказуем и может меняться от запуска к запуску.

Практические рекомендации:

  • Используйте редко. Современные планировщики и многоядерные процессоры эффективно управляют потоками.
  • Не используйте для синхронизации или контроля порядка выполнения. Для этого существуют wait()/notify(), Lock, Semaphore.
  • Основное применение: В академическом коде или для снижения агрессивного потребления CPU в очень плотных, неблокирующих циклах (busy-wait loops), хотя обычно лучше использовать sleep(1) или более сложные примитивы синхронизации.