Java锁
《Linux内核设计与实现》
为什么内核系统调用比较慢?
0x80 硬中断信号, 系统函数调用
切换用户态和内核态,线程空间。
CAS 比较和交换 自旋锁 (ABA问题,加版本号检查) 乐观锁
LOCK_IF_MP
Java底层Unsafe C++内联 lock cmpxchg 汇编指令,在多核CPU机器上调用
lock 锁定CPU总线,无法被其他指令打断,lock指令在执行后面指令的时候锁定一个北桥信号。synchronized 同原理。(用户态汇编指令,不经过系统内核)
最终通过硬件级别锁总线,北桥信号
被volatile关键字修饰的变量也会存在一个 ‘lock:’ 的前缀
JOL (java object Layout)
Object 内存布局
org.openjdk.jol 查看内存布局的工具
ClassLayout.parseInstance(o).toPrintable();
字节数被8整除
markword (8字节 64位 记录锁信息,记录GC信息,记录 Identity HashCode)
class pointer 类指针
instance data
padding (需要被8整除)
给对象加锁,就是修改markword的值
对象分代年龄只占4位,G1,PS,PO等默认最高15
CMS 默认分代最多6
ZGS等没有分代
锁升级步骤
偏向锁(用户态 CAS 当前线程指针)–>轻量级锁(用户态 CAS)–>重量级锁(内核态)
Hotspot源码
为何会有偏向锁?
多数synchronized方法很多情况下只有一个线程在运行。
StringBuffer中的一些sync方法,Vector中的一些sync方法。
markword
*001 无锁态
*101 偏向锁状态
**00 轻量锁
**10 重量级锁
**11 GC回收中
偏向锁启用有延迟,JVM启动4秒之后(若启动时资源竞争激烈,则无必要启用偏向锁), 启动之前对象默认是没有偏向锁的。
95%的情况下不需要竞争(偏向锁) –> 竞争增加(2+线程竞争) –> 轻量锁(CAS自旋检查markword锁状态,消耗CPU)–> 竞争加剧(JDK1.6 10次以上自旋,CPU核数/2以上线程,需要调优;JDK 1.7+ 自适应自旋) –> 重量级锁(线程等待队列,不消耗CPU)
Epoch 批量重偏向,批量锁撤销。
锁升级会stw
锁重入:
synchronized可重入锁
LockRecord是栈帧里的一条记录,把markword复制了一份
可重入锁的加锁是在线程的栈帧中,每多一重锁,入栈一个Lock Record
AQS的state来记录重入的
JIT 即时编译器(Just In-Time)
volatile
static volatile int flag=false;
线程可见性(线程本地缓存)
禁止指令重排序 (指令重排序,CPU打破指令执行顺序,优化效率)
延迟初始化的DLC(Double Check Lock),会发生极低概率的bug。(百万级并发运行半年以上,对象半初始化时,发生了指令重排序,另一线程抢先拿到了尚未正常初始化的对象),通过对单例增加volatile防止情况发生。
JSR内存屏障,底层实现lock一条空指令
lock addl 0
底层c++通过lock指令对共享内存独占使用,
MESI(Modified已修改 Exclusive独占 Shared共享 Invalid 无效) 是缓存一致性协议的一种,是Intelx86使用的。
一个缓存行 64字节 8个long (工业折中值)
@sun.misc.Contended
public volatile long p1,p2,p3,p4,p5,p5,p6,p7;
public volatile long x = 0L
public volatile long p9,p10,p11,p12,p13,p14,p15;
分代回收算法
标记清除,复制,标记压缩
eden, survivor, survivor, tunured
新生代 大量死去,少量存活,采用复制算法(不同的垃圾回收器 Serial, ParallelScavenge, ParNew)
svuvivor 最大年龄,CMS默认年龄6,其他大都15 (不同的垃圾回收器 SerialOld, ParallelOld, CMS)
老年代 存活率高,回收较少,采用标记清除或标记压缩
内存越来越大,导致单线程Stop_The_World算法(SerialOld)代价太大,出现了多线程STW算法(ParalleOld)
内存继续增大,多线程STW算法消耗了过多的时间在线程切换上,于是出现了承前启后的CMS(concurrent mark sweep)回收算法(并发标记,并发清除)
Java 8 G1
Java 9 G1
Java 11 ZGC
Java 12 Shenadoah
Epsilon
什么是JVM调优
- 根据需求进行JVM规划和预调优
- 优化JVM运行环境(卡、慢)
- 解决JVM运行过程中的问题(OOM,内存泄漏)
定位内存泄漏:
jstack
jmap(arthas 无法取代的命令)
jsoncole
arthas
jps
top -Hp [PID]
jmap -histo [PID] | head -20 #按对象总数总占用空间大小逆序排列
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 using1174@foxmail.com
文章标题: Java锁
文章字数: 1,111
本文作者: Jun
发布时间: 2020-05-13, 22:04:00
最后更新: 2020-05-19, 11:23:58
原始链接: http://yoursite.com/2020/05/13/Java锁/版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。