面试准备 --- volatile和JMM

面试准备,同样是学习的过程,无法保证正确,慎,欢迎纠正

正文

JMM

  • 原子性

    • 原子性指一个操作是不可被中断的.jvm定义了8中原子操作:

      • lock:将主内存中的变量锁定,为一个线程所独占

      • unclock:将lock加的锁定解除,此时其它的线程可以有机会访问此变量

      • read:将主内存中的变量值读到工作内存当中

      • load:将read读取的值保存到工作内存中的变量副本中。

      • use:将值传递给线程的代码执行引擎

      • assign:将执行引擎处理返回的值重新赋值给变量副本

      • store:将变量副本的值存储到主内存中。

      • write:将store存储的值写入到主内存的共享变量当中。

  • 一个很好的例子,i++;这个是操作系统课上必讲的内容.在操作系统的层面上,这个操作分为三个步骤,取出i的值,变量+1,重写回i的值.

  • 还有一个例子,就是在32位系统下,对于long和double的读写不是原子的.是分两步进行的,如果是多线程情况下,可能会读到不存在的数字,这也是面试题.

  • 可见性

    • 因为计算机硬件和编译器优化的原因,会存在缓存和寄存器作为CPU和内存之间的中间件.在串行程序中,不存在可见性的问题,在并发情况下,指令执行的顺序无法预估,很可能发生一个线程修改了实际值,但是缓存中的值还未修改,却被另一个线程读到了缓存中的值,造成数据不一致.
  • 有序性

    • 这个概念不难理解,但很难想到,至少我在接触并发的这些知识前,一度以为代码就是从前向后执行的,不是有顺序结构嘛.后来才知道重排序的事.
    • 重排序是虚拟机和操作系统会对指令进行一定的重排,在保证不破坏语义的串行性的情况下,优化指令的执行顺序.重排序虽然不可知,但是有很多原则:
      • 程序顺序原则:一个线程内保证语义的串行性
      • volatile规则:volatile变量的写先于读发生,保证可见性
      • 锁规则:解锁发生在另一个加锁前
      • 传递性:A先于B,B先于C,A先于C
      • 线程的start方法先于该线程的每一个动作
      • 线程的所有操作先于线程的终结
      • 线程的中断先于被中断的代码
      • 构造函数的执行,结束先于finalize方法
    • 并发情况下,一切情况都很难预料,实在无法理解,想想重排序的规则,也不用非要记住

volatile

  • 这个词的意思是"易变的",“不稳定的”,当使用这个关键字修饰一个变量时,就等于告诉虚拟机,这个变量很可能被程序修改,为了保证这个变量的修改被所有线程看到,虚拟机会采用一些手段,保证可见性
  • 比如我们上面说的重排序的规则之一:volatile变量的写先于读发生,保证有序性.保证可见性是通过每次访问刷新缓存,不会发生我们之前说到的,一个线程因为缓存和寄存器的原因读到未被写进内存的旧值.
  • 很重要的一个点,volatile无法保证原子性,即使保证了可见性和有序性,但如果使用类似i++的操作,还是无法得到想要的结果.

猜你喜欢

转载自blog.csdn.net/qq_36865108/article/details/86675271
今日推荐