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

由于 volatile 建立了happens-before关系,所以 i 的最终值应该严格地为 2000000。但是,实际结果与变量 i 没有 volatile 没有什么不同。谁能解释为什么它在这里不起作用?由于 i 被声明为 volatile,因此应保护它免受内存不一致的影响。

4

1 回答 1

10

谁能解释为什么它在这里不起作用?由于 i 被声明为 volatile,因此应保护它免受内存不一致的影响。

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

  1. 线程 #1 读取i,得到 10
  2. 紧接着,线程#2 读取i,得到 10
  3. 线程 #1i增加到 11
  4. 线程 #2i增加到 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();
        }
于 2013-04-29T23:41:35.173 回答