简介
Synchronized是Java的一个关键字,通过它可以实现线程安全。
使用方式
修饰实例方法
将实例作为锁对象
修饰静态方法与静态代码块
将Class对象作为锁对象
自定义锁对象
原理
编译过程中会生成monitorenter
与monitorexit
字节码指令。锁信息会记录在锁对象的对象头中的Mark Word中
锁升级过程
参考:锁升级过程
最初Synchronized是采用重量级锁,重量级锁存在内核态与用户态的切换,存在性能损耗。于是后续进行了相关优化:锁升级
无锁 -> 偏向锁 -> 轻量级锁 -> 重量级锁
偏向锁:偏向锁只有遇到其他线程尝试竞争偏向锁时,持有偏向锁的线程才会释放锁,线程是不会主动释放偏向锁的。线程尝试竞争时,偏向锁等待全局安全点判断是否有竞争恢复到轻量级锁或无锁状态。偏向锁适用于同一个线程多次获取锁的情况。 缺点:竞争激烈情况下,存在锁撤销的开销,此时可以关闭偏向锁
轻量级锁:适用于多个线程交替获取锁,很少发生竞争, 缺点:消耗CPU
重量级锁:系统中存在大量的线程同时尝试获取锁,高并发场景,缺点:线程阻塞唤醒,频繁切换上下文性能损耗
详细过程:
- 尝试获取锁的线程,检查锁对象头中Mark Word记录的线程ID。如果与当前线程ID相同,表示已获取锁直接执行
- 如果发现与当前线程不一致,偏向锁撤销升级为轻量级锁。拷贝Mark Word到栈帧,尝试CAS自旋修改Mark Word指向栈帧,修改成功则获得锁,否则在多次(15次)自旋失败后膨胀为重量级锁
- 此时存在大量竞争,未保证线程安全并且降低自旋导致的cpu busy。重量级锁接管,对于未获取锁的线程进行阻塞。等待锁释放操作系统调度。