Java基础 -----volatile

Volatile
1. 可见性: 当一个共享变量被volatile修饰时,它会保证修改的值会立刻被更新到主存,当有其他线程需要读取时,它会去内存中读取新值。而普通的共享变量不能保证可见性,因为普通共享变量被修改之后,什么时候写入主存是不确定的,当其他线程去读取时,此时内存中可能还是原来的旧值,因此无法保证可见性
另外: 通过synchronized和Lock也能保证可见性,synchronized和Lock能保证同一时刻只有一个线程获取锁然后执行同步代码,并且在释放锁之前会将对变量的修改刷新到主存当中,因此可以保证可见性

  1. 有序性: 在java内存模型中,允许编译器和处理器对指令进行重新排序,但重新排序过程不会影响到单线程程序的执行,却会影响到多线程并发执行的正确性。volatile禁止进行指令重排序,在一定程序上可以保证有序性

  2. volatile关键字无法保证对变量的操作的原子性。只能靠变量自身保证原子性。x=0,y=x,x++,其中只有x=10是原子性操作,y=x包含2个操作(先读取x,再讲x的值写入工作内存y中),x++包含3个操作(读取x的值,进行加1,写入心智)

  3. 原理和机制: 观察加入volatile关键字和没有加入volatile关键字时所生成的汇编代码发现,加入volatile关键字时,会多出一个lock前缀指令

每个线程在运行过程中都有自己的工作内存,会将变量的值拷贝一份放在自己的工作内存中,使用volatile会导致线程的工作内存中缓存变量的缓存行无效,需要重新从主存中读取变量(反映到硬件层的话,就是CPU的L1或者L2缓存中对应的缓存行无效)

代码举例

package com.volatiletest;

public class VolatileTest {
    public volatile int inc = 0;
    public void increase () {
        inc++;
    }

    public static void main(String[] args) {
        final VolatileTest test = new VolatileTest();
        for (int i = 0; i < 10; i++) {
            new Thread() {

                @Override
                public void run() {
                    for (int j = 0; j < 1000; j++) {
                        test.increase();
                    }
                }
            }.start();
        }
        while (Thread.activeCount() > 1) {
            Thread.yield();
        }
        System.out.println(test.inc);
    }
}

详细参考资料

猜你喜欢

转载自blog.csdn.net/miracle_8/article/details/79286902