Есть Нить.сон(0) и Thread.доходность() высказывания эквивалентными?


эти два утверждения эквивалентны?

Thread.sleep(0);
Thread.yield();
12 55

12 ответов:

нет. Самое очевидное различие заключается в том, что sleep() кидает (проверено) InterruptedException. На практике эффект может быть почти таким же, но он полностью зависит от реализации.

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

Yield добавляет текущий поток в очередь готовности и позволяет запускать другие потоки. Сон не гарантирует отказ от процессора.

Это действительно зависит от платформы и версии JVM. Например, под Windows в JDK 5 (Hotspot), yield() буквально реализован как Sleep(0) - хотя сон 0 обрабатывается немного специально Windows, как я помню. Но в JDK 6, yield () реализуется как SwitchToThread ().

Я собрал некоторую информацию некоторое время назад на нить.выход (), включая некоторые детали реализации, которые могут представлять интерес. (Вы также можете увидеть материал на нить.сон() Я собрал на одном сайте.)

источник 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 ниток.доходность() следующий код:

  // 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 кажется, гораздо проще, чем os::sleep. Например: os::yield только для вызовов Linux sched_yield(). И os::sleep около 70 строк кода.

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

sleep (x) сообщает потоку JVM Планировщик, чтобы активно поставить это нитка спать и не запускать его снова до тех пор, пока прошло не менее x миллисекунд.

ни сна (), ни выхода () изменения что-нибудь о статусе блокировка синхронизации. Если ваша нить есть замок, и вы звоните спать(1000), тогда хотя бы секунда пройдет прежде чем ваша нить проснется. Когда это просыпается он может принять решение об освобождении замок-или он может держаться за нее длиннее.

источник: http://www.jguru.com/faq/view.jsp?EID=425624

в знаменитой книге Брайана Гетца "Java Concurrency in Practice" (опубликованной в 2006 году, но все еще принципиально действительной) говорится следующее по этому вопросу.

семантика потока.выход и нить.сон(0) не определено [JLS17.9]; в JVM является бесплатным для их выполнения, а нет-Ops или относиться к ним как планирование оттенками. В частности, они не обязаны иметь семантику sleep(0) в системах Unix - для этого поместите текущий поток в конец очереди выполнения приоритет, уступая другим потокам того же приоритета - хотя некоторые JVMs реализуют выход таким образом.

остальное можно найти на страницах документации.

нить.Yield может отказаться от ресурсов процессора для потоков с более низкими приоритетами, в то время как поток.Sleep (0) предоставляет процессор только потокам с равными или более высокими приоритетами.

по крайней мере на платформе Windows :)

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

Thread.Sleep() имеет немного большие накладные расходы, потому что он создает систему, которая включает в себя какой-то таймер, который разбудит процесс. (Зависит от реализации в основном)
Итог он будет называть Yield() в конце.

Thread.Yield() просто откажется от поворота нити и получит его в следующем раунде.

Thread.Sleep(0) может иметь оптимизацию, чтобы просто вызвать выход. (Опять же, реализация)

что yield() должен сделать, это сделать текущий поток вернитесь к runnable, чтобы разрешить другим потокам с тем же приоритетом теперь их очередь. Таким образом, намерение состоит в том, чтобы использовать yield() для продвижения изящного поворот среди потоков с равным приоритетом. На самом деле, однако, метод yield() не гарантирует выполнение того, что он утверждает, и даже если yield () приводит к тому, что поток выходит из работы и возвращается к runnable, нет никакой гарантии, что уступчивая нить не будет просто быть выбран снова над всеми остальными! Так что пока yield() может-и часто делает-делает Бегущий поток отказаться от своего слота для другого бегущего потока такого же приоритета нет никакой гарантии.

выход () никогда не заставит поток перейти к ожиданию / сну/ состояние блокировки. В большинстве, доходность() вызовет поток, чтобы перейти от бег до runnable, но опять же, это может не иметь никакого эффекта вообще.

источник: SCJP Sun сертифицированный программист книга

Это зависит от платформы и реализации, и они, вероятно, не эквивалентны.

ниже фрагмент, при использовании потока.sleep(0), большую часть времени дает выход:

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

тогда как при использовании потока.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();
}

нет, они не эквивалентны и кроме объяснений выше, Я думаю, что это необходимо, чтобы проверить 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.