0%

Synchronized

简介

Synchronized是Java的一个关键字,通过它可以实现线程安全。

使用方式

  1. 修饰实例方法

    将实例作为锁对象

  2. 修饰静态方法与静态代码块

    将Class对象作为锁对象

  3. 自定义锁对象

原理

编译过程中会生成monitorentermonitorexit字节码指令。锁信息会记录在锁对象的对象头中的Mark Word中

锁升级过程

参考:锁升级过程

最初Synchronized是采用重量级锁,重量级锁存在内核态与用户态的切换,存在性能损耗。于是后续进行了相关优化:锁升级

无锁 -> 偏向锁 -> 轻量级锁 -> 重量级锁

偏向锁:偏向锁只有遇到其他线程尝试竞争偏向锁时,持有偏向锁的线程才会释放锁,线程是不会主动释放偏向锁的。线程尝试竞争时,偏向锁等待全局安全点判断是否有竞争恢复到轻量级锁或无锁状态。偏向锁适用于同一个线程多次获取锁的情况缺点:竞争激烈情况下,存在锁撤销的开销,此时可以关闭偏向锁

轻量级锁:适用于多个线程交替获取锁,很少发生竞争缺点:消耗CPU

重量级锁:系统中存在大量的线程同时尝试获取锁,高并发场景缺点:线程阻塞唤醒,频繁切换上下文性能损耗

详细过程:

  1. 尝试获取锁的线程,检查锁对象头中Mark Word记录的线程ID。如果与当前线程ID相同,表示已获取锁直接执行
  2. 如果发现与当前线程不一致,偏向锁撤销升级为轻量级锁。拷贝Mark Word到栈帧,尝试CAS自旋修改Mark Word指向栈帧,修改成功则获得锁,否则在多次(15次)自旋失败后膨胀为重量级锁
  3. 此时存在大量竞争,未保证线程安全并且降低自旋导致的cpu busy。重量级锁接管,对于未获取锁的线程进行阻塞。等待锁释放操作系统调度。