pull/1/head
ruyu.li 3 years ago
parent ada13e0390
commit cc28f71d02

@ -118,7 +118,7 @@ AQS定义了一套多线程访问共享资源的同步模板解决了实现
![AQS的组成结构](images/JAVA/AQS的组成结构.png)
三部分组成:`state同步状态`、`Node组成的CLH队列`、`ConditionObject条件变量`包含Node组成的条件单向队列
三部分组成:`volatile int state同步状态`、`Node组成的CLH队列`、`ConditionObject条件变量`包含Node组成的条件单向队列
@ -186,7 +186,7 @@ CLH是AQS内部维护的FIFO先进先出双端双向队列方便尾部
### 流程概述
线程获取资源失败,封装成`Node`节点从`C L H`队列尾部入队并阻塞线程,某线程释放资源时会把`C L H`队列首部`Node`节点关联的线程唤醒(**此处的首部是指第二个节点,后面会细说**),再次获取资源。
线程获取资源失败,封装成`Node`节点从`CLH`队列尾部入队并阻塞线程,某线程释放资源时会把`CLH`队列首部`Node`节点关联的线程唤醒(**此处的首部是指第二个节点,后面会细说**),再次获取资源。
![AQS-流程](images/JAVA/AQS-流程.png)
@ -2837,7 +2837,12 @@ JVM可运行的CPU核数可以通过`Runtime.getRuntime().availableProcessors()`
## synchronized
synchronized是Java中的关键字是利用锁的机制来实现同步的。synchronized是一种 **互斥锁**它通过字节码指令monitorenter和monitorexist隐式的来使用lock和unlock操作synchronized 具有 **原子性** 和 **可见性** 。
`synchronized` 是依赖监视器 `Monitor` 实现方法同步或代码块同步的,代码块同步使用的是 `monitorenter``monitorexit` 指令来实现的:
- monitorenter指令是在编译后插入到同步代码块的开始位置
- monitorexit指令是插入到方法结束处和异常处的
任何对象都有一个 Monitor 与之关联,当且一个 Monitor 被持有后它将处于锁定状态。synchronized是一种 **互斥锁**它通过字节码指令monitorenter和monitorexist隐式的来使用lock和unlock操作synchronized 具有 **原子性** 和 **可见性** 。
共享资源代码段又称为**临界区**`critical section`),保证**临界区互斥**,是指执行**临界区**`critical section`)的只能有一个线程执行,其他线程阻塞等待,达到排队效果。
@ -2867,7 +2872,7 @@ synchronized是Java中的关键字是利用锁的机制来实现同步的。s
### Monitor
在多线程的 JAVA程序中实现线程之间的同步就要说说 Monitor。 Monitor是 Java中用以实现线程之间的互斥与协作的主要手段它可以看成是对象或者 Class的锁。每一个对象都有也仅有一个 monitor。下 面这个图,描述了线程和 Monitor之间关系 及线程的状态转换图:
在多线程的 JAVA程序中实现线程之间的同步就要说说 Monitor。 Monitor是 Java中用以实现线程之间的互斥与协作的主要手段它可以看成是对象或者 Class的锁。每一个对象都有也仅有一个 monitor。下面这个图描述了线程和 Monitor之间关系以及线程的状态转换图
![JAVA_Monitor](images/JAVA/JAVA_Monitor.jpg)
- **进入区(Entrt Set)**表示线程通过synchronized要求获取对象的锁。如果对象未被锁住则进入拥有者否则在进入等待区。一旦对象锁被其他线程释放立即参与竞争
@ -2921,11 +2926,9 @@ synchronized是Java中的关键字是利用锁的机制来实现同步的。s
### 锁升级
### 锁膨胀机制
`Java`中每个对象都拥有对象头,对象头由`Mark World` 、指向类的指针、以及数组长度三部分组成,本文,我们只需要关心`Mark World` 即可,`Mark World` 记录了对象的`HashCode`、分代年龄和锁标志位信息。
**Mark World简化结构**
`Java`中每个对象都拥有对象头,对象头由`Mark World` 、指向类的指针、以及数组长度三部分组成,本文,我们只需要关心`Mark World` 即可,`Mark World` 记录了对象的`HashCode`、分代年龄和锁标志位信息。**Mark World简化结构**
| 锁状态 | 存储内容 | 锁标记 |
| :------- | :------------------------------------------------------ | :----- |
@ -2939,38 +2942,56 @@ synchronized是Java中的关键字是利用锁的机制来实现同步的。s
#### 偏向锁
在大多数情况下锁总是由同一线程多次获得不存在多线程竞争所以出现了偏向锁其目标就是在只有一个线程执行同步代码块时降低获取锁带来的消耗提高性能可以通过J V M参数关闭偏向锁-XX:-UseBiasedLocking=false关闭之后程序默认会进入轻量级锁状态。线程执行同步代码或方法前线程只需要判断对象头的Mark Word中线程ID与当前线程ID是否一致如果一致直接执行同步代码或方法具体流程如下
HotSpot 作者经过研究实践发现,在大多数情况下,锁不存在多线程竞争,总是由同一线程多次获得的,为了让线程获得锁的代价更低,于是就引进了偏向锁。
偏向锁Biased Locking指的是它会偏向于第一个访问锁的线程如果在运行过程中同步锁只有一个线程访问不存在多线程争用的情况则线程是不需要触发同步的这种情况下会给线程加一个偏向锁。
**偏向锁执行流程**
当一个线程访问同步代码块并获取锁时,会在对象头的 Mark Word 里存储锁偏向的线程 ID在线程进入和退出同步块时不再通过 CAS 操作来加锁和解锁,而是检测 Mark Word 里是否存储着指向当前线程的偏向锁,如果 Mark Word 中的线程 ID 和访问的线程 ID 一致,则可以直接进入同步块进行代码执行,如果线程 ID 不同,则使用 CAS 尝试获取锁,如果获取成功则进入同步块执行代码,否则会将锁的状态升级为轻量级锁。具体流程如下:
![synchronized-偏向锁](images/JAVA/synchronized-偏向锁.png)
- 无锁状态,存储内容「是否为偏向锁(`0`)」,锁标识位`01`
- `CAS`设置当前线程ID到`Mark Word`存储内容中
- 是否为偏向锁`0` => 是否为偏向锁`1`
- 执行同步代码或方法
- 偏向锁状态,存储内容「是否为偏向锁(`1`、线程ID」锁标识位`01`
- 对比线程`ID`是否一致,如果一致执行同步代码或方法,否则进入下面的流程
- 若不一致,`CAS`将`Mark Word`的线程`ID`设置为当前线程`ID`,设置成功,执行同步代码或方法,否则进入下面的流程
- `CAS`设置失败,证明存在多线程竞争情况,触发撤销偏向锁,当到达全局安全点,偏向锁的线程被挂起,偏向锁升级为轻量级锁,然后在安全点的位置恢复继续往下执行
**偏向锁的优点**
#### 轻量级锁
轻量级锁考虑的是竞争锁对象的线程不多持有锁时间也不长的场景。因为阻塞线程需要C P U从用户态转到内核态代价较大如果刚刚阻塞不久这个锁就被释放了那这个代价就有点得不偿失所以干脆不阻塞这个线程让它自旋一段时间等待锁释放。
偏向锁是为了在无多线程竞争的情况下,尽量减少不必要的锁切换而设计的,因为锁的获取及释放要依赖多次 CAS 原子指令,而偏向锁只需要在置换线程 ID 的时候执行一次 CAS 原子指令即可。
**Mark Word**
当前线程持有的锁是偏向锁的时候,被另外的线程所访问,偏向锁就会升级为轻量级锁,其他线程会通过自旋的形式尝试获取锁,不会阻塞,从而提高性能。轻量级锁的获取主要有两种情况:① 当关闭偏向锁功能时;② 多个线程竞争偏向锁导致偏向锁升级为轻量级锁。
在 HotSpot 虚拟机中,对象在内存中存储的布局可以分为以下 3 个区域:
- **对象头Header**
- **实例数据Instance Data**
- **对齐填充Padding**
对象头中又包含了:
- **Mark Word标记字段我们的偏向锁信息就是存储在此区域的**
- **Klass PointerClass 对象指针)**
对象在内存中的布局如下:
![MarkWord-对象内存布局](images/JAVA/MarkWord-对象内存布局.jpg)
在 JDK 1.6 中默认是开启偏向锁的,可以通过“-XX:-UseBiasedLocking=false”命令来禁用偏向锁。
#### 轻量级锁
**轻量级锁考虑的是竞争锁对象的线程不多,持有锁时间也不长的场景**。因为阻塞线程需要CPU从用户态转到内核态代价较大如果刚刚阻塞不久这个锁就被释放了那这个代价就有点得不偿失所以干脆不阻塞这个线程让它自旋一段时间等待锁释放。当前线程持有的锁是偏向锁的时候被另外的线程所访问偏向锁就会升级为轻量级锁其他线程会通过自旋的形式尝试获取锁不会阻塞从而提高性能。
![synchronized-轻量级锁](images/JAVA/synchronized-轻量级锁.png)
- 无锁状态,存储内容「是否为偏向锁(`0`)」,锁标识位`01`
- 关闭偏向锁功能时
- `CAS`设置当前线程栈中锁记录的指针到`Mark Word`存储内容
- 锁标识位设置为`00`
- 执行同步代码或方法
- 释放锁时,还原来`Mark Word`内容
- 轻量级锁状态,存储内容「线程栈中锁记录的指针」,锁标识位`00`(存储内容的线程是指"持有轻量级锁的线程"
- `CAS`设置当前线程栈中锁记录的指针到`Mark Word`存储内容,设置成功获取轻量级锁,执行同步块代码或方法,否则执行下面的逻辑
- 设置失败,证明多线程存在一定竞争,线程自旋上一步的操作,自旋一定次数后还是失败,轻量级锁升级为重量级锁
- `Mark Word`存储内容替换成重量级锁指针,锁标记位`10`
**注意事项**
需要强调一点:**轻量级锁并不是用来代替重量级锁的**,它的本意是在没有多线程竞争的前提下,减少传统的重量级锁使用产生的性能消耗。轻量级锁所适应的场景是线程交替执行同步块的情况,如果同一时间多个线程同时访问时,就会导致轻量级锁膨胀为重量级锁。

@ -47,14 +47,15 @@ JVM试图定义一种统一的内存模型能将各种底层硬件以及操
**线程隔离数据区:**
- **程序计数器:** 当前线程所执行字节码的行号指示器
- **虚拟机栈:** 里面的元素叫栈帧,存储局部变量表、操作栈、动态链接、方法出口等,方法被调用到执行完成的过程对应一个栈帧在虚拟机栈中入栈到出栈的过程
- **程序计数器:** 一块较小的内存空间,可以看作是当前线程所执行字节码的行号指示器
- **虚拟机栈:** 里面的元素叫栈帧,**存储局部变量表、操作栈、动态链接、方法返回地址**等,方法被调用到执行完成的过程对应一个栈帧在虚拟机栈中入栈到出栈的过程
- **本地方法栈:** 和虚拟机栈的区别在于虚拟机栈为虚拟机执行Java方法本地方法栈为虚拟机使用到的本地Native方法服务
**线程共享数据区:**
- **方法区:** 可以描述为堆的一个逻辑部分,或者说使用永久代来实现方法区。存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据
- **堆:** 唯一目的就是存放对象的实例是垃圾回收管理器的主要区域分为Eden、From/To Survivor空间
- **元数据区**:常量池、方法元信息、
@ -796,6 +797,12 @@ GC Roots 是一组必须活跃的引用。用通俗的话来说,就是程序
#### 分区收集
## GC垃圾收集器
![收集器](images/JVM/收集器.jpg)
@ -872,23 +879,30 @@ Parallel Old 收集器是 Parallel Scavenge 的老年代版本,追求 CPU 吞
**主要流程如下**
- 初始标记(CMS initial mark)
- 并发标记(CMS concurrenr mark)
- 重新标记(CMS remark)
- 并发清除(CMS concurrent sweep)
- **初始标记(CMS initial mark)**仅标记出GC Roots能直接关联到的对象。需要Stop-the-world
- **并发标记(CMS concurrenr mark)**进行GC Roots遍历的过程寻找出所有可达对象
- **重新标记(CMS remark)**修正并发标记期间因用户程序继续运作而导致标记产生变动的那一部分对象的标记记录。需要Stop-the-world
- **并发清除(CMS concurrent sweep)**:清出垃圾
**优点**
**CMS触发机制**当老年代的使用率达到80%时就会触发一次CMS GC。
- `-XX:CMSInitiatingOccupancyFraction=80`
- `-XX:+UseCMSInitiatingOccupancyOnly`
**优点**
- 并发收集
- 停顿时间最短
**缺点**
**缺点**
- 并发收集占据一定CPU资源导致程序GC过程中变慢吞吐量下降
- 无法处理浮动垃圾可能出现”Concurrent Mode Failure“失败而导致另一次Full GC
- 因为基于”标记-清除算法“导致空间碎片过多可能因此在分配对象时引起另一次GC
- 并发收集**占据一定CPU资源**导致程序GC过程中变慢吞吐量下降
- **无法处理浮动垃圾**可能出现”Concurrent Mode Failure“失败而导致另一次Full GC
- 因为基于”**标记-清除算法**“导致空间碎片过多可能因此在分配对象时引起另一次GC
@ -904,16 +918,54 @@ Parallel Old 收集器是 Parallel Scavenge 的老年代版本,追求 CPU 吞
#### G1收集器
G1收集器中的堆内存被划分为多个大小相等的内存块Region每个Region是逻辑连续的一段内存结构如下
![G1-Region](images/JVM/G1-Region.png)
每个Region被标记了E、S、O和H说明每个Region在运行时都充当了一种角色其中H是以往算法中没有的它代表Humongous巨大的这表示这些Region存储的是巨型对象humongous objectH-obj当新建对象大小超过Region大小一半时直接在新的一个或多个连续Region中分配并标记为H。
**Region**
堆内存中一个Region的大小可以通过 `-XX:G1HeapRegionSize`参数指定大小区间只能是1M、2M、4M、8M、16M和32M总之是2的幂次方。如果G1HeapRegionSize为默认值则在堆初始化时计算Region的实际大小默认把堆内存按照2048份均分最后得到一个合理的大小。
**GC模式**
- **young gc**
发生在年轻代的GC算法一般对象除了巨型对象都是在eden region中分配内存当所有eden region被耗尽无法申请内存时就会触发一次young gc这种触发机制和之前的young gc差不多执行完一次young gc活跃对象会被拷贝到survivor region或者晋升到old region中空闲的region会被放入空闲列表中等待下次被使用。
- `-XX:MaxGCPauseMillis`设置G1收集过程目标时间默认值`200ms`
- `-XX:G1NewSizePercent`:新生代最小值,默认值`5%`
- `-XX:G1MaxNewSizePercent`:新生代最大值,默认值`60%`
- **mixed gc**
当越来越多的对象晋升到老年代old region时为了避免堆内存被耗尽虚拟机会触发一个混合的垃圾收集器即mixed gc该算法并不是一个old gc除了回收整个young region还会回收一部分的old region这里需要注意**是一部分老年代,而不是全部老年代**可以选择哪些old region进行收集从而可以对垃圾回收的耗时时间进行控制
- **full gc**
- 如果对象内存分配速度过快mixed gc来不及回收导致老年代被填满就会触发一次full gcG1的full gc算法就是单线程执行的serial old gc会导致异常长时间的暂停时间需要进行不断的调优尽可能的避免full gc
**G1垃圾回收器** 应用于大的堆内存空间。它将堆内存空间划分为不同的区域对各个区域并行地做回收工作。G1在回收内存空间后还立即对空闲空间做整合工作以减少碎片。CMS却是在全部停止(stop the world,STW)时执行内存整合工作。对于不同的区域G1根据垃圾的数量决定优先级。使用 `-XX:UseG1GCJVM` 参数来开启使用G1垃圾回收器。
![G1收集器](images/JVM/G1收集器.jpg)
**主要流程如下**
- 初始标记(Initial Marking)
- 并发标记(Concurrenr Marking)
- 最终标记(Final Marking)
- 筛选回收(Live Data Counting And Evacution)
- 初始标记(Initial Marking)标记从GC Root可达的对象。会发生STW
- 并发标记(Concurrenr Marking)标记出GC Root可达对象衍生出去的存活对象并收集各个Region的存活对象信息。整个过程gc collector线程与应用线程可以并行执行
- **最终标记(Final Marking)**标记出在并发标记过程中遗漏的或内部引用发生变化的对象。会发生STW
- 筛选回收(Live Data Counting And Evacution)垃圾清除过程如果发现一个Region中没有存活对象则把该Region加入到空闲列表中
`-XX:InitiatingHeapOccupancyPercent`当老年代大小占整个堆大小百分比达到该阈值时会触发一次mixed gc。

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

@ -1 +1 @@
<mxfile host="Electron" modified="2021-06-03T05:50:04.242Z" agent="5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/14.5.1 Chrome/89.0.4389.82 Electron/12.0.1 Safari/537.36" etag="IgTnOnY0u0pZWmU-kKFm" version="14.5.1" type="device"><diagram id="qJx3MESUr1q7judaKmlN" name="第 1 页">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</diagram></mxfile>
<mxfile host="Electron" modified="2021-08-03T01:47:08.757Z" agent="5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/14.5.1 Chrome/89.0.4389.82 Electron/12.0.1 Safari/537.36" etag="JPsBLjcFpA8YP234nJIB" version="14.5.1" type="device"><diagram id="qJx3MESUr1q7judaKmlN" name="第 1 页">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</diagram></mxfile>
Loading…
Cancel
Save