2014-10-30 107 views
0

此代碼來自樣品OCP/SCJPJava線程啓動方法或方法

我真的不知道爲什麼Printx()運行之前被稱爲()。 以及爲什麼這是有保證的?

public class ConstructorOrRun extends Thread { 

    private int x = 2; 

    public ConstructorOrRun() throws Exception { 
     x = 5; 
     start(); 
    } 

    public void printX() throws Exception { 
     x = x - 1; 
     System.out.print(x); 
    } 

    public void run() { 
     x *= 2; 
    } 

    public static void main(String[] args) throws Exception { 
     // TODO Auto-generated method stub 
     new ConstructorOrRun().printX(); 

    } 

} 
+2

'extends Thread'是可怕的做法,除非你的意圖是改變線程的工作方式。不要那麼做。 – cHao 2014-10-30 02:32:35

+0

Nathan Hughes的「這將是糟糕的形式」答案有點輕描淡寫。您不能依賴測試來確定程序是否「線程安全」。在一個操作系統版本上測試不會告訴你它是否可以在不同的操作系統版本上運行。在一個JRE版本中測試不會告訴你它是否能夠在不同的JRE版本上工作,今天的測試可能不會告訴你它是否會在明天工作。如果一個程序的正確性取決於一場比賽的結果(例如,像在你的例子中設置x的比賽),那麼無論測試說什麼,該程序都是錯誤的。 – 2014-10-30 14:07:31

回答

3

ConstructorOrRun()立即在主線程上返回,然後調用printX()。

不能保證在構造函數中調用start()會導致run()開始,更不用說在構造函數返回之前完成(在另一個線程上)。事實上,如果確實如此,我會感到驚訝。

4

我不認爲'保證'在這裏是正確的詞。在實踐中,printx可能會首先完成,因爲starting a new thread takes a huge amount of time相對於當前正在運行的線程執行小算術運算所需的時間,獲取控制檯的(無爭用)鎖並寫入該鎖。

雖然這是一個競爭條件,但依靠任何一件事情都會是一個非常糟糕的主意。如果一個程序運行足夠多的時間,可能會發生各種交織。無法保證首先會發生哪些事情,最好避免做出假設。

還有另一個問題。構造函數由主線程調用,初始化x,然後啓動一個新線程。新線程修改run方法中的x,但沒有任何要求使x的內容對新線程可見。使x變爲volatile將使其內容可見。

還有一個問題:算術運算需要執行多個步驟,並可能被其他線程干擾。這不僅僅是首先發生哪種操作的問題,它們可以交錯。解決這個問題需要鎖定或使用atomicInteger。

+0

謝謝。這是比其他任何東西都更糟糕的問題...... – user3431327 2014-10-30 14:48:59

+0

@ user3431327:我不知道你在哪裏得到這個,但是這些問題測試了具體的目標,這對我來說並不明顯。 – 2014-10-31 02:03:58