美文网首页
JAVA内存模型

JAVA内存模型

作者: handsomemao666 | 来源:发表于2021-01-02 11:33 被阅读0次

    Java 虚拟机
    我们都知道 Java 语言的可以跨平台的,这其中的核心是因为存在 Java 虚拟机这个玩意。虚拟机,顾名思义就是虚拟的机器,这不是真实存在的硬件,但是却可以和不同的底层平台进行交互。而且 Java 虚拟机模拟的还比较全面,它想象了自己拥有硬件,处理器,寄存器和堆栈等,还具有相应的指令系统,以此来对接不同的底层操作系统。
    Java 内存模型(Java Memory Model)
    上次已经说过了底层硬件中内存的相关结构和处理,那同样的对于 Java 虚拟机这个“机器”来说,是不是也应该会有相应的结构呢?因为说到底虚拟机玩的再花,要什么有什么,最终还是要和底层 RAM 进行交互的嘛。
    怎么交互?这就是一个大问题,有一群专家就定义了一套规范,定义 Java 内存模型并不是一件容易的事情,这个模型必须定义得足够严谨,才能让 Java 的并发操作不会产生歧义;但是,也必须得足够宽松,使得虚拟机的实现能有足够的自由空间去利用硬件的各种特性(寄存器、高速缓存等)来获取更好的执行速度。
    Java 内存模型的主要目标是定义程序中各个变量的访问规则,即在虚拟机中将变量存储到内存和从内存中取出变量这样底层细节。此处的变量与 Java 编程时所说的变量不一样,只包括了实例字段、静态字段和构成数组对象的元素,但是不包括局部变量与方法参数,后者是线程私有的,不会被共享。
    Java 内存模型中规定了所有的变量都存储在主内存中,每个线程还有自己的工作内存(类比缓存理解),线程的工作内存中保存了该线程使用到主内存中的变量拷贝,线程对变量的所有操作(读取、赋值)都必须在工作内存中进行,而不能直接读写主内存中的变量。不同线程之间无法直接访问对方工作内存中的变量,线程间变量值的传递(通信)均需要在主内存来完成,线程、主内存和工作内存的交互关系如下图所示

    这个图和 CPU 与缓存的图非常类似,搞不好 JMM 的构建就是仿照硬件系统来的。同样的道理我们要思考一下在多线程的环境中,JMM 又是如何保证主内存和工作内存中的变量一致性?回忆一下 CPU 是如何保证缓存一致性的,使用 MESI 协议。那在这里呢,Java 内存模型就定义了 8 种操作和 8 个规则。
    回头想想,JMM 是一套规则呀,它只会给你定义规范,模型,具体的实现自己玩去!理解这一点很重要。我们来看看它给出了哪些操作和必须满足的规则吧。


    lock(锁定):作用于主内存的变量,把一个变量标识为一条线程独占状态。
    unlock(解锁):作用于主内存变量,把一个处于锁定状态的变量释放出来,释放后的变量才可以被其他线程锁定。
    read(读取):作用于主内存变量,把一个变量值从主内存传输到线程的工作内存中,以便随后的 load 动作使用
    load(载入):作用于工作内存的变量,把 read 操作从主内存中得到的变量值放入工作内存的变量副本中。
    use(使用):作用于工作内存的变量,把工作内存中的一个变量值传递给执行引擎,每当虚拟机遇到一个需要使用变量的值的字节码指令时将会执行这个操作。
    assign(赋值):作用于工作内存的变量,它把一个从执行引擎接收到的值赋值给工作内存的变量,每当虚拟机遇到一个给变量赋值的字节码指令时执行这个操作。
    store(存储):作用于工作内存的变量,把工作内存中的一个变量的值传送到主内存中,以便随后的 write 的操作。
    write(写入):作用于主内存的变量,它把 store 操作从工作内存中一个变量的值传送到主内存的变量中。
    如果要把一个变量从主内存中复制到工作内存,就需要按顺序地执行 read 和 load 操作,如果把变量从工作内存同步回主内存中,就要按顺序地执行 store 和 write 操作。Java 内存模型只要求上述操作必须按顺序执行,而没有保证必须是连续执行。也就是 read 和 load 之间,store 和 write 之间是可以插入其他指令的,如对主内存中的变量 a、b 进行访问时,可能的顺序是 read a,read b,load b, load a。Java 内存模型还规定了在执行上述八种基本操作时,必须满足如下规则:
    1 不允许 read 和 load、store 和write 操作之一单独出现
    2 不允许一个线程丢弃它的最近 assign 的操作,即变量在工作内存中改变了之后必须同步到主内存中。
    3 不允许一个线程无原因地(没有发生过任何 assign 操作)把数据从工作内存同步回主内存中。
    4 一个新的变量只能在主内存中诞生,不允许在工作内存中直接使用一个未被初始化(load 或 assign)的变量。即对一个变量实施 use 和 store 操作之前,必须先执行过了 assign 和 load 操作。
    5 一个变量在同一时刻只允许一条线程对其进行 lock 操作,lock 和 unlock 必须成对出现
    6 如果对一个变量执行 lock 操作,将会清空工作内存中此变量的值,在执行引擎使用这个变量前需要重新执行 load 或 assign 操作初始化变量的值
    7 如果一个变量事先没有被 lock 操作锁定,则不允许对它执行 unlock 操作;也不允许去 unlock 一个被其他线程锁定的变量
    8 对一个变量执行 unlock 操作之前,必须先把此变量同步到主内存中(执行 store 和 write 操作)

    相关文章

      网友评论

          本文标题:JAVA内存模型

          本文链接:https://www.haomeiwen.com/subject/cxleoktx.html