Я немного смущен использованием yield()
метода в Java, особенно в приведенном ниже примере кода. Я также читал, что yield () «используется для предотвращения выполнения потока».
Мои вопросы:
Я считаю, что приведенный ниже код дает одинаковый результат как при его использовании, так
yield()
и когда он не используется. Это верно?Каковы на самом деле основные применения
yield()
?Каким образом
yield()
отличается отjoin()
иinterrupt()
методов?
Пример кода:
public class MyRunnable implements Runnable {
public static void main(String[] args) {
Thread t = new Thread(new MyRunnable());
t.start();
for(int i=0; i<5; i++) {
System.out.println("Inside main");
}
}
public void run() {
for(int i=0; i<5; i++) {
System.out.println("Inside run");
Thread.yield();
}
}
}
Я получаю тот же результат, используя приведенный выше код как с использованием, так и без использования yield()
:
Inside main
Inside main
Inside main
Inside main
Inside main
Inside run
Inside run
Inside run
Inside run
Inside run
yield()
и нет. когда у вас больше i, чем 5, вы можете увидеть эффектyield()
метода.Ответы:
Источник: http://www.javamex.com/tutorials/threads/yield.shtml
источник
Я вижу, что вопрос был повторно активирован наградой, теперь я спрашиваю, каково практическое использование
yield
. Приведу пример из своего опыта.Как мы знаем,
yield
заставляет вызывающий поток отказаться от процессора, на котором он работает, чтобы можно было запланировать запуск другого потока. Это полезно, когда текущий поток на данный момент завершил свою работу, но хочет быстро вернуться в начало очереди и проверить, не изменилось ли какое-либо условие. Чем это отличается от переменной условия?yield
позволяет потоку намного быстрее вернуться в рабочее состояние. При ожидании переменной условия поток приостанавливается и должен ждать, пока другой поток не подаст сигнал о том, что он должен продолжить.yield
в основном говорит: «разрешите запуск другого потока, но позвольте мне очень быстро вернуться к работе, поскольку я ожидаю, что что-то изменится в моем состоянии очень и очень быстро». Это намекает на интенсивное вращение, когда условие может быстро измениться, но приостановка потока приведет к значительному снижению производительности.Но хватит болтовни, вот конкретный пример: параллельный узор волнового фронта. Базовым примером этой проблемы является вычисление отдельных «островков» единиц в двумерном массиве, заполненном нулями и единицами. «Остров» - это группа ячеек, которые примыкают друг к другу по вертикали или горизонтали:
Здесь у нас есть два островка единиц: верхний левый и нижний правый.
Простое решение - сделать первый проход по всему массиву и заменить значения 1 увеличивающимся счетчиком так, чтобы к концу каждая 1 была заменена своим порядковым номером в старшем порядке строк:
На следующем шаге каждое значение заменяется минимумом между ним и значениями соседей:
Теперь мы можем легко определить, что у нас есть два острова.
Часть, которую мы хотим запустить параллельно, - это этап, на котором мы вычисляем минимумы. Не вдаваясь в подробности, каждый поток получает строки с чередованием и полагается на значения, вычисленные потоком, обрабатывающим строку выше. Таким образом, каждый поток должен немного отставать от потока, обрабатывающего предыдущую строку, но также должен успевать за разумное время. Более подробная информация и реализация представлены мной в этом документе . Обратите внимание на использование ,
sleep(0)
которое более или менее С эквивалентомyield
.В этом случае
yield
использовалось, чтобы заставить каждый поток по очереди приостанавливаться, но поскольку поток, обрабатывающий соседнюю строку, тем временем продвигался бы очень быстро, переменная условия оказалась бы катастрофическим выбором.Как видите,
yield
это довольно мелкая оптимизация. Использование его в неправильном месте, например, ожидание в условиях, которые редко меняются, приведет к чрезмерному использованию ЦП.Извините за долгий лепет, надеюсь, я ясно выразился.
источник
yield
когда условие не выполняется, чтобы дать другим потокам возможность продолжить вычисление, а не использовать более высокий примитивы синхронизации уровней, верно?yield
.О различиях между
yield()
,interrupt()
иjoin()
- в общем, не только в Java:В частности, для Java см.
Присоединение:
Как использовать Thread.join? (здесь, в StackOverflow)
Когда присоединяться к темам?
Урожайность:
Прерывание:
Является ли Thread.interrupt () злом? (здесь, в StackOverflow)
источник
wait()
не является соединением, это касается блокировки объекта, который вызывающий поток пытается получить - он ждет, пока блокировка не будет освобождена другими и не будет получена потоком. Соответственно изменил свой ответ.Во-первых, собственно описание
Теперь очень вероятно, что ваш основной поток выполнит цикл пять раз до того, как будет выполнен
run
метод нового потока, поэтому все вызовыyield
будут происходить только после того, как цикл в основном потоке будет выполнен.join
остановит текущий поток до тех пор, пока вызываемый поток не завершитjoin()
выполнение.interrupt
прерывает вызываемый поток, вызывая InterruptedException .yield
позволяет переключение контекста на другие потоки, поэтому этот поток не будет использовать все ресурсы ЦП процессом.источник
SwitchToThread()
call лучше, чем Sleep (0), и это должно быть ошибкой в Java :)Там нет практической разницы в
Thread.yield()
между Java версии с 6 до 9.TL; DR;
Выводы на основе исходного кода OpenJDK ( http://hg.openjdk.java.net/ ).
Если не учитывать поддержку HotSpot у зондов USDT (информация о системной трассировке описана в гайде по dtrace ) и свойство JVM,
ConvertYieldToSleep
то исходный код уyield()
них практически такой же. См. Объяснение ниже.Java 9 :
Thread.yield()
вызывает специфичный для ОС методos::naked_yield()
:В Linux:
В Windows:
Java 8 и более ранние версии:
Thread.yield()
вызывает специфичный для ОС методos::yield()
:В Linux:
В Windows:
Как видите,
Thread.yeald()
в Linux все версии Java идентичны.Посмотрим на Windows
os::NakedYield()
из JDK 8:Отличие Java 9 от Java 8 в дополнительной проверке существования метода Win32 API
SwitchToThread()
. Тот же код присутствует для Java 6.Исходный код
os::NakedYield()
в JDK 7 немного отличается, но имеет то же поведение:Дополнительная проверка была удалена из-за того, что
SwitchToThread()
метод доступен с Windows XP и Windows Server 2003 (см. Примечания к msdn ).источник
Yield предлагает процессору остановить текущий поток и начать выполнение потоков с более высоким приоритетом. Другими словами, присвоение значения низкого приоритета текущему потоку, чтобы оставить место для более важных потоков.
НЕТ, оба будут давать разные результаты. Без yield (), как только поток получит управление, он выполнит цикл «Внутренний прогон» за один раз. Однако с yield (), как только поток получит управление, он один раз напечатает «Внутренний прогон», а затем передаст управление другому потоку, если таковой имеется. Если в очереди нет потока, этот поток будет возобновлен снова. Таким образом, каждый раз, когда выполняется «Внутренний прогон», он будет искать другие потоки для выполнения, и если поток недоступен, текущий поток будет продолжать выполнение.
yield () предназначен для предоставления места другим важным потокам, join () предназначен для ожидания, пока другой поток завершит свое выполнение, а interrupt () предназначен для прерывания выполняемого в данный момент потока для выполнения чего-то еще.
источник
Without a yield(), once the thread gets control it will execute the 'Inside run' loop in one go
? Просьба уточнить.Thread.yield()
заставляет поток перейти из состояния «Выполнение» в состояние «Выполнение». Примечание. Это не приводит к переходу потока в состояние «Ожидание».источник
RUNNING
состояния дляjava.lang.Thread
инстансов. Но это не препятствует естественному «запущенному» состоянию для собственного потока, для которогоThread
экземпляр является прокси.Thread.yield ()
присоединиться()
источник
yield () в основном используется для приостановки работы многопоточного приложения.
все эти различия в методах заключаются в том, что yield () приостанавливает поток во время выполнения другого потока и возвращается обратно после завершения этого потока, join () объединит начало потоков, выполняемых до конца, и другого потока, который будет запущен после того, как этот поток завершено, прерывание () остановит выполнение потока на некоторое время.
источник
yield
следует использовать.