2013-04-06 111 views
0

我正在學習編寫線程安全程序以及如何評估非線程安全的代碼。Java線程安全計數器

如果一個類在由多個線程執行時正常工作,則該類被認爲是線程安全的。

我的Counter.java不是線程安全的,但是對於所有3個線程,輸出的打印效果都是0-9。

任何人都可以解釋爲什麼嗎?以及線程安全如何工作?

public class Counter { 

    private int count = 0; 

    public void increment() { 
     count++; 
    } 

    public void decrement() { 
     count--; 
    } 

    public void print() { 
     System.out.println(count); 
    } 

} 

public class CountThread extends Thread { 
    private Counter counter = new Counter(); 

    public CountThread(String name) { 
     super(name); 
    } 

    public void run() { 
     for (int i=0; i<10; i++) { 
      System.out.print("Thread " + getName() + " "); 
      counter.print(); 
      counter.increment(); 
     } 
    } 

} 

public class CounterMain { 

    public static void main(String[] args) { 
     CountThread threadOne = new CountThread("1"); 
     CountThread threadTwo = new CountThread("2"); 
     CountThread threadThree = new CountThread("3"); 

     threadOne.start(); 
     threadTwo.start(); 
     threadThree.start(); 
    } 

} 
+3

您正在使用每個線程不同的計數器對象,這就是爲什麼你沒有看到在這種情況下,任何線程安全問題。 – Leon 2013-04-06 14:35:38

回答

5

你的代碼運行在特定的測試罰款。這並不意味着它總能正常工作。嘗試迭代很多次,你可能會開始看到異常。

如果您測試一座橋可以支持20輛卡車,那麼您的測試有點像通過搭乘單車駕駛在橋上。它沒有展示任何東西。通過測試證明th代碼是線程安全的幾乎是不可能的。只有仔細閱讀和理解所有潛在的問題才能保證。一個非線程安全的程序可能會很好地工作多年,並突然有一個錯誤。

爲了讓您安全起見,請使用AtomicInteger。

編輯:

此外,由@SpringRush指出,你不能共享線程之間的一個計數器。每個線程都有自己的計數器。所以你的代碼實際上是線程安全的,但我認爲它不會做你打算做的事情。

+0

是的,只有在我發佈了我的答案的第一個版本後,我纔看到。我修好了它。 – 2013-04-06 14:38:15

+0

換句話說,每個線程中聲明的所有變量都不會受到影響? – youcanlearnanything 2013-04-06 14:41:28

+0

線程安全問題只發生在幾個線程之間共享某個狀態時。如果某個狀態只能被一個線程看到並觸及,那麼這個狀態就不會有任何線程安全問題。 – 2013-04-06 14:43:26

9

Counter不通過3個線程共享,相反,每個線程都有一個獨特的Counter

+0

也許你應該解釋*爲什麼這是更徹底的答案。 – BlackVegetable 2013-04-06 14:35:42

+1

(明顯的,因此省略)的解釋是,OP在每個線程中創建了一個唯一的Counter實例。 – 2013-04-06 14:39:22

+1

當然,我遵循推理。我只是不知道作者是否理解他的Counter實例的位置是如何使它成爲線程特定的。 (+1,我想。) – BlackVegetable 2013-04-06 15:05:13

2

所以這實際上是線程安全的。對於每個CountThread,都有一個計數器。爲了使它不是線程安全的,改變計數器變量:

private static Counter counter = new Counter(); 

那就不是線程安全的,因爲不同的線程可以在同一時間被修改的計數器狀態。

1

試試這個:

public class ThreadSafeCounter { 

    AtomicInteger value = new AtomicInteger(0); 

public ThreadSafeCounter(AtomicInteger value) { 
    this.value = value; 
} 

public void increment() { 
    value.incrementAndGet(); 
} 

public void decrement() { 
    value.decrementAndGet(); 
} 

public AtomicInteger getValue() { 
    return value; 
} 

}