【面试】Volatile常见面试题

大纲

  • 一、为什么有Volatile?
  • 二、Volatile是什么?
      • 1、volatile的作用是什么?
        • 追问1:volatile能保证原子性吗?为什么?
      • 2、说下volatile的应用场景?
        • 追问1:Volatile是否用得越多越好?
      • 3、之前32位机器上共享的long和double变量的为什么要用volatile? 现在64位机器上是否也要设置呢?
      • 4、happens-before等?
  • 三、Volatile怎么实现的?
  • 四、Volatile延申?
      • 1、synchronized和Volatile区别是什么?
      • 2、……
  • 五、参考

一、为什么有Volatile?

  • 类似:了解过JMM内存模型吗?
    1-详解java中的并发关键字volatile-https://zhuanlan.zhihu.com/p/86931805
    多线程环境下,一个共享变量可能存在于多个位置,如主内存、多个本地内存,可能带来数据不一致的问题。不一致有两方面原因,可见性和有序性。

  • 可见性
    一个线程对主内存数据进行了修改,而另外一个线程不知道,导致共享变量值不一样。

  • 有序性
    多线程交替执行,由于编译器优化重排的存在,变量无法保证一致性。

……处理器指令间的数据依赖性……

二、Volatile是什么?

1、volatile的作用是什么?

类似:什么是内存可见性?能否举例说明?什么又是重排序呢?能举例说明吗?

  • 可见性
    当一个线程改完一个共享变量会立刻刷新到主内存,并强制清空该变量的缓存数据,必须从主内存重新读取最新数据。
  • 有序性
    禁止指令重排序,在一定程度上保证有序性。
volatile关键字禁止指令重排序有两层意思:
1)当程序执行到volatile变量的读操作或者写操作时,在其前面的操作的更改肯定全部已经进行,且结果已经对后面的操作可见;在其后面的操作肯定还没有进行;
2)在进行指令优化时,不能将在对volatile变量的读操作或者写操作的语句放在其后面执行,也不能把volatile变量后面的语句放到其前面执行。

追问1:volatile能保证原子性吗?为什么?

  • 类似:i++为什么不能保证原子性?

不能完全保证,只能保证单次的读/写操作具有原子性。比如,i++,这是是一个复合操作:

  • 读取 i 值;
  • 对 i 加 1;
  • 将 i 值写回内存。

volatile无法保证这三个操作有原子性。

// 通过AtomicInteger或Synchronized来保证+1操作的原子性。

public class P0Test {
    private volatile  int value;  //将value变量声明成volatile类型
    public  void increment(){ //synchronized
        i++;
        System.out.println(i);
    }
    public static void main(String[] args) {
        final P0Test volatileTest1 = new P0Test();
        for(int i = 0; i < 100; i ++){
            new Thread(new Runnable() {
                @Override
                public void run() {
                    volatileTest1.increment();
                }
            }).start();
        }
    }
}

2、说下volatile的应用场景?

一次读一次写。

  1. 运算结果不依赖变量的当前值。
--》不能是自增量(如x++
  1. 变量不需要与其他的转态变量共同参与不变的约束。
--》不变的约束即为条件表达式(start < end),若表达式使用了两个及以上变量(不管是否是volatile变量)就无法保证正确性,即不变式会失效。

如:一写多读。

追问1:Volatile是否用得越多越好?

不是,可能导致总线风暴。 由于Volatile的MESI缓存一致性协议,需、要不断从主内存嗅探和CAS循环,无效交互会导致总线带宽达到峰值,所以不要大量使用Volatile。

3、之前32位机器上共享的long和double变量的为什么要用volatile? 现在64位机器上是否也要设置呢?

因为long和double操作可分为高32位和低32位两部分,因此普通long或double类型读/写可能不是原子。因此,家将共享long和double变量设置为volatile类型能保证任何情况下单次读/写操作的原子性。

4、happens-before等?

……

三、Volatile怎么实现的?

类似:底层原理是怎么实现的吗?怎么保证有序性的?volatile如何实现可见性?volatile如何实现有序性?

1、可见性
volatile变量修饰会出现Lock前缀指令,在多核处理器中会引发两件事:

  • 将当前处理器缓存行数据写回到系统内存
  • 然后使其他CPU里缓存了该内存地址的数据无效

2、有序性
Lock前缀指令相当于一个内存屏障/栅栏,让volatile上面、volatile修饰变量、volatile下面的执行顺序保持相对不变。

四、Volatile延申?

1、synchronized和Volatile区别是什么?

  • volatile本质是在告诉JVM当前变量在寄存器(工作内存)中的值是不确定的,需要从主存中读取;synchronized则是锁定当前变量,只有当前线程可以访问该变量,其他线程被阻塞住。
  • volatile仅能使用在变量级别;synchronized则可以使用在变量、方法和类级别的;
  • volatile仅能实现变量的修改可见性,不能保证原子性;而synchronized则可以保证变量的修改可见性和原子性;
  • volatile不会造成线程的阻塞;synchronized可能会造成线程的阻塞。
  • volatile标记的变量不会被编译器优化;synchronized标记的变量可以被编译器优化。

2、……

JVM的底层操作、字节码的操作、单例
为什么 AtomicInteger 可以保证原子性,怎么实现?

……

五、参考

  • 自己整理
    1、【面试】Volatile详解

  • 面试
    1、面试官没想到一个Volatile,我都能跟他扯半小时
    2、关键字: volatile详解
    3、Java面试官最爱问的volatile关键字

  • 主要内容
    1、Java多线程volatile详解
    2、Java 之 volatile 详解

  • 代码示例
    1、详解java中的并发关键字volatile

  • Geek
    1、33 | 并发中的编译技术(一):如何从语言层面支持线程?
    2、加餐 | 什么是数据的强、弱一致性?

你可能感兴趣的:(面试,java,职场和发展)