Java volatile变量的行为不正确.

One*_*ero 6 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);
    }
}
Run Code Online (Sandbox Code Playgroud)

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

Gra*_*ray 9

任何人都可以解释为什么它在这里不起作用?由于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

正如您所看到的,即使已经发生了2个增量并且线程之间的值已经正确同步,竞争条件意味着该值仅增加1.请参阅这个漂亮的解释.这是另一个很好的答案:Java中的volatile int是否是线程安全的?

您应该使用的是AtomicInteger允许您从多个线程安全递增的内容.

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

  • @OneZero http://docs.oracle.com/javase/tutorial/essential/concurrency/atomic.html应该解释一下'volitile`的用途.不是这个. (2认同)