ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

volatile相关面试点

volatile相关面试点 目录并发编程的三个重要特性1.volatile 的原子性、可见性、有序性2.volatile 深入解析3.volatile 和 synchronized并发编程的三个重要特性1. 原子性在一次操作或者多次操作中要么所有的操作全部得到执行并且不会受到任何因素的干扰而中断要么所有的操作都不执行。2. 可见性当一个线程对共享变量进行了修改那么另外的线程可以立即看到修改后的最新值。3. 有序性 指程序代码在执行过程中的先后顺序由于Java在编译期以及运行期的优化导致了代码的执行顺序未必就是开发者编写代码时的顺序。1.volatile 的原子性、可见性、有序性在java中对基本数据类型读取赋值操作都是原子性的对引用类型的变量读取和赋值的操作也是原子性的。PS1. 多个原子性的操作在一起就不是原子性操作了。2. 简单的读取和操作都是原子性将一个变量赋给另外一个变量的操作不是原子性的。总结volatile 关键字不具备保证原子性的语义。Java提供了三种方式来保证可见性1. 使用关键字 volatitle ,当一个变量被 volatile 关键字修饰时对于共享资源的读取操作会直接在主内存中进行当然也会缓存到工作内存中当其他线程对该共享资源进行了修改则会导致当前线程在工作内存中的共享资源失效所以必须从主内存中再次获取对于共享资源的写操作当然是先要修改工作内存但是修改结束后会立即将其刷新到主内存中。2. 使用 synchronized 关键字这个就不多说了3. 通过JUC提供的显式锁 Lock 。总结 volatile 关键字具有保证可见性的语义。有序性同可见性一样Java 使用了一模一样的这三种方式来保证有序性。总结 volatile 关键字具有保证顺序性的语义。2.volatile 深入解析被 volatile 修饰的实例变量或者类变量具备两层含义1. 保证了不同线程之间对共享变量操作时的可见性。也就是当一个线程修改 volatile 修饰的变量另外一个线程会立即看到最新的值。2. 禁止对指令进行重排序的操作。volatile 的变量规则 对一个变量的写操作要早于对这个变量的读操作。通过对 OpenJDK 下的 unsafe.cpp 源码的阅读会发现被 volatile 修饰的变量存在于一个 “lock;” 的前缀。“lock;” 前缀实际上相当于是一个内存屏障该内存屏障会为指令的执行提供以下几个保障确保指令重排序时不会将其后面的代码排到内存屏障之前。确保指令重排序时不会将其前面的代码排到内存屏障之后。确保在执行到内存屏障修饰的指令时前面的代码全部执行完成。强制将线程工作内存中值得修改刷新到主内存中。如果是写操作则会导致其他线程工作内存CPU Cache中的缓存数据失效。volatile 的使用场景使用 volatile 要充分利用它的可见性和有序性。但它不能代替 synchronized 因为 volatile 不具备原子性。3.volatile 和 synchronized一、使用上的区别volatile 只能用于修饰实例变量或者类变量不能用于修饰方法以及方法参数和局部变量、常量等。synchronized不能用于对变量的修饰只能用于修饰方法或者语句块。volatile 修饰的变量可以为 null synchronized同步语句块的 monitor 对象不能 为 null 。二、对原子性的保证volatile 无法保证原子性。由于 synchronized 是一种排他机制。因此被 synchronized 关键字修饰的同步代码是无法被中途打断的因此能保证代码的原子性。三、对可见性的保证两者均可以保证共享资源在多线程间的可见性但是实现机制完全不同。synchronized 借助于JVM 指令 monitor enter 和 monitor exit 对通过排他的方式使得同步代码串行化在 monitor exit 时所有共享资源都将会刷新到主内存中。相比较于 synchronized 关键字 volatile 使用机器指令偏硬件“lock”的方式迫使其他线程工作内存中的数据失效不得不到主内存中进行再次加载。四、对有序性的保证volatile 关键字禁止 JVM 编译器以及处理器对其进行重排序所以它能够保证有序性。synchronized 修饰的同步方法也可以保证有序性不过是通过程序的串行化执行换来的。五、其他volatile 不会使线程陷入阻塞。synchronized 关键字会使线程进入阻塞状态。六、volatile 深入解析被 volatile 修饰的实例变量或者类变量具备两层含义1. 保证了不同线程之间对共享变量操作时的可见性。也就是当一个线程修改 volatile 修饰的变量另外一个线程会立即看到最新的值。2. 禁止对指令进行重排序的操作。volatile 的变量规则 对一个变量的写操作要早于对这个变量的读操作。通过对 OpenJDK 下的 unsafe.cpp 源码的阅读会发现被 volatile 修饰的变量存在于一个 “lock;” 的前缀。“lock;” 前缀实际上相当于是一个内存屏障该内存屏障会为指令的执行提供以下几个保障确保指令重排序时不会将其后面的代码排到内存屏障之前。确保指令重排序时不会将其前面的代码排到内存屏障之后。确保在执行到内存屏障修饰的指令时前面的代码全部执行完成。强制将线程工作内存中值得修改刷新到主内存中。如果是写操作则会导致其他线程工作内存CPU Cache中的缓存数据失效。volatile 的使用场景使用 volatile 要充分利用它的可见性和有序性。但它不能代替 synchronized 因为 volatile 不具备原子性。
返回列表