Действительно ли эти два оператор эквивалентны?
Thread.sleep(0);
Thread.yield();
Нет, они не эквивалентны и помимо объяснений выше, я думаю, что необходимо проверить Javadoc yield
. Это кажется не хорошей идеей использовать yield
, если ниже ситуации не встречается.
It is rarely appropriate to use this method. It may be useful for debugging or testing purposes, where it may help to reproduce bugs due to race conditions. It may also be useful when designing concurrency control constructs such as the ones in the {@link java.util.concurrent.locks} package.
В книге известного Brian Goetz "Параллелизм Java на практике" (опубликованный в 2006, но все еще существенно допустимый) говорится следование этого вопроса.
семантика Thread.yield и Thread.sleep (0) не определена [JLS17.9]; JVM свободна реализовать их столь же без операций в секунду или рассматривать их как планирующие подсказки. В частности, они не обязаны иметь семантику сна (0) в системах Unix —, помещает текущий поток в конце очереди выполнения для того приоритета, уступая другим потокам того же приоритета —, хотя некоторые JVMs реализуют урожай таким образом.
Остальные можно найти на страницах Javadoc.
Thread.sleep () и Thread.yield () делают то же самое за исключением того, что Thread.yield () оставляет только потокам, работающим на том же процессоре в многопроцессорной среде.
Это - platform-and-implementation-dependent, и они вероятны не эквивалентные.
ниже отрывка, при использовании Thread.sleep (0), большую часть времени дает вывод:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
принимая во внимание, что при использовании Thread.yield (), главным образом дает:
[0, 1, 1, 1, 1, 1, 1, 1, 1, 1]
[0, 2, 2, 2, 2, 2, 2, 2, 2, 2]
Посмотрите отрывок ниже:
public class CompareSleepZeroAndYield {
private ArrayList<Integer> list1 = new ArrayList<>();
private ArrayList<Integer> list2 = new ArrayList<>();
public ArrayList<Integer> getList1() {
return list1;
}
public ArrayList<Integer> getList2() {
return list2;
}
public CompareSleepZeroAndYield() {
list1.add(0);
list2.add(0);
}
public void tryFieldLock1() {
synchronized (this.list1) {
list1.add(list2.get(list2.size() - 1) + 1);
}
}
public void tryFieldLock2() {
synchronized (this.list2) {
list2.add(list1.get(list1.size() - 1) + 1);
}
}
public static void main(String[] args) {
CompareSleepZeroAndYield obj = new CompareSleepZeroAndYield();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
int count = 10;
while (--count >0) {
obj.tryFieldLock1();
try {
Thread.sleep(0);
} catch (InterruptedException e) {
e.printStackTrace();
}
// compare above and below
// Thread.yield()
}
System.out.println(obj.getList1());
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
int count = 10;
while (--count >0) {
obj.tryFieldLock2();
try {
Thread.sleep(0);
} catch (InterruptedException e) {
e.printStackTrace();
}
// compare above and below
// Thread.yield()
}
System.out.println(obj.getList2());
}
});
t1.start();
t2.start();
}
Источник OpenJDK (Java SE 7) имеет следующую реализацию для Thread.sleep(0)
в JVM_Sleep
функция jvm.cpp:
if (millis == 0) {
// When ConvertSleepToYield is on, this matches the classic VM implementation of
// JVM_Sleep. Critical for similar threading behaviour (Win32)
// It appears that in certain GUI contexts, it may be beneficial to do a short sleep
// for SOLARIS
if (ConvertSleepToYield) {
os::yield();
} else {
ThreadState old_state = thread->osthread()->get_state();
thread->osthread()->set_state(SLEEPING);
os::sleep(thread, MinSleepInterval, false);
thread->osthread()->set_state(old_state);
}
}
И implemtation Thread.yield () имеют следующий код:
// When ConvertYieldToSleep is off (default), this matches the classic VM use of yield.
// Critical for similar threading behaviour
if (ConvertYieldToSleep) {
os::sleep(thread, MinSleepInterval, false);
} else {
os::yield();
}
Так Thread.sleep(0)
и Thread.yield()
может назвать те же системные вызовы в некоторых платформах.
os::sleep
и os::yield
платформа определенный материал. И на Linux и на Windows: os::yield
, кажется, много simplier, чем os::sleep
. Например: os::yield
из вызовов Linux только [1 113] sched_yield()
. И os::sleep
имеют приблизительно 70 строк кода.
то, Что урожай (), как предполагается, делает, заставляют в настоящее время рабочий поток возвратиться к выполнимому, чтобы позволить другим потокам того же приоритета получить их очередь. Таким образом, намерение состоит в том, чтобы использовать урожай () для продвижения корректного взятия поворота среди потоков равного приоритета. В действительности, тем не менее, урожай () метод, как гарантируют, не сделает то, чего он требует, и даже если урожай () действительно заставляет поток ступать из выполнения и назад к выполнимому, нет никакой гарантии, уступающий поток будет не просто выбран снова по всему другие! Таким образом, в то время как урожай () might— и часто does— заставляет рабочий поток бросить свой слот к другому выполнимому потоку того же приоритета, нет никакой гарантии.
урожай А () никогда не будет заставлять поток переходить к waiting/sleeping/блокирующему состоянию. Самое большее урожай () заставит поток идти от выполнения до выполнимого, но снова, это не могло бы иметь никакого эффекта вообще.
Источник: SCJP Сертифицированная Sun книга
Программиста