2016-03-12 66 views
1

這是一個測試問題。我已經多次運行代碼並獲得相同的答案:999999.他們說,即使在編寫runLoop方法時出現同步,此代碼也不會每次都產生相同的結果。我錯過了什麼?非線程安全代碼意外地給出了可重複的結果

public class B extends Thread{ 
    static int a = 0; 

    public static void main(String[] Args){ 
     B MyB = new B(); 
     MyB.start(); 
     runLoop(1000000); 
     System.out.println(a); 
    } 

    public static synchronized void runLoop(int b){ 
     for(int i = 0; i<b; i++){ 
      a=i; 
     } 
    } 

    public void run(){ 
     runLoop(12345678); 
    } 
} 
+0

我跑了代碼不同的時間,總是得到不同的答案 –

+0

運行多個線程並報告結果後。 –

+0

@RomanC你回答我的評論?我跑了很多線程... –

回答

1

通常當你調用

SomeThread.start(); 

它需要一些時間才能正常啓動線程,讓正在執行這個命令來執行一些它的下一行線,像

SomeThread.start();//lets say it should print "A" 
System.out.print("B"); 

在很多情況下會打印BA而不是AB,這就是您的問題所在。

因此,如果您的代碼之前MyB線程將start(),主線程可以調用自己的runLoop(1000000);。然後MyB可以運行runLoop(12345678);但現在主線程可以執行System.out.println(a);這是不同步的方式訪問a所以它可能會顯示MyB多少次重複了的時候(因此兩個線程同時訪問a當前點可以給每個不同的結果當你運行你的應用程序)。

如果你說你總是有作爲響應999999那麼你何干很幸運,或者沒有向我們展示你的實際代碼(如在MyB.start();runLoop(1000000);之間還有其他的代碼,這可能需要足夠的時間來讓MyB.start()完成情況如TimeUnit.SECONDS.sleep(1);)。

+0

感謝您的回答。這是有道理的你說什麼。有一點是不清楚的。重新啓動計算機後,我確實得到了不同的結果。事情是,他們真的很小。數字(例如8589)與runloop作爲參數進行比較。你能解釋爲什麼嗎? – Lebowski

+0

我想我現在明白了。我們有兩個線程。如果我理解正確,他們每個人都可以「跳過」並執行不同的語句 – Lebowski

+0

@Lebowski「事情是他們真的是小數字(例如8589)」,它只是意味着'MyB.run()'正在執行'runLoop (12345678);'在主線程完成其'runLoop(1000000);'和代碼'System.out.println(a)'後執行''在同一時間執行。更確切地說,'MyB.run'能夠在'System'訪問它的'.out'字段之前迭代很少次,然後'a'被訪問,因爲我們需要知道它的值,然後才能調用.println(一)'。 – Pshemo

0

你缺少的事實,你無法證明你的代碼是通過運行它一堆倍確定性。你可以然而證明它不是確定性的。這是編寫多線程代碼的問題:根據個人偏見誤解結果太容易了。我們都這樣做。

還有別的東西怎麼回事:代碼通過start方法,這是正確的,代碼調用runLoop(調用runLoop()間接)直接在主要方法。這就是代碼不確定的原因 - 這是原始問題的答案。在main方法中顯式調用runLoop()不應該在那裏。所有主要應該做的就是開啓線程。

0

當推理線程安全問題時,很可能它在您的機器上工作。或者在正常情況下的許多機器上。但這並不意味着程序正常工作。實際上,「一直」運行的代碼在某些條件下可能會中斷。這裏

0

兩件事情 -

  1. 單線程模式 - 要爲確保獲得價值999999,您應該限制線程同時訪問它。在這種情況下,它的主線程和正在啓動的線程。您可以按前面的答案中的建議同步類 - synchronized(b.class)

  2. 多線程模型 - 由於您只能同步類的實例,所以類級資源仍然可以同時訪問。在這個輸出保證始終是相同的。