2014-12-19 56 views
2

您可以複製粘貼下面的示例以在本地計算機上運行。我正在學習MultiThreading,並在線查看了這個例子。我很困惑,爲什麼添加的方法(在類Counter中)如果聲明爲同步時會有所作爲,則可以從中刪除同步的關鍵字,並且不會影響最終結果,因此我只是想知道服務的目的是什麼宣佈它同步在以下示例中聲明一個同步方法的目的是什麼

class Counter { 

    long count = 0; 

    public synchronized void add(long value) { 
     this.count += value; 
     System.out.println(count + "-" + Thread.currentThread().getName()); 
    } 
} 

class CounterThread extends Thread { 

    protected Counter counter = null; 

    public CounterThread(Counter counter) { 
     this.counter = counter; 
    } 

    public void run() { 
     for (int i = 0; i < 10; i++) { 
      try { 
       Thread.sleep(100); 
      } catch (InterruptedException ex) { 
       Logger.getLogger(CounterThread.class.getName()).log(Level.SEVERE, null, ex); 
      } 
      counter.add(i); 
     } 
    } 
} 

public class Example { 

    public static void main(String[] args) { 
     Counter counter = new Counter(); 
     Thread threadA = new CounterThread(counter); 
     Thread threadB = new CounterThread(counter); 
     Thread threadC = new CounterThread(counter); 

     threadA.start(); 
     threadB.start(); 
     threadC.start(); 
    } 
} 
+0

如果刪除了睡眠,並提高到100000000次迭代左右(所以它不會只是完成瞬間),並在最後打印計數器的值(主線程加入其他線程)之後,你會看到有所不同。 – immibis 2014-12-19 05:23:19

+0

@immibis是的,我做了一個類似的實驗,最終的結果是不是一件預期。 – 2014-12-19 05:52:01

回答

4

​​關鍵字可防止threadA,threadB和threadC同時執行這些操作。

  1. 讀數區域
  2. 附加價值
  3. 寫入次數場

如果刪除​​關鍵字,那麼你可以想像:理解this.count += value內部實現三個操作是很重要的以下事件序列:

  1. threadA讀數字段(0)
  2. threadB讀取計數字段(0)
  3. 的ThreadA增加值來計算從#(計數= 0從#1 +值= 1的例子)
  4. threadB增加值的計數(計數= 0 2 +值= 1的例子)
  5. 的ThreadA(從#3)
  6. threadB從#4(!寫入計數字段(11)寫入計數字段,因此,在#5的寫入操作丟失)
+0

啊哈,我明白了。目前去除同步不影響的代碼,但我想,如果值更新過程較長再有就是讀取從多個線程發生在同一時間的可能性。得到它了。非常感謝bkail。 – 2014-12-19 05:22:22

+1

是的,這是正確的,而墨菲定律說,當該代碼是在生產:-)它會發生。 – 2014-12-19 05:24:06

+0

墨菲是該死的權利! – 2014-12-19 05:25:42

4

聲明班級爲​​意味着,無論線程想要執行的方法必須首先獲取當前對象的鎖。該對象只有一個鎖,只有獲得它的線程才能執行該方法。其他線程必須等待鎖定線程完成。完成該方法後,正在執行的線程將釋放該鎖。

總之。​​關鍵字可確保在任何給定時間只有一個線程可以執行該方法。

同步對於以下類中很重要:(a)系統是多線程的; (b)該類具有可在該方法內更改的實例變量。多線程問題通常發生在兩個或更多線程同時執行相同的方法時。一個線程可以根據其輸入更改實例變量,而另一個線程可以看到這些更改。

在此特定示例中,實例變量count可能會出現問題。如果一個線程將它設置爲5,則第二個線程可能會出現並將其設置爲10.當第一個線程執行System.out.println調用時,它會打印一個值10 - 這是意外的行爲。

+0

我看到它可能會失敗。謝謝。 – 2014-12-19 05:22:52

3

使add()方法同步的原因很重要的是,該行:

this.count += value; 

不是原子動作。這真是編譯,因爲這(或類似):

long c = count; 
c = c + value; 
count = c; 

這應該是很明顯線程。

相關問題