2011-03-01 2 views
6

В Javadoc есть говорят, что метод доходностиКак работает метод?

Вызывает исполняемую в данный момент объект потока временно приостановить и позволить другим потокам выполнения.

И Кэтрин Сиерра и Берт Бейтс SCJP книга говорит, что

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

Так что же на самом деле метод делает?

+1

Я надеваю Здесь нет вопроса. Что вы не понимаете в документации, которую вы цитировали? –

+0

Я просто думаю, что потоки одного и того же приоритета не включают потоки с приоритетом выше одного, дают methof того, что было названо –

+4

Исходный код говорит, что все это 'public static native void yield();': p –

ответ

10

При использовании многопоточного приложения yield приведет к тому, что текущий исполняемый поток приостановит выполнение и будет установлен в состоянии ожидания. Затем JVM начнет запуск другого потока, который ранее находился в состоянии ожидания.

Я считаю, что тот же самый поток, который только что уступил, может быть спланирован, чтобы начать заново.

И мне еще предстоит увидеть это в дикой природе. Поэтому я думаю, что это безопасно.

Выработать:

В многопоточных нитей антуражей Запланированные и незапланированные выключить и по желанию JVM в. Таким образом, даже если доход не вызывается в коде, ваш поток может/будет автоматически уступать другим потокам, когда JVM решит, что это нужно. Это позволяет работать с несколькими потоками в среде с одним ядром обработки.

Вызывающий доход просто сообщает JVM о том, что текущий поток находится в состоянии ожидания, даже если JVM не подходит.

Постараюсь иллюстрацию:
Ниже приводится очень упрощенное представление исполнения 2 потоков с течением времени (предположим, 1 ядро) -

Thread\Time 1 2 3 4 5 6 7 8 9 
Thread 1 -----------  -----   ------- 
Thread 2    -------  ----------  ------ 

Всякий раз, когда вы видите '-' это означает, что поток является выполнения. A ' ' означает, что поток ожидает. Как вы можете видеть, только 1 поток может фактически запускаться одновременно. Итак, пока 1 работает, другой ждет. То, что нужно сделать, это дать другим потокам возможность бежать впереди текущего текущего потока.

+0

+1 Мне всегда было очень полезно думать о 'yield()' как о простом намеке на планировщик. (Я знаю, что это технически не подсказка, но во многом она ведет себя как одна.) – biziclop

+0

Согласно спецификации Java, 'yield()' может быть не-op. Если вы хотите заставить урожай, вы можете попробовать 'Thread.sleep (1)'. Однако только в очень редких случаях такое использование оправдано. –

+0

@ Не знаю, подтверждаете ли вы эту строку: «Я считаю, что тот же самый поток, который только что уступил, можно было бы спланировать, чтобы начать снова».? – jjnguy

1

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

Доходность приводит к тому, что поток изменяется от бега к runnable и ждет, пока планировщик изменит его на запуск снова, в будущем. Это то, что имеется в книге SCJP.

К нищете, похоже, что это временно приостановлено, как описано в javadoc. Таким образом, оба утверждения верны, иначе говоря.

1

yield() обычно используется, когда вы ожидаете нить, чтобы что-то произошло, но не хотите блокировать цикл CPC чем-то вроде while(condition){ ...}.Способ работы yield() отличается от платформы к платформе и зависит от Планировщика потоков, и вы не должны полагаться на то, что он ведет себя определенным образом.

1

Это происходит от времени совместной многозадачности. Основная идея заключается в том, что процессор не выполняет только один поток до:

  1. эта нить заканчивается
  2. эта нить делает некоторые операции блокировки, как object.wait() или Thread.sleep, ожидая какой-то операции ввода-вывода для завершения, ожидая какого-либо объекта монитор или аналогичный.
  3. этот поток вызывает Thread.yield().

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

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

+0

вы не указали блокировку IO и LockSupport.park, где поток может вылечить – bestsss

+0

@bestsss: упоминается блокировка ввода-вывода («ожидание завершения какой-либо операции ввода-вывода»), а LockSupport.park включен в «или аналогичный». Но я думаю, что этот метод (и класс) еще не существовал, когда yield() был необходим. –

+0

ŭlo, мое плохое, IO ускользнуло в голове. LockSupport был введен в 1.5 (метод эффективно вызывает 'Unsafe.park'), Thread.yeild доступен с момента создания Java. – bestsss

1

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

1

В конечном счете, призыв к yield() результатов в вызове методов Os, как это, что в принципе было бы поставить саму задачу обратно в очередь выполнения и пусть следующий запуск задачи (source):

/** 
    * sys_sched_yield - yield the current processor to other threads. 
    * 
    * This function yields the current CPU to other tasks. If there are no 
    * other threads running on this CPU then this function will return. 
    */ 
SYSCALL_DEFINE0(sched_yield) 
{ 
     /* 
     * lock this runqueue and disable interrupts. 
     */ 
     struct rq *rq = this_rq_lock(); 

     schedstat_inc(rq, yld_count); 
     current->sched_class->yield_task(rq); 

     /* 
      * Since we are going to call schedule() anyway, there's 
      * no need to preempt or enable interrupts: 
      */ 
     __release(rq->lock); 
     spin_release(&rq->lock.dep_map, 1, _THIS_IP_); 
     _raw_spin_unlock(&rq->lock); 
     preempt_enable_no_resched(); 

     schedule(); 

     return 0; 
} 
Смежные вопросы