«1. Обзор

В этом руководстве мы рассмотрим метод yield() в классе Thread.

Мы сравним его с другими идиомами параллелизма, доступными в Java, и в конечном итоге рассмотрим его практическое применение.

2. Краткий обзор yield()

Как следует из официальной документации, yield() предоставляет механизм для информирования «планировщика» о том, что текущий поток желает отказаться от своего текущего использования процессора, но хотел бы быть запланировано обратно как можно скорее.

«Планировщик» может придерживаться или игнорировать эту информацию и фактически имеет различное поведение в зависимости от операционной системы.

Следующий фрагмент кода отображает два потока с одинаковым приоритетом, уступающим после каждого расписания:

public class ThreadYield {
    public static void main(String[] args) {
        Runnable r = () -> {
            int counter = 0;
            while (counter < 2) {
                System.out.println(Thread.currentThread()
                    .getName());
                counter++;
                Thread.yield();
            }
        };
        new Thread(r).start();
        new Thread(r).start();
    }
}

Когда мы пытаемся запустить приведенную выше программу несколько раз, мы получаем разные результаты; некоторые из них упомянуты ниже:

Запуск 1:

Thread-0
Thread-1
Thread-1
Thread-0

Запуск 2:

Thread-0
Thread-0
Thread-1
Thread-1

Как видите, поведение yield() недетерминировано и зависит от платформы.

3. Сравнение с другими идиомами

Существуют и другие конструкции, влияющие на относительную последовательность потоков. Они включают в себя wait(), notify() и notifyAll() как часть класса Object, join() как часть класса Thread и sleep() как часть класса Thread.

Давайте посмотрим, как они соотносятся с yield().

3.1. yield() vs wait()

    Пока yield() вызывается в контексте текущего потока, wait() может вызываться только для явно полученной блокировки внутри синхронизированного блока или метода. для wait(), чтобы указать минимальный период времени ожидания перед любой попыткой снова запланировать поток. С помощью wait() также можно разбудить поток в любое время с помощью вызова notify() или notifyAll() для соответствующего объекта блокировки ~ ~~ 3.2. yield() vs sleep()

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

    3.3. yield() vs join()

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

    4. Использование yield()

Как следует из официальной документации, использование yield() требуется редко, и, следовательно, его следует избегать, если не совсем ясно с целями в свете своего поведения.

Тем не менее, yield() может использоваться для разработки конструкций управления параллелизмом, повышения скорости отклика системы в программе с большим объемом вычислений и т. д.

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

5. Заключение

В этой небольшой статье мы обсудили метод yield() в классе Thread и рассмотрели его поведение и ограничения на фрагменте кода.

Мы также изучили его сравнение с другими идиомами параллелизма, доступными в Java, и, наконец, рассмотрели некоторые варианты использования, где yield() может быть полезен.

Как всегда, вы можете ознакомиться с примерами, приведенными в этой статье, на GitHub.

«