Java volatile变量不';我的行为不正确。 公共类读取 { 挥发性静态inti; 公共静态类myT扩展线程 { 公开作废运行() { int j=0; while(j

Java volatile变量不';我的行为不正确。 公共类读取 { 挥发性静态inti; 公共静态类myT扩展线程 { 公开作废运行() { int j=0; while(j,java,concurrency,volatile,Java,Concurrency,Volatile,有人能解释为什么它在这里不工作吗?因为我被声明为volatile,所以应该保护它不受内存不一致的影响 它是受保护的,但不幸的是,i++不是一个原子操作。它实际上是读取/增量/存储。因此,volatile不会将您从线程之间的争用条件中拯救出来。您可能会从程序中获得以下操作顺序: 线程#1读取i,得到10 紧接着,线程2读取i,得到10 线程#1将i增加到11 螺纹#2增量i至11 线程#1将11存储到i 线程2将11存储到i 如您所见,即使发生了2次增量,并且线程之间的值已正确同步,争用条件意味着

有人能解释为什么它在这里不工作吗?因为我被声明为volatile,所以应该保护它不受内存不一致的影响

它是受保护的,但不幸的是,
i++
不是一个原子操作。它实际上是读取/增量/存储。因此,
volatile
不会将您从线程之间的争用条件中拯救出来。您可能会从程序中获得以下操作顺序:

  • 线程#1读取
    i
    ,得到10
  • 紧接着,线程2读取
    i
    ,得到10
  • 线程#1将
    i
    增加到11
  • 螺纹#2增量
    i
    至11
  • 线程#1将11存储到
    i
  • 线程2将11存储到
    i
  • 如您所见,即使发生了2次增量,并且线程之间的值已正确同步,争用条件意味着该值只增加了1。请参见此。下面是另一个很好的答案:

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

    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);
        }
    }
    
    静态最终AtomicInteger i=新的AtomicInteger(0);
    ...
    
    对于(int j=0;jOnly
    i
    需要是一个
    AtomicInteger
    j
    是线程的纯本地线程。我不确定如何回答@OneZero。将其声明为
    volatile
    将不起作用,因为++不是原子的。您可以在每次更新它或使用
    AtomicInteger
    时对其进行同步。使其
    volatile
    还不够。@OneZero应该解释一下
    volitile
    的用途。不是这个。@OneZero非volitile读取可以从预写值中获取一些位,从后写值中获取一些位,但仅限于基础内存中大于
    字的类型。
    double
    是最常见的违例者。通常峰值时,大多数并发问题对于
    volatile
    来说太多了,所以请看
    synchronize
    wait
    。@Gray在这个千年期构建的任何东西上的实践中,可能是真的。不过,我不认为这是语言规范中的保证。也许更实际的保证是保留了写入顺序,因此如果您如果是
    double data
    volitile boolean ready
    以及先设置
    data
    再设置
    ready=true
    的代码,那么可以肯定的是,在看到
    ready
    变为true后,
    数据也会被设置,即使在不同的线程中也是如此。如果没有
    volatile
    k,这是不保证的eyword,您可以看到
    ready
    true,然后
    data
    的值可能没有从写入线程传播。
    static final AtomicInteger i = new AtomicInteger(0);
    ...
            for (int j = 0; j<1000000; j++) {
                i.incrementAndGet();
            }