- 一个对象虽被多个线程访问,但访问时间是错开的,不存在竞争
- 轻量级锁对使用者 是透明的, 语法:syncronized
- 对于两个方法,用同一个对象进行加锁
package com.dreamer.multithread.day03;
public class Demo01 {
public static void main(String[] args) {
new Thread(() -> Student.method01()).start();
}
}
class Student {
private static Object obj = new Object();
public static void method01() {
synchronized (obj) {
System.out.println("first method working");
method02();
}
}
public static void method02() {
synchronized (obj) {
System.out.println("second method working");
}
}
}
3. 加锁流程
3.1 创建锁纪录
- 创建锁记录(Lock Record)对象,每个线程的栈桢都会包含一个锁记录的结构,内部可以存储锁定对象的Mark Word
- 让锁记录中Object reference指向锁对象,并尝试用cas替换Object中的 Mark Word, 将Mark Word 中的值存入
- Object中,01代表无锁状态
- 如果cas交换成功,对象头中存储锁记录地址和状态00,表示由该线程给对象加锁
- Object中01就会变为00,代表轻量级锁
- 锁膨胀:如果是其他线程已经持有了该Object 的轻量级锁,表明有竞争,进入锁膨胀过程
- 锁重入:如果是自己执行了synchronized锁重入,那么再添加一个Lock Record作为重入计数
- 重入: 通过lock record和00,能发现是自己这个线程已经持有这个锁了,就会将锁记录变为null
- 当退出synchronized代码块时候,如果有取值为null的锁记录,表示有重入,这时重制锁记录,表示重入计数减一
- 当退出synchronized代码块时,锁记录不为null,这时使用cas将Mark Word的值恢复给对象头
- 成功则代表解锁成功; 失败说明轻量级锁进入了锁膨胀或者已经升级为重量级锁
- 如果在尝试轻量级加锁的过程中,CAS操作无法成功,可能是因为:其他线程为此对象加上了轻量级锁(有竞争),这时需要进行锁膨胀,将其他线程的锁变为重量级锁
- 当Thread-0 退出同步块时,使用cas将Mark Word的值恢复给对象头,失败进入重量级解锁流程
- 按照Monitor地址找到Monitor对象,设置Owner为null,唤醒EntryList中BLOCKED线程
- 重量级锁竞争的时候,还可以使用自旋来进行优化,如果当前线程自旋成功(即这个时候锁线程颐景退出了同步快,释放了锁),这时线程就可以避免阻塞
智能自旋: 1. java6之后,自旋是自适应的,比如对象刚刚的一次自旋成功,就认为自旋成功的概率大,就会多自旋几次 反之,就少自旋几次甚至不自旋 2. 自旋会占用cpu时间,单核自旋就是浪费,多核自旋才有意义 3. java7之后不能控制是否开启自旋功能



