引入

【Java】什么是CAS、synchronized升级概述、偏向锁/轻量级锁详解 – 笔记-编程知识网

【Java】什么是CAS、synchronized升级概述、偏向锁/轻量级锁详解 – 笔记-编程知识网

CAS

【Java】什么是CAS、synchronized升级概述、偏向锁/轻量级锁详解 – 笔记-编程知识网
【Java】什么是CAS、synchronized升级概述、偏向锁/轻量级锁详解 – 笔记-编程知识网

【Java】什么是CAS、synchronized升级概述、偏向锁/轻量级锁详解 – 笔记-编程知识网

【Java】什么是CAS、synchronized升级概述、偏向锁/轻量级锁详解 – 笔记-编程知识网
【Java】什么是CAS、synchronized升级概述、偏向锁/轻量级锁详解 – 笔记-编程知识网
lock cmpxchg在硬件层面实现:在操作过程中不允许被其他CPU打断,避免CAS在写数据的时候被其他线程打断,相比操作系统级别的锁,效率要高很多。
加锁才能让多线程的访问变为序列化。

用户态和内核态

对于操作系统来说,普通程序希望操作硬件,需要进行申请。所有指令可以直接被操作系统内核直接访问,而用户进程想要访问硬件资源,需要通过操作系统才能访问。

内核态:执行在内核空间,能够访问所有指令
用户态:只能访问用户能够访问的指令

linux内核工作在ring0,用户进程工作在ring3

syncronized的升级:不同于早期,有时候只需要在用户态进行操作,不需要经过内核态。
int 0x80 向OS申请一个中断的调用
【Java】什么是CAS、synchronized升级概述、偏向锁/轻量级锁详解 – 笔记-编程知识网

markword

工具:JOL=Java Object Layout,添加 Maven 依赖:
【Java】什么是CAS、synchronized升级概述、偏向锁/轻量级锁详解 – 笔记-编程知识网
对象的内存布局:当new出一个对象之后,这个对象在内存是怎么分布的?
我们来看HotSpot的实现。

要求对象8字节对齐(对象大小字节数必须是8的整数倍,如果不是,补4个空字节)

8字节markword
4字节classpointer(默认)
4字节instance data(用于存储成员变量)

…关于类方法,方法放在虚方法表里,那是另外一个实现了。

【Java】什么是CAS、synchronized升级概述、偏向锁/轻量级锁详解 – 笔记-编程知识网
【Java】什么是CAS、synchronized升级概述、偏向锁/轻量级锁详解 – 笔记-编程知识网
那么,synchronized 做了什么事?
【Java】什么是CAS、synchronized升级概述、偏向锁/轻量级锁详解 – 笔记-编程知识网
结论:锁信息被记录在了markword里面
【Java】什么是CAS、synchronized升级概述、偏向锁/轻量级锁详解 – 笔记-编程知识网

JDK8 markword实现表:

【Java】什么是CAS、synchronized升级概述、偏向锁/轻量级锁详解 – 笔记-编程知识网

【Java】什么是CAS、synchronized升级概述、偏向锁/轻量级锁详解 – 笔记-编程知识网

锁升级初步

轻量级锁也叫自旋锁
【Java】什么是CAS、synchronized升级概述、偏向锁/轻量级锁详解 – 笔记-编程知识网
【Java】什么是CAS、synchronized升级概述、偏向锁/轻量级锁详解 – 笔记-编程知识网

偏向锁

【Java】什么是CAS、synchronized升级概述、偏向锁/轻量级锁详解 – 笔记-编程知识网
前提:
StringBuffer是同步的
多数代码段在实际运行时只有一个线程,所以没有必要设计竞争机制。

偏向锁
没有必要设计锁竞争机制时,只是把第一个访问的线程的id写到markword中,而不去真正的加锁

自旋锁
偏向锁时,有人来竞争锁了,现在操作系统把偏向锁撤销,进行自旋锁(轻量级锁)竞争
竞争方式:每个人在自己的线程内部生成一个自己LR(Lock Record锁记录),两个线程通过自己的方式尝试将 LR 写门上,竞争成功的开始运行,竞争失败的一直自旋等待。

重量级锁
当必须加锁时,markword中记录的是objectmonitor(JVM用C++写的一个Object)

class文件的字节码

monitorenter(sync开始时)
monitorexit(sync完成或发生异常)
【Java】什么是CAS、synchronized升级概述、偏向锁/轻量级锁详解 – 笔记-编程知识网

【Java】什么是CAS、synchronized升级概述、偏向锁/轻量级锁详解 – 笔记-编程知识网

锁重入

synchronized是可重入锁(在未解锁的情况下,可以多次被加锁)。
用来满足子类和父类都是sync的情况。
重入次数必须记录,因为要解锁几次必须要对应。

偏向锁实现:记录在线程栈里,自旋锁->线程栈->每重入一次,LockRecord+=1

重量锁实现:惊动了操作系统,记录在ObjectMonitor字段上

轻量级锁什么时候升级为重量级锁

【Java】什么是CAS、synchronized升级概述、偏向锁/轻量级锁详解 – 笔记-编程知识网

什么是偏向锁启动/未启动

为什么有自旋锁,还需要有重量级锁?
自旋是占用CPU时间,消耗CPU资源的。如果锁的时间长或者自旋线程多,CPU资源会被大量消耗。这是不划算的。在这种情况下,升级为重量级锁。重量级锁中有等待队列,拿不到锁的进入等待队列,不需要消耗CPU资源(比如竞争队列、执行队列、等待队列waitset)

偏向锁是否一定比自旋锁效率高?
不一定。在明确知道一个资源会有多线程竞争的情况下,偏向锁肯定会涉及锁撤销。这时候应给直接使用自旋锁。
JVM启动过程,会有很多线程竞争(明确知道),所以默认情况,JVM启动时不打开偏向锁(默认时延4秒)。一段时间之后再打开。可以使用Thread.sleep(5000);之后再new对象验证
【Java】什么是CAS、synchronized升级概述、偏向锁/轻量级锁详解 – 笔记-编程知识网

普通对象 怎么直接到 偏向锁?

批量重偏向与批量锁撤销
【Java】什么是CAS、synchronized升级概述、偏向锁/轻量级锁详解 – 笔记-编程知识网