即使没有volatile,线程值也不会被线程缓存?

1 java multithreading volatile

class Counter
{
    public int i=0;
    public void increment()
    {
        i++;
        System.out.println("i is "+i);
        System.out.println("i/=2 executing");
        i=i+22;
        System.out.println("i is (after i+22) "+i);
        System.out.println("i+=1 executing");
        i++;
        System.out.println("i is (after i++) "+i);
    }
    public void decrement()
    {
        i--;
        System.out.println("i is "+i);
        System.out.println("i*=2 executing");
        i=i*2;
        System.out.println("i is after i*2"+i);
        System.out.println("i-=1 executing");
        i=i-1;
        System.out.println("i is after i-1 "+i);
    }
    public int value()
    {
        return i;
    } }

class ThreadA
{
    public ThreadA(final Counter c)
    {
        new Thread(new Runnable(){
            public void run()
            {
                System.out.println("Thread A trying to increment");
                c.increment();
                System.out.println("Increment completed "+c.i);
            }
        }).start();
    }
}
class ThreadB
{
    public ThreadB(final Counter c)
    {
        new Thread(new Runnable(){
            public void run()
            {
                System.out.println("Thread B trying to decrement");
                c.decrement();
                System.out.println("Decrement completed "+c.i);
            }
        }).start();
    }
}
class ThreadInterference
{
    public static void main(String args[]) throws Exception
    {
        Counter c=new Counter();
        new ThreadA(c);
        new ThreadB(c); 
    }
}
Run Code Online (Sandbox Code Playgroud)

在上面的代码中,ThreadA首先访问Counter对象并递增值并执行一些额外的操作.ThreadA第一次没有i的缓存值.但是在执行i ++之后(在第一行),它将获得缓存值.稍后更新值并获得24.根据程序,由于变量i不是易失性的,因此更改将在ThreadA的本地缓存中完成,

现在,当ThreadB访问decrement()方法时,i的值由ThreadA更新,即24.这怎么可能?

Jon*_*eet 5

假设线程不会看到其他线程对共享数据所做的每个更新都不合适,因为假设所有线程都会立即看到彼此的更新.

重要的是要考虑不看更新的可能性 - 不要依赖它.

除了没有看到来自其他线程的更新之外还有另一个问题,请注意 - 所有操作都以"读取,修改,写入"的方式运行...如果另一个线程在您阅读之后修改了该值,您基本上就会忽略它.

例如,假设i我们到达此行时为5:

i = i * 2;
Run Code Online (Sandbox Code Playgroud)

...但在其中途,另一个线程将其修改为4.

该行可以被认为是:

int tmp = i;
tmp = tmp * 2;
i = tmp;
Run Code Online (Sandbox Code Playgroud)

如果第二个线程i在"扩展"版本的第一行之后变为4,那么即使i是volatile,4的写入仍然会被有效地丢失 - 因为到那时tmp,它是5,它将加倍到10,然后10将被写出来.