Java volatile变量的行为不正确。

时间:2013-04-29 23:39:37

标签: java concurrency volatile

public class MyThread
{
    volatile static int i;

    public static class myT extends Thread
    {
        public void run ()
        {
            int j = 0;
            while(j<1000000){
                i++;
                j++;
            }
        }
    }

    public static void main (String[] argv)
    throws InterruptedException{
            i = 0;

            Thread my1 = new myT();
            Thread my2 = new myT();
            my1.start();
            my2.start();

            my1.join();
            my2.join();

            System.out.println("i = "+i);
    }
}

由于在关系之前发生了易失性构建,因此i的最终值应该严格为2000000.但是,实际结果与变量i没有volatile的情况没有什么不同。任何人都可以解释为什么它在这里不起作用?由于i被声明为volatile,因此应该保护它不受内存不一致的影响。

1 个答案:

答案 0 :(得分:8)

  

任何人都可以解释为什么它在这里不起作用?由于i被声明为volatile,因此应该保护它不受内存不一致的影响。

它受到保护,但不幸的是i++不是原子操作。它实际上是读/增/存。所以volatile不会让你免于线程之间的竞争条件。您可以从程序中获得以下操作顺序:

  1. 线程#1读取i,得到10
  2. 之后,线程#2读取i,得到10
  3. 主题#1将i增加到11
  4. 线程#2将i增加到11
  5. 主题#1将11存储到i
  6. 线程#2将11存储到i
  7. 正如您所看到的,即使已经发生了两次增量并且线程之间的值已经正确同步,竞争条件意味着该值仅增加1.请参阅此nice looking explanation。这是另一个好的答案:Is a volatile int in Java thread-safe?

    您应该使用的是AtomicInteger,它允许您从多个线程安全地增加。

    static final AtomicInteger i = new AtomicInteger(0);
    ...
            for (int j = 0; j<1000000; j++) {
                i.incrementAndGet();
            }