在正式学习JMM之前,我们先来说清楚 JMM和JVM之间有什么关系,我们把二者放在一起大概是因为 他俩名称上差不多,所以下意识联想到他们有什么某种关系。这里可以明确告诉大家,这二者之间的关系就是没有任何关系,两个不同层次的玩意。
JVM是对物理内存功能上的划分,比如创建的对象是在这一个块内存区域(堆),开启一个线程所占用的内存(虚拟机栈)。而JMM是一种抽象概念,对程序/线程在访问各种变量时的一种规范。就是遵守的规则。
接下来 我们从以下几个点来对JMM深入学习。
- JMM结构规范
- JMM三大特性
JMM结构规范
JMM规定了所有变量都存储在主内存中。每个线程还有自己的工作内存,线程的工作内存中保存了该线程使用到的主内存中变量的拷贝(简单来说,就是线程在访问共享变量时,会把主内存中的变量拷贝一份到自己的工作内存中,最后访问的是自己工作内存中的变量。)线程对变量的所有操作(赋值,读取等)都必须在工作内存中完成,而不能直接读写主内存中的变量。不同的线程之间也无法直接访问对方工作内存中的变量,线程之间值的传递需要通过主内存来完成
我们 通过JMM 只来讨论共享变量,就是那些在堆中的,每个线程都能访问的变量。比如 实例对象,静态变量等 而那些局部变量,方法定义的参数,这些都是不会在线程之间共享的,他们不会有内存可见性问题,当然也不受内存模型影响。
主内存和本地内存
JMM定义了主内存和线程的抽象关系,线程之间的共享变量存储在主内存中,每个线程都有一个私有的本地内存(上述说的工作内存),本地内存存储了读/写共享变量的副本。本地内存是一个抽象的概念,不是真实存在的。本地内存它涵盖了 缓存,写缓存区,寄存器等一些其他地方
JMM的三大特性
JMM的三大特性:原子性、可见性、有序性。
- 原子性:
- 一个操作不能被打断,要么全部执行完毕,要么不执行。在这点上有点类似于事务操作,要么全部执行成功,要么回退到执行该操作之前的状态。
- 可见性:
- 只要有一个线程对共享变量的值做了修改,其他线程都将马上收到通知,立即获得最新值。
- Java内存模型是通过将在工作内存中的变量修改后的值同步到主内存,在读取变量前从主内存刷新最新值到工作内存中,这种依赖主内存的方式来实现可见性的。
- 无论是普通变量还是volatile变量都是如此,区别在于:volatile的特殊规则保证了volatile变量值修改后的新值立刻同步到主内存,每次使用volatile变量前立即从主内存中刷新,因此volatile保证了多线程之间的操作变量的可见性,而普通变量则不能保证这一点。
- 除了volatile关键字能实现可见性之外,还有synchronized,Lock,final也是可以的。
- 有序性:
- 对于一个线程的代码而言,我们总是以为代码的执行是从前往后的,依次执行的。这么说不能说完全不对,在单线程程序里,确实会这样执行;但是在多线程并发时,程序的执行就有可能出现乱序。用一句话可以总结为:在本线程内观察,操作都是有序的;如果在一个线程中观察另外一个线程,所有的操作都是无序的。前半句是指“线程内表现为串行语义(WithIn Thread As-if-Serial Semantics)”,后半句是指“指令重排”现象和“工作内存和主内存同步延迟”现象。
- Java提供了两个关键字volatile和synchronized来保证多线程之间操作的有序性,volatile关键字本身通过加入内存屏障来禁止指令的重排序,而synchronized关键字通过一个变量在同一时间只允许有一个线程对其进行加锁的规则来实现。
开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 17 天,点击查看活动详情

