目录
- 1、对象头
 - 2、原理Monitor
 - 3、原理之Synchronized
 - 4、原理之Synchronized进阶
 - 1)轻量级锁
 - 2)锁膨胀
 - 3)自旋优化
 - 4)偏向锁
 - 5)锁消除
 
1、对象头
64 位虚拟机
 在加锁的过程中,Mark Word中的62位将会指向操作系统的Monitor对象
 
2、原理Monitor

3、原理之Synchronized
static final Object lock = new Object();
static int counter = 0;
public static void main(String[] args) {
	 synchronized (lock) {
	 	counter++;
	 }
}
 
从字节码角度来分析synchronize的加锁原理:
 (由于字节码文件看不懂,暂时先记着,以后来回顾)
 
4、原理之Synchronized进阶
1)轻量级锁
轻量级锁的使用场景:
 如果一个对象虽然有多线程要加锁,但加锁的时间是错开的(也就是没有竞争),那么可以使用轻量级锁来优化。
 轻量级锁对使用者是透明的,即语法仍然是 synchronized
demo来进行解释
 假设有两个方法同步块,利用同一个对象加锁
    static final Object obj = new Object();
    public static void method1() {
        synchronized( obj ) {
            // 同步块 A
            method2();
        }
    }
    public static void method2() {
        synchronized( obj ) {
            // 同步块 B
        }
    }
 
-  
创建锁记录(Lock Record)对象,每个线程的栈帧都会包含一个锁记录的结构,内部可以存储锁定对象的Mark Word

 -  
让锁记录中 Object reference 指向锁对象,并尝试用 cas 替换 Object 的 Mark Word,将 Mark Word 的值存入锁记录

 -  
如果 cas 替换成功,对象头中存储了 锁记录地址和状态 00 ,表示由该线程给对象加锁,这时图示如下

 -  
如果 cas 失败,有两种情况
- 如果是其它线程已经持有了该 Object 的轻量级锁,这时表明有竞争,进入锁膨胀过程
 - 如果是自己执行了 synchronized 锁重入,那么再添加一条 Lock Record 作为重入的计数

 
 -  
当退出 synchronized 代码块(解锁时)如果有取值为 null 的锁记录,表示有重入,这时重置锁记录,表示重入计数减一

 -  
当退出 synchronized 代码块(解锁时)锁记录的值不为 null,这时使用 cas 将 Mark Word 的值恢复给对象头
- 成功,则解锁成功
 - 失败,说明轻量级锁进行了锁膨胀或已经升级为重量级锁,进入重量级锁解锁流程
 
 
2)锁膨胀
如果在尝试加轻量级锁的过程中,CAS 操作无法成功,这时一种情况就是有其它线程为此对象加上了轻量级锁(有竞争),这时需要进行锁膨胀,将轻量级锁变为重量级锁
- 当 Thread-1 进行轻量级加锁时,Thread-0 已经对该对象加了轻量级锁

 - 这时 Thread-1 加轻量级锁失败,进入锁膨胀流程 
  
- 即为 Object 对象申请 Monitor 锁,让 Object 指向重量级锁地址
 - 然后线程1自己进入 Monitor 的 EntryList BLOCKED

 
 - 当 Thread-0 退出同步块解锁时,使用 cas 将 Mark Word 的值恢复给对象头,失败。这时会进入重量级解锁流程,即按照 Monitor 地址找到 Monitor 对象,设置 Owner 为 null,唤醒 EntryList 中 BLOCKED 线程

 
3)自旋优化
重量级锁竞争的时候,还可以使用自旋来进行优化,如果当前线程自旋成功(即这时候持锁线程已经退出了同步块,释放了锁),这时当前线程就可以避免阻塞
自旋重试成功的情况
 
 自旋重试失败的情况
 
 
4)偏向锁
轻量级锁在没有竞争时(就自己这个线程),每次重入仍然需要执行 CAS 操作
Java 6 中引入了偏向锁来做进一步优化:只有第一次使用 CAS 将线程 ID 设置到对象的 Mark Word 头,之后发现这个线程 ID 是自己的就表示没有竞争,不用重新 CAS。以后只要不发生竞争,这个对象就归该线程所有
  static final Object obj = new Object();
    public static void m1() {
        synchronized( obj ) {
            // 同步块 A
            m2();
        }
    }
    public static void m2() {
        synchronized( obj ) {
            // 同步块 B
            m3();
        }
    }
    public static void m3() {
        synchronized( obj ) {
                
            // 同步块 C
        }
    }
 

偏向状态
 回忆一下对象头格式:
 
 现在已经不想看了,稍后会总结
撤销-调用对象的hashCode
5)锁消除
JIT即时编译器会对java字节码文件进行进一步优化,例如在不需要加锁的地方会进行一个锁消除的优化
 例如: 局部变量没有逃离方法作用域
public void b() throws Exception {
	 Object o = new Object();
	 synchronized (o) {
		 x++;
	 }
 }
                

















