Java并发:奇怪的输出

时间:2016-03-20 20:20:38

标签: java multithreading concurrency

我正在使用Java线程,我编写了这个创建多个线程并运行它们的小程序。在每个线程中,值会多次递增。我使用了ThreadLocal类,因此没有争用资源。

来源:

class MyValueHolder {

    public static ThreadLocal<Integer> value = new ThreadLocal<Integer>()
    {
        protected Integer initialValue() {
            return 0;
        }
    };

    public static void increment() {
        value.set(value.get() + 1);
    }

    public static Integer get() {
        return value.get();
    }
}

class MyTask implements Runnable {

    public static int counter;

    public MyTask() {
        counter++;
    }

    public void run() {

        for(int i = 0; i < 100; i++) {
            MyValueHolder.increment();
        }
        System.out.println("MyTask " + counter + ", Value " + MyValueHolder.get());
    }
}

public class Main {

    public static void main(String[] args) {

        ExecutorService es = Executors.newCachedThreadPool();

        for(int i = 0; i < 5; i++) {

            es.execute(new MyTask());
        }

        es.shutdownNow();
    }
}

完成后输出大部分时间是这样的:

MyTask 5, Value 100
MyTask 5, Value 100
MyTask 5, Value 100
MyTask 5, Value 100
MyTask 5, Value 100

这是我期望看到的。

然而,有时我得到这样的东西:

MyTask 2, Value 100
MyTask 4, Value 200
MyTask 5, Value 300
MyTask 5, Value 100
MyTask 5, Value 100

现在这令人困惑。即使每个任务完全相同,为什么值会有所不同?

3 个答案:

答案 0 :(得分:5)

如果Runnable完成,则在添加所有Runnable之前,CachedThreadPoolExecutor会重用线程。如果发生这种情况,该线程的ThreadLocal也将被重用。

答案 1 :(得分:1)

如上所述,ThreadLocal正在重复使用。

对于计数器,请改用AtomicInteger并设置初始值。 counter ++不是一个原子操作,它的两个操作并不是线程安全的。

答案 2 :(得分:0)

线程会在你得到输出时继续运行你应该等待它们完成你可以尝试isAlive();与线程