簡體   English   中英

收益如何在這里工作?

[英]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");  
    }  

}

我希望我應該看到:

  1. 然后In main
  2. In test thread

其余的將是不確定的。 但是我不明白為什么有時我只看到: In mainBack 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM