2016-06-10 42 views
-1

即使調用代碼塊已同步,競態條件也會發生。再次想到,這似乎是一個鎖定問題。請看看下面這個簡單的代碼塊(代碼將更好地解釋它) -Java線程:爭用條件vs同步

class CriticalSectionTest { 

    public void initWithSync() { 
     final CriticalSection cSection = new CriticalSection(); 

     Thread threadA = new Thread(new Runnable() { 
      @Override public void run() { 
       synchronized (cSection) { 
        cSection.add(2); 
        System.out.println(
          "Value after adding from thread-A: " + cSection.getCount()); 
       } 
      } 
     }); 

     Thread threadB = new Thread(new Runnable() { 
      @Override public void run() { 
       synchronized (cSection) { 
        cSection.add(3); 
        System.out.println(
          "Value after adding from thread-B: " + cSection.getCount()); 
       } 
      } 
     }); 

     threadA.start(); 
     threadB.start(); 

     //Desired output: 
     //A: 2 
     //B: 5 
    } 
} 

class CriticalSection { 
    private long count = 0; 

    public void add(long value) { 
     /* This method was not made synchronized, intentionally as its done in caller class 
     */ 
     this.count = this.count + value; 
    } 

    public long getCount() { 
     return count; 
    } 
} 

在多個運行,它打印下列輸出 -

這也不行

Value after adding from thread-B: 3 
Value after adding from thread-A: 5 

看起來不錯

Value after adding from thread-A: 2 
Value after adding from thread-B: 5 

任何解釋?還是我缺少一些基礎知識?

+3

同步不會確定執行順序。它只是保證線程不會同時執行代碼。如果您希望代碼按特定順序並按順序執行,請勿使用多個線程。 –

+1

另一種說法Andy Yassin在這裏已經說過的話:同步不是爲了防止數據競爭。這是爲了防止數據競爭做_harm_。如果你的程序如此嚴重同步以至於沒有數據競爭的可能,那麼你最好使它成爲單線程。 –

回答

3

同步不確定執行順序。它只是保證線程不會同時執行代碼。

調用Thread.start()不會立即調用Thread.run();它只是要求線程調度程序在將來的某個時刻運行它。你描述的行爲的解釋是線程調度器可能有時在線程A之前開始執行線程B.這是預期的行爲。

如果您希望代碼按特定順序和順序執行,那麼在單個線程中完成所有操作會更容易。

2

沒有關於每個線程的開始順序的安全。 Main線程將啓動線程一前一後,但沒有什麼能阻止以下內容:

THREAD A : START 
THREAD B : START 
THREAD A : WAIT 
THREAD B : RUN 
THREAD A : RUN 
THREAD A : STOP 
THREAD B : STOP 

threadB可以threadA有時前開始治療,這就是你面對的現在。