Java 中的 volatile
volatile 是Java虚拟机提供的轻量级的同步机制。
- 保证可见性
 - 不保证原子性
 - 禁止指令重排
 
可见性
当多个线程操作同一个变量时,每个线程都会将该变量拷贝一份到自己工作内存中,然后线程完成操作之后,将变量写回主内存。因此可见性就是一个线程在修改变量之后,回通知其他线程,告知改变量已经被修改了。
首先创建一个资源类
class MyData {
    volatile int number = 0;
    public void setNumber () {
        this.number = 60;
    }
    public void numberPlus() {
        this.number++;
    }
}
// 多线程下测试
public static void main(String[] args) {
   MyData myData = new MyData();
   new Thread(() -> {
            System.out.println(myData.number);
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            myData.setNumber();
            System.out.println(myData.number);
        }, "AAA").start();;
        while(myData.number == 0) {
        }
}
当使用 volatile 修饰 number 之后,程序回输出 0 和 60 之后执行完成退出。
当没有使用 volatile 修饰 number,程序回输出 0 和 60 之后一直保持执行(死循环),不退出。
由此可以看出,volatile 修饰的变量在修改后,回通知其他线程,保证可见性。
原子性
class MyData {
    volatile int number = 0;
    public void setNumber () {
        this.number = 60;
    }
    public void numberPlus() {
        this.number++;
    }
    AtomicInteger atomicInteger = new AtomicInteger(); // 默认为0
    public void atomicAdd() {
        atomicInteger.getAndIncrement();
    }
}
public static void main(String[] args) {
    MyData myData = new MyData();
    for(int i=0; i<20; i++) {
            new Thread(() -> {
                for(int j=0; j<1000; j++) {
                    myData.numberPlus();
                    myData.atomicAdd();
                }
            }, String.valueOf(i)).start();;
        }
        while(Thread.activeCount() >2) {
            Thread.yield();
        }
        System.out.println(myData.number);
        System.out.println(myData.atomicInteger);
}
程序输出 number 的值小于20000,atomicIntege r等于20000。
因为 volatile 不保证原子性,所以在多线程下操作 number 会出现值被覆盖的问题,也就是一个线程还没有完成++,另一个线程就取出了 number 进行++, 最后导致值小于了 20000。
解决 volatile 原子性问题,可以使用 AtomicInteger 。
指令重排
为了提高性能,编译器和处理器常常会进行指令重排,在多线程环境下,由于指令重排,导致代码的执行顺序和我们书写代码顺序不一致,最终变量能否保持一致是无法确定的,结果无法预测。

                
            
        
浙公网安备 33010602011771号