java synchronised 机制

作用范围:静态代码块、方法

写法如下:

  1. Object lock = new Object();
  2. synchronised(lock){
  3. // 业务代码
  4. }

多线程对锁的竞争,就是对共享资源lock 的竞争; 抢夺lock 对象monintor修改锁标识;

对象的内存布局

image.png

偏向锁

锁竞争中,同一个线程获得锁的概率大,为了让获取锁的代价更低,引入了偏向锁;

当一个线程获取到锁,会在对象头中存储线程id;后续这个线程进入和退出代码块时,不需要再次加锁和释放锁;

偏向锁的获取和撤销

1)获取锁的对象,判断是否处于可偏向的状态 ( lock_1, 且 threadId 为 null )

2)可以偏向,通过cas ,把当前线程id 写入 Markword;

  • 写入成功,锁对象升级为偏向锁
  • 写失败,说明其他线程已经获取到锁,锁升级为轻量级锁(这个操作需要等到全局安全点,也就是没有线程在执行字节码)

3)如果是已偏向状态,需要检查 markword 中存储的ThreadID 是否等于当前线程的 ThreadID

  • 如果相等,不需要再次获得锁,可直接执行同步代码块
  • 如果不相等,说明当前锁偏向于其他线程,需要撤销偏向锁并升级到轻量级锁

轻量级锁

轻量级锁设置失败,会升级为轻量级锁;

相比于偏向锁,轻量级锁会再当线程 创建 锁记录, 将对象头中的锁记录指向当前线程;

也就是说偏向锁比较的是 线程id是否与当前线程一致; 轻量级锁比较的是,锁对象的指针是否指向自己;

重量级锁

轻量级锁升级为重量级锁后,就只能被挂起阻塞来等待唤醒了;

锁的转化

image.png

注意点:

  • 1)锁的升级是不可逆向的
  • 2)偏向锁cas替换threadId 失败后情况?
  • 3)轻量级锁到重量级锁的转化?

    1. 轻量级锁和偏向锁都有CAS操作,两者区别?

用户态和内核态

参考