«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.
«