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,因此应该保护它不受内存不一致的影响。
答案 0 :(得分:8)
任何人都可以解释为什么它在这里不起作用?由于i被声明为volatile,因此应该保护它不受内存不一致的影响。
它受到保护,但不幸的是i++
不是原子操作。它实际上是读/增/存。所以volatile
不会让你免于线程之间的竞争条件。您可以从程序中获得以下操作顺序:
i
,得到10 i
,得到10 i
增加到11 i
增加到11 i
i
正如您所看到的,即使已经发生了两次增量并且线程之间的值已经正确同步,竞争条件意味着该值仅增加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();
}