Java锁

  1. volatile
  2. 分代回收算法

《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调优

  1. 根据需求进行JVM规划和预调优
  2. 优化JVM运行环境(卡、慢)
  3. 解决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" 转载请保留原文链接及作者。

目录
×

喜欢就点赞,疼爱就打赏