2013-04-06 108 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; 
} 

}