0

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

如果一个类在被多个线程执行时能够正确运行,那么它就被认为是线程安全的。

我的 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();
    }

}
4

4 回答 4

9

Counter不是通过 3 个线程共享的,而是每个线程都有一个唯一的Counter

于 2013-04-06T14:34:35.137 回答
5

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

你的测试有点像如果你测试一座桥可以支持 20 辆卡车,只需要一辆汽车骑在桥上。它没有表现出任何东西。并且几乎不可能使用测试证明代码是线程安全的。只有仔细阅读和理解所有潜在问题才能保证这一点。一个非线程安全的程序可能运行良好多年,然后突然出现错误。

为了让您反击安全,请使用 AtomicInteger。

编辑 :

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

于 2013-04-06T14:36:02.730 回答
2

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

private static Counter counter = new Counter(); 

那么它就不是线程安全的,因为不同的线程可以同时修改计数器状态。

于 2013-04-06T14:37:27.017 回答
2

试试这个:

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

}

于 2016-09-30T10:55:54.483 回答