1.1. synchronized锁
1.1.1. synchronized注意点
- 一把锁只能同时被一个线程获取,没有获得锁的线程只能等待
- 每个实例对应自己的一把锁(this),不同实例之间互不影响
- synchronized修饰的方法,正常执行完及抛出异常,都会释放锁
1.1.2. 锁类型
锁膨胀方向:无锁-->偏向锁-->轻量级锁-->重量级锁(过程不可逆,但偏向锁可被重置为无锁)
1.1.3. synchronized锁升级过程
- 无锁-->偏向锁
- 线程访问锁对象时,会将当前线程id写入锁对象的对象头内,升级为偏向锁,不会主动释放锁,此后,再有线程获取锁会判断与对象头 内的线程id是否相同,一样则继续获得锁
- 如果不一致,需要判断对象头内记录的线程是否存活,如果没存活,锁对象重置为无锁状态
- 如果存活,立即查找该线程的栈帧信息,如果还是需要持有,那么暂停当前线程,撤销偏向锁,升级为轻量级锁
- 轻量级锁原理
- 线程1获取轻量级锁时会把锁对象的对象头MarkWord复制一份到线程1的栈帧中创建的用于存储锁记录的空间(DisplacedMarkWord),然后使用CAS把对象头中的内容替换为线程1存储的锁记录的地址; - 如果在复制对象头的同时,线程2也准备获取锁,复制了对象头到线程2的锁记录空间中,但是在线程2CAS的时候,发现线程1已经把对象头换了,线程2的CAS失败,那么线程2就尝试使用自旋锁来等待线程1释放锁。自旋锁简单来说就是让线程2在循环中不断CAS
- 升级重量锁 - 如果自旋的时间太长也不行,因为自旋是要耗CPU的,因此自旋的次数是有限制的,比如10次或者100次,如果自旋次数达到了线程1还没有释放锁,或者线程1还在执行,线程2还在自旋等待,这时又有一个线程3过来竞争这个锁对象,那么这个时候轻量级锁就会膨胀为重量级锁。重量级锁把除了拥有锁的线程都阻塞,防止CPU空转