掌握高并发、高可用架构
第二课 并发编程
从本课开始学习并发编程的内容。主要介绍并发编程的基础知识、锁、内存模型、线程池、各种并发容器的使用。
第六节 JAVA内存模型
JMM
内存模型
Java内存模型(Java Memory Model)规范了Java虚拟机与计算机内存是如何协同工作的。对于开发并发程序,理解Java内存模型是非常重要的。它规定了如何和何时可以看到由其他线程修改过的共享变量的值,以及在必要时如何同步的访问共享变量。
JMM内部原理
JMM把JVM内部划分为线程栈和堆。
每个运行在JVM中的线程都拥有自己的线程栈,这个线程栈包含了这个线程调用的方法当前执行点的相关信息。一个线程仅能访问自己的线程栈,线程创建的本地变量对其他线程不可见。
堆上包含Java程序中创建的所有对象,无论是哪个对象创建的,包括原始类型的对象版本。
一个原始类型的本地变量,它是在线程栈中的;
一个引用对象类型的本地变量,那么引用(这个本地变量)是在线程栈中,而引用的对象本身则是在堆中;
一个对象的方法内部的本地变量,仍然是在线程栈中的,即使方法所属的对象是在堆上;
一个对象的成员变量是在堆上,不管该变量是原始类型还是引用类型;
静态成员变量跟随类的定义一起存在堆上;
每个线程都有自己的工作内存,工作内存中保存了线程使用到的主内存中变量的副本
线程对变量的操作(读取、修改等)都必须在工作内存中进行,不能直接操作主内存
线程之间的值传递只能通过主内存来完成;不同线程之间无法访问对方的工作内存
协议
操作 | 解释 | 作用域 | 说明 |
---|---|---|---|
lock | 锁定 | 主内存 | 把一个变量表示为线程独占的状态 |
unlock | 解锁 | 主内存 | 把一个变量从线程独占的状态释放出来,释放后的变量才能被其他线程锁定 |
read | 读取 | 主内存 | 把一个变量从主内存传输到工作内存中 |
load | 载入 | 工作内存 | 把read操作的变量值放入工作内存的变量副本中 |
use | 使用 | 工作内存 | 把工作内存中的变量传递到执行引擎。当虚拟机遇到需要使用该<br />变量值的字节码指令时执行此操作 |
assign | 赋值 | 工作内存 | 把执行引擎来的值赋给工作内存的变量。当虚拟机遇到给变量赋值<br />的字节码指令时执行此操作 |
store | 存储 | 工作内存 | 把变量的值传到主内存 |
write | 写入 | 主内存 | 把store操作的值放到主内存的变量中 |
不允许read和load、store和write单独出现,即不允许变量从主存读取了但是工作内存不接受的情况;不允许从工作内存写回了但主存不接受的情况
不允许一个线程丢弃它最近的assign操作,即变量在工作内存修改后,就必须同步回主存
不允许一个线程无原因的把数据从线程的工作内存同步回主存,即没有assign就不允许写回主存
一个新的变量只能在主存中创建,不允许在工作内存中使用一个违背初始化的变量,即要use必须load,要store必须assign
一个变量在同一时刻只允许一个线程进行lock,但一个线程可以执行多次lock操作,多次lock后,必须执行相同次数的unlock,变量才能解锁
没有lock就不能unlock,也不允许unlock由其他线程锁住的变量
对变量unlock时,必须先把变量同步回主存,即store、wirte