[英]How does method yield work?
在javadoc中有說yield方法
導致當前正在執行的線程對象暫時暫停並允許其他線程執行。
Katherine Sierra和Bert Bates的SCJP書中說過
yield()應該做的是使當前運行的線程返回runnable以允許具有相同優先級的其他線程輪到他們。
那么實際的方法是做什么的?
給定一個多線程應用程序, yield
將導致當前正在執行的線程暫停執行並設置為等待狀態。 然后,JVM將開始運行另一個先前處於等待狀態的線程。
我相信剛剛產生的同一個線程在技術上可以安排再次啟動。
而且我還沒有在野外看到這一點。 所以我覺得避免安全。
詳細說明:
在多線程環境中,線程是在JVM的意願下調度和打開的。 因此,即使在代碼中沒有調用yield,當JVM決定它應該時,你的線程可以/將自動屈服於其他線程。 這允許多線程在僅具有一個處理核心的環境中工作。
調用yield只是告訴JVM將當前線程置於等待狀態,即使JVM不會。
我將嘗試一個例子:
以下是隨着時間的推移執行2個線程的非常簡化的說明(假設1個核心) -
Thread\Time 1 2 3 4 5 6 7 8 9
Thread 1 ----------- ----- -------
Thread 2 ------- ---------- ------
每當你看到'-'
表示線程正在執行。 A ' '
表示線程正在等待。 如您所見,一次只能運行一個線程。 因此,當1次運行時,另一次等待。 要產生的收益是讓其他線程有機會在當前運行的線程之前運行。
線程可以處於准備狀態(可運行),阻塞狀態(例如,等待某些io完成)或運行; 這對於所有線程實現都是通用的,盡管某些特定實現可能具有更多狀態。
Yield會導致線程從運行更改為可運行,並等待調度程序將來再次將其更改為運行。 這就是SCJP書中的含義。
對於線程,它似乎暫停了一段時間,就像在javadoc中描述的那樣。 所以這兩個陳述都是正確的,只是用不同的措辭。
yield()
通常用於等待線程發生某些事情但不想用while(condition){ ...}
來阻止CPC周期。 yield()的工作方式因平台而異,取決於線程調度程序,您不應該依賴於它以特定方式運行。
它起源於合作多任務的時間。 基本思想是,處理器只執行一個線程,直到:
object.wait()
或Thread.sleep
,等待一些IO操作完成,等待某個對象監視器或類似操作。 Thread.yield()
。 在每種情況下,線程調度程序然后選擇另一個要執行的線程。 因此,為了公平對待其他線程,您可以在沒有任何阻塞操作的較長循環中定期調用yield()
。 (如果沒有其他線程准備好運行,則會再次安排相同的線程,因此不會造成很大的性能損失。)
在現代VM中,線程切換可以在任何點上發生,不僅這些列出的線程甚至可以同時執行,因此它不是必需的,並且一些VM可能完全忽略它(類似於System.gc()
。)
yield()方法用於確保應用程序中的所有相同優先級線程不會導致飢餓 。 例如,應用程序中存在五個線程,並且所有線程具有相同的優先級。 現在假設一個線程有機會運行,這個線程需要很長時間來完成它的任務,因此其他線程不會有機會運行。 所以為了避免這種情況,yield()就可以解救了。
最終,對yield()
的調用導致調用這樣的os方法,原則上它會將任務本身放回到運行隊列中並讓下一個任務運行( 源 ):
/**
* 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;
}
希望能幫助到你!
package yield;
public class ThreadYieldApp {
Thread th1 = new Thread("Thread 1") {
public void run() {
for(int i = 0; i <= 10; i++) {
System.out.println("Before Yield - " + Thread.currentThread().getName() + " at index - " + i);
//Currently pauses the thread and checks for other threads of same priority, and passes control to it based on Thread Scheduler pick
Thread.yield();
System.out.println("Currently running - " + Thread.currentThread().getName() + " at index - " + i);
}
}
};
Thread th2 = new Thread("Thread 2") {
public void run() {
for(int i = 0; i <= 10; i++) {
System.out.println("Currently running - " + Thread.currentThread().getName() + " at index - " + i);
}
}
};
public static void main(String[] args) {
ThreadYieldApp threadYieldApp = new ThreadYieldApp();
threadYieldApp.th1.start();
threadYieldApp.th2.start();
}
//Happy coding -- Parthasarathy S
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.