JAVA面试题——volatile的理解

一、简介(请你谈谈对volatile的理解)

首先,volatile是Java虚拟机提供的轻量级的同步机制,他基本遵守了JMM的规范。
JMM模型:JMM内存模型描述

二、三大特性

volatile主要有三大特性:保证可见性,有序性(即禁止指令重排序),但是不保证原子性。

什么叫保证了可见性?

可见性:一个线程修改了主物理内存的值,其他线程马上获取主内存的值。

禁止指令重排序

有序性:为了提高性能,编译器和处理器都会对指令做重排,一般分为:
源代码-> 编译器优化的重排->指令并行的重排->内存系统的重排->最终执行的指令

单线程环境里面确保程序最终执行结果和代码顺序执行的结果一致。
处理器在进行重排序时必须要考虑指令之间的数据依赖性

多线程环境中线程是交替执行的,由于编译器优化重排的存在,两个线程中使用的变量能否保证一致性是无法确定的,结果无法预测。加入了volatile之后,就可以保证有序性。

不保证原子性

验证不保证原子性代码:

public class volatileDemo {
    public static void main(String[] args) {
        MyData myData = new MyData();

        for (int i = 1; i <= 20; i++) {
            new Thread(() -> {
                for(int j=1;j<=1000;j++){
                    myData.addPlusPlus();
                    myData.addMyAtomic();
                }
            },String.valueOf(i)).start();
        }
        while (Thread.activeCount()>2){
            Thread.yield();
        }
        System.out.println(Thread.currentThread().getName()+"\tAtomicInteger type,final number"+myData.atomicInteger);
    }
}
class MyData{
    volatile int number = 0;//没有使用volatile,则最后结果不会是20000

    public void addT060(){
        this.number =60;
    }
    public void addPlusPlus(){
        number++;
    }

    AtomicInteger atomicInteger = new AtomicInteger();
    public void addMyAtomic(){
        atomicInteger.getAndIncrement();
    }

}

如何解决?
1、加synchonized关键字;
分析:过重,不适合。
2、直接使用juc下AtomicInteger。
atomicInteger.getAndIncrement(); 解决了多线程环境下number++的问题;底层原理是CAS。
CAS原理:CAS原理描述

三、哪里有用过volatile?

单例模式DCL(Double Check Lock双端检锁机制),DCL机制不一定线程安全,原因是指令重排序的存在,加入volatile可以禁止指令重排。
原因在于某一个线程执行到第一次检测,读取到的instance不为null时,instance的引用对象可能没有完成初始化。
Instance = new SingletonDemo();可以分为以下三步完成。

扫描二维码关注公众号,回复: 8902975 查看本文章
Memory = allocate(); //1.分配对象内存空间
Instance(memory); //2.初始化对象
Instance = memory;//3.设置instance指向刚分配的内存地址,此时instance!=null

2和3不存在依赖关系,而且无论重排前还是重排后程序的执行结果在单线程中并没有改变。

发布了5 篇原创文章 · 获赞 0 · 访问量 47

猜你喜欢

转载自blog.csdn.net/qq_33805483/article/details/104099013