一:摘要概述
- synchronized应用
- synchronized实现
- 偏向锁状态
- 轻量级锁与重锁
二:synchronized应用
场景 | 加锁对象 |
---|---|
静态方法 | 类Class对象 |
实例方法 | this对象 |
代码块 | 括号内对象 |
三:synchronized实现
一切皆对象的Java中synchronized也是用对象实现的锁,JVM中对象分为对象头
、实例数据
、对齐填充
,synchronized锁就存在与对象头中
对象头中有一块区域称之为Mark Word
,里面存储对象自身的一些运行时数据。包括hash值、GC年龄、锁状态标志等,Mark Down随着锁状态变化如下:
synchronized同步代码块
实现就是通过两个命令monitorenter
、monitorexit
,方法同步也是采用类似原理。两个命令必须成对出现 写一个如下简单demo后进入class字节码所在文件目录执行命令javap -v SynchronizedTest.class
反编译
public class SynchronizedTest {
private static final Object LOCK = new Object();
public static void main (String[] args) {
synchronized (LOCK){
System.out.println(123);
}
}
}
复制代码
有两个monitorexit并不奇怪,还有一个是在异常发生时执行。也就是synchronized代码块中发生异常会自动释放锁
四:偏向锁状态
synchronized经过JDK1.6的优化过后引入了偏向锁与轻量级锁,完整的synchronized加锁状态分为:无锁
、偏向锁
、轻量级锁
、重量级锁
4.1 偏向锁加锁
4.2 偏向锁释放
偏向锁的释放是在出现锁竞争时进行释放,当线程争抢锁资源时会暂停所有线程并取消偏向锁膨胀为轻量级锁
五:轻量级锁与重量级锁
轻量级锁的实现其实就是在执行同步代码块之前,JVM会会在当前线程的栈帧中创建锁记录空间,并且将Mark Work 区域内容复制到锁记录空间中。然后使用CAS尝试获取锁,成功则将Mark Work区域指针指向锁记录空间,失败则使用CAS自旋获取锁
轻量级锁的释放就是在自旋获取锁失败时,这时候锁就会膨胀为重量级锁。所有未获取锁线程进入等待状态。锁的优缺点对比如下图:
最后主要阐述一点:锁的整个膨胀过程不可逆