1. 锁分类
无锁->偏向锁->轻量级锁->重量级锁
synchronized属于重量级锁,monitor是基于底层os的mutex Lock实现了,挂起线程和恢复线程都需要内核态完成,都需要切换CPU状态来完成。
Monitor与对象以及线程如何关联?
  1.对象被某个线程锁住,则该对象
 
 
2. synchronized锁升级流程
synchronized用的锁依赖释放偏向锁标志位和锁标志位。
- 偏向锁:MarkWord存储的是偏向的线程ID。
 - 轻量锁:MarkWord存储指向线程栈中Lock Recoard的指针。
 - 重量锁:MarkWord存储的是指向堆中的monitor对象的指针。

 
3. 偏向锁
 单线程竞争:当一段同步代码一直被同一个线程多次访问,后续访问自动获取锁。
 偏向锁默认有4s的延迟。
  竞争出现才释放偏向锁。
  Java 15取消了偏向锁。
 
4. 轻量级锁
 当有另外线程逐步来竞争锁的时候,偏向锁会升级为轻量级锁。
  竞争线程尝试CAS更新对象头失败,会等待到全局安全点 (此时不会执行任何代码) 撤销偏向锁。
 
 轻量级锁的加锁
  JVM会为每个线程在当前线程的栈帧中创建用于存储记录的空间,即Displaced Mark Word。若一个线程获得锁时,发现是轻量级锁,会把锁的MarkWord复制到Displaced Mark Word里面。然后尝试用CAS将锁的Mark Word替换为指向锁记录的指针。
  成功,当前线程获得锁。失败,表示Mark Word已经被替换成了其他线程的锁记录,说明在与其他线程竞争锁,当前线程就尝试使用自旋来获取锁。
 轻量级锁的释放
  在释放锁时,当前线程会使用CAS操作将Displaced Mark Word的内容复制回锁的Mark Word里面。
  没有竞争,那么这个复制的操作会成功。如果其他线程因为自旋多次导致轻量级锁升级为重量级锁,那么CAS操作会失败,此时会释放锁并唤醒被阻塞的线程。
5. 重量级锁
 有大量线程参与锁的竞争,冲突性很高。
  synchronized的重量级锁基于进入和退出Monitor对象实现的。在编译时会将同步块的开始位置插入monitor enter指令,在结束位置插入monitor exit指令。
  当线程执行到monitor enter指令时,会尝试获取对象所对应的Monitor所有权,如果获取到了锁,会在Monitor的owner中存放当前线程的id,这样它将处于锁定状态,除非退出同步块,否则其他线程无法获取到这个Monitor。
  指向互斥量的指针。
6. 锁和哈希码
 不推荐修改hashCode。
  当一个对象计算过hashCode后,再也无法进入偏向锁状态。
  偏向锁过程中遇到一致哈希计算请求,立马撤销偏向模式,膨胀为重量级锁。
- 无锁状态:对象的hashCode()方法第一次被调用时,JVM会生成对应的identity hash code值并将该值存储到Mark Word中。
 - 偏向锁:线程获取偏向锁,或用线程id和epoch值覆盖identity hash code所在的位置。如果一个对象的hashCode() 方法已被调用过一次之后,这个对象不能被设置偏向锁。为了保证统一对象前后两次调用hashCode() 方法得到的结果一致。
 - 轻量锁:JVM会在当前线程的栈帧中创建一个锁记录(Lock Record)空间,用于存储锁对象的Mark Word拷贝。所以轻量锁可以和identity hash code共存,哈希码和GC年龄保存于此,释放锁后,这些信息写回对象头中,
 - 重量级锁:Mark Word的重量级锁指针指向重量级锁的ObjectMonitor类,里面有字段记录非加锁状态下的Mark Word,释放后也会写回。
 
7. JIT编译器对锁的优化
Just in time compiler即时编译器。
7.1 锁消除
锁消除。JIT编译器会无视它,每次new o,synchronized(o) 就会无视它。
class Test05 {
    Object object = new Object();
    public void print() {
        Object o = new Object();
        synchronized (o) {
            System.out.println("Lock:" + o.hashCode() + " Object:" + object.hashCode());
        }
    }
}
public class demo05 {
    public static void main(String[] args) {
        Test05 test05 = new Test05();
        for(int i=0; i<10; i++) {
            test05.print();
        }
    }
}
 
7.2 锁粗化
一次申请锁。
    public static void main(String[] args) {
        Object o = new Object();
        for(int i=0; i<10; i++) {
            synchronized (o) {
                System.out.println("1");
            }
            synchronized (o) {
                System.out.println("1");
            }
        }
    }
                


















