并发编程---JMM模型

引言

在了解本文之前,我们知道所谓的并发编程就是平日中接触的多线程编程,既然扯到了多线程,那一定绕不开多线程的一些特性以及每个线程的结构或者说是线程的内存模型。接下来,我们从JMM(Java线程内存模型)来进行一些原理上的剖析。

多线程的关系分为三种:

1.同步:线程之间的协作
2.互斥:常见的互斥锁
3.分工:大任务的拆解

多线程经常遇到的问题:

1.死锁
2.资源共享问题
3.CPU调度问题(线程是由CPU来调度,JVM是没有权限的)
4.脏读
5.原子性问题

并发的特性是什么?本质又是解决什么问题呢?

其实答案可以归为一种,即是特性又是其解决的问题点,可分为下面三种:
1.原子性
2.可见性
3.有序性

JMM模型

JMM(Java Memory Model),即Java线程内存模型,它是一个抽象的概念。为何说是一个抽象的概念,因为JSR133定义的规范,并不是实际存在,它屏蔽了一些操作系统的差异,对其在任何OS上的执行概念做了一个通用的描述。

模型的作用

它定义了一组规则,通过这组规则控制各个变量在共享数据区域和私有数据区域的访问方式,JMM则是围绕原子性、有序性、可见性来展开的。

简单的JMM模型图
在这里插入图片描述

由此我们可以看到,每个线程都有各自的工作内存,也会与其他线程共享一个主内存,至于图中标注的共享标量副本,可以先看下主内存中的共享变量,思考一下它们之间的关系。

对于多个线程用到的共享变量,每个线程是将使用的共享变量拷贝副本到私有工作内存中来进行操作,操作完成会将新值回写到主内存中,我们可以再来细致的分析一下工作内存的结构,如图下所示

在这里插入图片描述

看到这幅图,如果对JVM有所了解的话,理解起来并不困难。因为JVM中五大区域,其中虚拟机栈是属于线程私有的,而里面每个执行方法或都是一个栈帧,里面方法内一些变量也都存在栈上

JMM与硬件内存架构的关系

为什么又要扯到硬件内存架构上呢?大家不妨来思考一下,JVM没有权限进行线程调度,那么是谁来控制着线程的上下文切换和执行顺序呢?

Java线程是内核级线程,其所有的调度都是CPU来控制的,当一个java线程启动,其实是映射到OS系统线程,再来调用内核线程来实现。这就是大家口中常说的:线程从用户态转为内核态
Java Thread >> OS Thread >> pthread_create

我们可以来初步的了解一下CPU的缓存架构,如下图:
在这里插入图片描述

从图上我们可以看出,我们的所有的操作都是要通过IO总线来向内存中写数据,然后再由CPU来进行读写,那么到底是CPU内部又是如何做到的一系列操作,这时我们就需要提到CPU寄存器与高速缓存

CPU寄存器与高速缓存

CPU缓存即高速缓冲存储器,是位于CPU与主内存间的一种容量较小但速度很高的存储器。由于CPU的速度远高于主内存,CPU直接从内存中存取数据要等待一定时间周期,Cache中保存着CPU刚用过或循环使用的一部分数据,当CPU再次使用该部分数据时可从Cache中直接调用,减少CPU的等待时间,提高了系统的效率。

在这里插入图片描述
图上所示为目前流程的多核CPU架构,可以看到每个CPU核里面都有独自的寄存器与L1、L2级别高速缓存,L3级也为三级缓存属于共享的。

寄存器相当于我们的栈帧来进行指令的执行,它在与主存还有一道中间过程,就是L1、L2、L3级高速缓存,可以看出
1.等级划分 L1 > L2 > L3
2.缓存速度 L1 > L2 > L3
3.缓冲区大小 L1 < L2 < L3

其实上面这三种关系我们可以从一个角度上来开始分析,就是缓冲区大小,如下图所示:

在这里插入图片描述
缓冲区越大,存储的变量就越多,对应的搜索范围越大,导致搜索时间就越长,最终导致其速度最慢,在上述描述中我们提到了一个名词“时钟周期”,指的就是不同级别的缓存对应查找的一个时间周期

在这里插入图片描述
当寄存器需要数据的时候如果从主存中获取,大概需要等待167个时钟周期,而从L1缓存中获取仅仅需要4个时钟周期,这其中提升的效率是非常明显的,所以

©️2020 CSDN 皮肤主题: 1024 设计师:上身试试 返回首页