Java线程安全计数器

Java线程安全计数器,java,multithreading,thread-safety,Java,Multithreading,Thread Safety,我正在学习编写线程安全的程序,以及如何评估非线程安全的代码 如果一个类在由多个线程执行时功能正确,则该类被认为是线程安全的 My Counter.java不是线程安全的,但是所有3个线程的输出都按预期从0到9打印 有人能解释为什么吗?线程安全是如何工作的 public class Counter { private int count = 0; public void increment() { count++; } public void

我正在学习编写线程安全的程序,以及如何评估非线程安全的代码

如果一个类在由多个线程执行时功能正确,则该类被认为是线程安全的

My 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个线程共享的,相反,每个线程都有一个唯一的计数器

您的代码在特定测试中运行良好。但这并不意味着它总是很好用。尝试多次迭代,您可能会看到异常

你的测试有点像,如果你测试一座桥可以支撑20辆卡车,只需驾驶一辆汽车。它没有证明什么。使用测试证明th代码是线程安全的几乎是不可能的。只有仔细阅读和理解所有潜在的问题才能保证这一点。一个非线程安全的程序可能会工作多年,突然出现错误

要使计数器安全,请使用AtomicInteger

编辑:


另外,正如@SpringRush所指出的,线程之间没有共享一个计数器。每个线程都有自己的计数器。因此,您的代码实际上是线程安全的,但我认为它并没有达到您想要的效果。

因此,这实际上是线程安全的。对于每个CountThread,都有一个计数器。要使其不是线程安全的,请将计数器变量更改为:

private static Counter counter = new Counter(); 
那么它就不是线程安全的,因为不同的线程可能会同时修改计数器状态。

尝试以下方法:

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;
}

}

您在每个线程中使用了不同的计数器对象,因此在本例中您没有看到任何线程安全问题。也许您应该解释为什么会出现这种情况,以便获得更彻底的答案。显而易见的,因此省略的解释是OP在每个线程中创建了一个唯一的计数器实例。当然,我会遵循推理。我只是不知道作者是否理解他放置反实例是如何使其特定于线程的+我想是的。是的,我是在发布了我答案的第一个版本后才看到的。我修复了它。换句话说,每个线程中声明的所有变量都不会受到影响?只有在多个线程之间共享某些状态时,才会出现线程安全问题。如果某个状态仅可见并被一个线程触及,则此状态不会有任何线程安全问题。确定。这是我写的一个无效的例子。