2009-10-31 54 views
0
public class Test extends Thread{ 
    public void hello(String s){ 
     System.out.println(s); 
    } 
    public void run(){ 
     hello("I’mrunning..."); 
    }//endofrun() 
    public static void main(String [] args){ 
     Test t=new Test(); 
    System.out.println("always first"); 
     t.start(); 

     System.out.println("always second but why?"); 
    } 
} 

我已經運行了這段代碼30次。在java中的bug線程處理

爲什麼「總是第二,但爲什麼?」總是在控制檯上第二?當調用t.start()時,我們有2個線程。 (2堆):主線和第二線。所以「我正在運行」必須有時是控制檯上的第二個輸出。當我刪除「總是第一」輸出語句比兩個輸出左,行爲非確定性(這是它應該是這樣)

所以我的想法是錯誤的,爲什麼是System.out.println(「永遠第一「);影響併發性?

回答

5

通過首先將某些東西寫入控制檯,您可能會影響何時發生JIT編譯,甚至可能發生類型初始化。我不覺得完全不可思議的是,這樣的事情改變了觀察到的排序。如果程序在不同系統和不同JVM上的行爲略有不同,我不會感到驚訝。

事情是,這些順序中的任何一個都是完全有效的。你不應該依靠它是一個或另一個,如果它總是以相同的方式發生,它不是一個錯誤。 (或者說,它可能是 - 但它不一定是)

如果你想確保一個特定的順序,你需要明確地做到這一點 - 如果你不介意事情發生的順序,那麼就沒有問題:)

+0

當然,確定性行爲會使測試更加困難...... – 2009-10-31 16:44:22

-2

System.out.println("always first")永遠是第一位的,因爲它是第二個線程開始以前,所以它絕不會影響併發。

試着將「永遠第一」的一句t.start();,你可能會得到你期待什麼:)

1

我已經運行的代碼塊的30倍。

在每個操作系統和硬件組合上運行它70億次,然後報告您的發現。 30是永遠很低的價值。

爲什麼「總是第二,但爲什麼?」總是在控制檯上第二?

你有多少核心?大多數線程調度器都會偏好當前正在運行的線程而不是新生成的線程,尤其是在單核上,並且會盡可能延遲核心之間的同步線程(線程對象和System.out需要在OS線程之間傳遞)。

鑑於線程化並不是確定性的,大多數操作系統並不能保證公平性和時效性,它並不是以這種方式表現的錯誤。

如果要在線程之間進行顯式排序,則應該使用同步塊或java.util.concurrent中功能更強大的類。如果您想要非確定性行爲,但要允許其他線程運行,則可以使用Thread.yield()向調度程序發出提示。

public static void main (String [] args) 
{ 
    FirstThreadBug t = new FirstThreadBug(); 
    System.out.println ("always first"); 
    t.start(); 
    yield(); 
    System.out.println ("always second but why?"); 
} 
0

爲什麼「總是第二,但是爲什麼呢?「總是第二控制檯上?

這並不總是第二位。我設法在約5執行你的代碼的同時生產排序。這兩種排序都是有效的,並且線程調度取決於您的操作系統,並且可能JVM和硬件。還有

究竟什麼是錯誤的,我思考,爲什麼是的System.out.println(「永遠第一」);影響的併發

你的想法是正確的,你的實驗是誤導你;)