multiThread修改了一个volatile变量,但是这个变量几乎不能接近10000

我几乎整个下午都在思考这个问题。为什么这个程序的 volatile 变量几乎不能接近 10000。代码如下:

public class TestModifyVolatile {
    volatile int count = 0;
    void m(){
        count++;
    }
    public static void main(String[] args) {
        List<Thread> threads = new ArrayList<>();
        TestModifyVolatile t = new TestModifyVolatile();
        for (int i=0;i<10000;i++){
            threads.add(new Thread(t::m,"t_"+i));
        }
        threads.parallelStream().forEach(e->e.start());
        threads.forEach(o->{
            try {
                o.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        System.out.println(t.count);
    }
}

大部分结果是9996 9998... 假设线程1先启动,线程1使变量count变为1。在上面描述的过程中。也许另一个线程与线程 1 同时启动,读取变量计数也是 0 并写回 1?这是我的猜测,但我无法证明

回答

count++即使count字段是可变的,增量操作也不是原子操作。实际上,它执行易失性读取,然后是易失性写入。在读取和后续写入之间,其他一些线程可以读取 的(初始)值count。所以你可以有以下交错:

   count is 100
   thread A:  read count -> 100
   thread B:  read count -> 100
   thread A:  write 101 to count -> 101
   thread B:  write 101 to count -> 101

你失去了一个增量。(

请注意,当前 JLS 中没有任何内容明确说明 volatile 增量是非原子的。但是,它遵循 JLS 17.4 为volatile字段的内存可见性属性指定的内容。

不可能使用单个2 volatile字段并且没有额外的同步来实现可靠的(线程安全的)计数器。使用AtomicInteger来代替。


1 - 可能有两个。我不知道。


以上是multiThread修改了一个volatile变量,但是这个变量几乎不能接近10000的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>