2009-10-21 108 views

回答

39

號最明顯的區別是sleep()拋出(選中)InterruptedException。實際上,效果可能幾乎相同,但完全取決於實施。

因爲系統計時器粒度可能經常導致其實際睡眠時間不可忽視,因此我寧願每連續進行一百萬次睡眠()的時間也會多花費

+0

這是一個很好的觀點,由於粒度的原因,像睡眠(1)可能花費比1毫秒長得多的時間。 – 2009-10-21 12:56:41

+1

@Michael你寫道:「實際上,效果可能幾乎相同」。通過閱讀Javadocs,我不清楚問題本身的相關性,並且在實踐中無法理解*效果*可能如何兩個調用「Thread.sleep(0)'和'Thread.yield()'相同?不是'Thread.sleep(0)'意味着什麼都不睡?如果答案是肯定的,那麼它怎麼能等同於Thread.yield(),它只是向OS調度器發送一個信號來調度其他線程呢? – Geek 2013-09-13 14:08:27

+3

@Geek:要讓「睡覺(0)」實際上意味着「根本不需要睡眠」就需要額外的邏輯來使其成爲無操作,而不是象任何其他數字那樣對待0,在這種情況下,它意味着「去立即休眠並再次喚醒「 - 這也*讓OS安排其他線程。由於特別對待這個邊緣案例沒有明顯的好處,我希望大多數實現者不這樣做。 – 2013-09-13 14:27:05

31

Yield將當前線程添加到就緒隊列並允許其他線程運行。睡眠不保證放棄CPU。

+1

我認爲這是真正的多平臺的依賴比。看到我的帖子下面。 – 2009-10-21 13:53:13

+7

@NeilCoffey你知道帖子的順序是隨機的嗎? – Pacerier 2012-03-08 08:56:58

+0

'yield()'不能保證產生CPU,但是不會導致CPU放棄CPU的操作是不可思議的。 – EJP 2015-04-23 05:17:23

10

收益率()告訴JVM線程調度 ,它是確定給其他線程 時間片。通常JVM使用這個調用來激活 相同線程優先級的另一個線程。在良好的 搶佔式多線程環境中, yield()是無操作的。然而,這是一個合作的 多線程環境 重要的,因爲沒有 產量(),一個線程可以吃 所有的CPU。

睡眠(x)的講述了JVM線程調度 積極把這個線程 睡覺,而不是再次運行它,直到 至少x毫秒已經過去了。

睡眠()和收益()都不會改變 有關 同步鎖定狀態的任何信息。如果你的線程 有鎖,而你調用sleep(1000), 則至少第二所耗的時間 之前,你的線程醒來。當 喚醒它可能決定釋放 鎖 - 否則可能抓住它 更長的時間。

來源:http://www.jguru.com/faq/view.jsp?EID=425624

+1

非規範性參考。這很大程度上不在Javadoc中,關於'JVM線程調度程序'的部分多年來一直是虛構的。 – EJP 2015-04-23 05:18:37

1

Thread.Yield可以放棄CPU資源具有較低優先級的線程,而Thread.sleep代碼(0)放棄CPU只以相等的或較高優先級的線程。

至少在Windows平臺:)

+0

這是與事件調整線程優先級的方式來反擊優先級倒置嗎? – finnw 2011-01-28 13:19:41

+0

http://stackoverflow.com/a/8274138/632951似乎不同意你(在yielding)。誰是對的? – Pacerier 2012-03-08 08:58:58

+0

沒有這是Java規範所要求的, – EJP 2015-04-23 05:19:12

25

這真的取決於JVM的平臺和版本上。例如,在JDK 5(Hotspot)中的Windows下,yield()實際上被實現爲Sleep(0) - 雖然我記得Windows的睡眠稍微被Windows處理。但是在JDK 6中,yield()被實現爲SwitchToThread()。

我把一些信息前一陣子上Thread.yield(),包括一些實現細節可能會感興趣。 (您可能還想看看Thread.sleep()上的東西,我放在同一個網站上。)

0

Thread.Sleep()有一個稍大的開銷,因爲它會創建一個包含某種計時器的系統來喚醒進程。 (上實現取決於基本)
底線,它會調用到底Yield()

Thread.Yield()只需放棄該線程,並在下一輪獲得。

Thread.Sleep(0)可能會有一個優化來調用yield。 (同樣,實現)

+0

你說睡眠的開銷會大大增加,你在說什麼操作系統? – Pacerier 2012-03-08 08:59:46

0

什麼收益率()是應該做的是使當前運行的線程 頭回可運行以允許 相同優先級的其他線程得到輪到他們。所以打算使用yield()來促進優先級相同的線程之間的優雅轉換。但實際上,yield()方法並不能保證它所聲明的效果,即使yield()確實導致線程退出運行並返回到 可運行,但不能保證yielding線程獲勝只是 再次選擇所有其他人!因此,儘管yield()可能(通常是 )會使正在運行的線程將其插槽放棄到具有相同優先級的另一個可運行線程 ,但不能保證。

yield()永遠不會導致線程進入等待/睡眠/ 阻塞狀態。 yield()最多會導致線程從 運行到可運行,但它再次可能完全沒有效果。

來源:SCJP Sun認證程序員書

+0

有點不協調的非規範性參考,如果它不是'假設' 「保證」做到這一點? – EJP 2015-04-23 05:19:59

11

的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。 yield()有以下代碼:

// 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::sleepos::yield是平臺特定的東西。 在Linux和Windows上:os::yield似乎比os::sleep簡單得多。 例如:os::yield僅限Linux調用sched_yield()。並且os::sleep有大約70行代碼。

1

Thread.sleep()方法Thread.yield()做同樣的事情,除了Thread.yield()只能放棄在多處理器環境在同一處理器上運行的線程。

+0

聲明的來源是什麼? – 2015-05-18 07:43:09

+2

這是在.NET中的情況我不確定有關java。h TTPS://msdn.microsoft.com/en-us/library/system.threading.thread.yield(V = vs.110)的.aspx – 2015-05-20 09:42:47

4

着名的Brian Goetz的書「Java Concurrency in Practice」(2006年出版,但仍然基本有效)在這個問題上說了以下內容。

Thread.yield和Thread.sleep(0)的語義未定義[JLS17.9]; JVM可以自由地將它們實現爲無操作或將它們視爲調度提示。特別是,它們不需要在Unix系統上具有睡眠(0)的語義 - 將當前線程放在運行隊列的末尾以獲得該優先級,從而產生具有相同優先級的其他線程 - 儘管一些JVM在這條路。

其餘人可以在Javadoc頁面中找到。

0

它依賴於平臺和實現,它們可能不等效。

以下代碼段,使用了Thread.sleep時(0),大多數時候給出的輸出:

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

使用Thread.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(); 
} 
0

不,他們並不等同,除了上述的解釋, 我認爲有必要檢查yield的Javadoc。除非下面的情況符合,否則使用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.