使用
synchronized
应该注意的是:- 一把锁只能同时被一个线程获取,没有获得锁的线程只能等待;
- 每个实例都对应有自己的锁,不同实例之间互不影响;锁对象是
*.class
以及synchronized
修饰的是 static 方法的时候,锁的是类,类的所有对象公用同一把锁
synchronized
修饰的方法,无论正常执行完毕还是抛出异常都会释放锁
实现原理
< Java 1.6
使用的是监视器锁(monitor)来实现的,依赖于系统的互斥锁(Mutex),属于重量级锁。
≥ Java 1.6
官方对
synchronized
进行了包括锁膨胀、锁消除、锁粗化、自适应自旋锁等大量优化。锁膨胀过程
目前锁状态有四种,级别由低到高依次是:无锁,偏向锁,轻量级锁、重量级锁。锁状态只能升级不能降级。
1. 无锁状态
2. 偏向锁
当初次执行到
synchronized
代码块时,锁对象变为偏向锁,通过 CAS 操作修改对象头中的标志位并存储锁偏向的线程 ID。默认之后只有该线程使用,之后当一个线程再次获取锁时检测 Mark Word 中指向的线程号是否为当前线程。当有其它线程竞争偏向锁时,等待全局安全点,即在某时刻当前线程没有字节码在执行时,暂停偏向锁的线程,判断线程不处于活动状态,将对象头设置成无锁状态,并撤销偏向锁。
3. 轻量级锁(CAS,自旋锁)
轻量级锁的获取主要有两种情况:
- 关闭偏向锁功能时
- 由于多个线程竞争偏向锁导致偏向锁升级为轻量级锁
在其它线程多次自旋获取锁失败后,轻量级锁将升级为重量级锁
4. 重量级锁
当后续线程获取锁时会将自己挂起,等待被唤醒。