[英]How does yield work here?
方法Thread.yield
:
使當前正在執行的線程對象暫時暫停並允許其他線程執行。
因此,在以下代碼中:
public class Test implements Runnable {
private int stopValue;
public Fib(int stopValue){
this.stopValue = stopValue;
}
@Override
public void run() {
System.out.println("In test thread");
for(int i = 0; i < stopValue; i++){
c = i + 1;
}
System.out.println("Result = "+c);
}
public static void main(String[] args){
int defaultStop = 1024;
if(args.length > 0){
defaultStop = Integer.parseInt(args[0]);
}
Thread a = new Thread(new Fib(defaultStop));
System.out.println("In main");
a.setDaemon(true);
a.start();
Thread.yield();
System.out.println("Back in main");
}
}
我希望我應該看到:
In main
In test thread
其余的將是不確定的。 但是我不明白為什么有時我只看到: In main
和Back in main
而沒有來自Test
線程的任何打印語句?
yield()是對調度的操作系統的提示,但不能在調度方面提供任何保證。 它並不總是停頓很長時間。 如果您反復調用它,可能只需要幾微秒。
啟動線程需要時間,即使您的主線程短暫暫停,它也可能在后台線程啟動之前完成。
如您所見,yield()會非常短暫地暫停。
long start = System.nanoTime();
long runs = 20000000;
for (int i = 0; i < runs; i++)
Thread.yield();
long time = System.nanoTime() - start;
System.out.printf("Thread.yield() took an average of %,d ns.%n", time / runs);
版畫
Thread.yield() took an average of 148 ns.
相比之下,System.nanoTime在我的計算機上花費的時間更長。
long start = System.nanoTime();
long runs = 20000000;
for (int i = 0; i < runs; i++)
System.nanoTime();
long time = System.nanoTime() - start;
System.out.printf("System.nanoTime() took an average of %,d ns.%n", time / runs);
版畫
System.nanoTime() took an average of 656 ns.
兩種時間因操作系統而異,且因計算機而異。
好吧,yield()可能根本不執行任何操作,因為就緒線程的數量少於內核的數量,在這種情況下,兩個線程都可以運行,並且main()只會繼續運行到其正在運行的內核上操作系統發出(很可能會出現隊列)調用其內核間驅動程序以在另一個CPU內核上運行新線程。 然后是與'System.out.println'的交互-一個可能受互斥鎖保護的輸出流調用。
我無法快速找到關於yield()在不同的環境/ CPU / OS中實際作用的任何可理解的解釋,這是我從未使用過它的原因之一。 另一個是,無論它如何工作,我都無法想到有什么用。
在線程有機會啟動之前,主進程可能已經退出。 無法保證Thread.yield()
會強制線程在任何特定時間運行。 如果線程沒有啟動,則setDaemon()
將無效。
嘗試將Thread.yield()替換為:
try {
Thread.sleep(500);
} catch (InterruptedException ex) {
System.out.println(ex);
}
@Peter的答案很好,但我想添加一些其他信息作為答案。
首先,如其他地方所述, a.setDaemon(true)
使JVM在退出之前不等待Thread a
完成。 如果您真正的問題是如何在JVM關閉之前確保Thread a
能夠正常工作,則刪除setDaemon(true)
可能是解決方案。 JVM退出時,可以殺死守護程序線程。 非守護程序線程將等待。 因此main()
方法可能會返回並且主線程可能會退出,但是您的Thread a
仍將運行到完成。
正如您提到的,就Thread.yield()
,javadocs聲明:
使當前正在執行的線程對象暫時暫停並允許其他線程執行。
但是,這有點令人誤解。 例如,如果您的體系結構上有2個線程正在運行並且有2個或更多處理器,那么yield()
將實際上是無操作的。 運行隊列中沒有其他線程在等待處理器資源,因此可以快速重新計划主線程,並以最小的暫停繼續運行。
即使您在單個CPU系統上運行,並且Main
確實執行yield()
,您的Thread a
也會執行System.out
,即IO。 IO可能阻塞,導致線程執行立即切換回Main
。
歸根結底,只有在非常特殊的情況下才需要使用yield()
。 我已經做過很多多線程編程,但從未使用過。 始終建議您相信JVM線程調度將在時間分割方面“做正確的事”,除非您有探查器輸出或相反的專家建議。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.