我正在学习编写线程安全程序以及如何评估非线程安全的代码。
如果一个类在由多个线程执行时正常运行,则该类被认为是线程安全的。
我的Counter.java不是一个线程安全的,但输出是按照预期从0到9打印所有3个线程。
任何人都可以解释原因吗?以及线程安全如何工作?
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();
}
}
答案 0 :(得分:9)
您的Counter
未通过3个主题分享,相反,每个主题都有唯一的Counter
答案 1 :(得分:5)
您的代码在特定测试中运行良好。这并不意味着它总能正常工作。尝试迭代很多次,你可能会开始看到异常。
你的测试有点像你测试过一座桥可以用一辆车骑在桥上就可以支撑20辆卡车。它没有展示任何东西。并且使用测试证明代码是线程安全的几乎是不可能的。只有仔细阅读和理解所有潜在的问题才能保证。一个非线程安全的程序可能会正常工作多年并突然出现错误。
为了使您的计数器安全,请使用AtomicInteger。
编辑:
另外,正如@SpringRush所说,你不是在线程之间共享一个计数器。每个线程都有自己的计数器。因此,您的代码实际上是线程安全的,但我认为它不会按照您的意图执行。
答案 2 :(得分:2)
所以这实际上是线程安全的。对于每个CountThread,都有一个计数器。要使其不是线程安全的,请将计数器变量更改为:
private static Counter counter = new Counter();
然后它不会是线程安全的,因为不同的线程可能同时修改计数器状态。
答案 3 :(得分: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;
}
}