目录
- 1、Synchronized锁
- 2、锁升级
1、Synchronized锁
通过Synchronized实现同步机制,属于一种悲观锁,在操作数据时,判断该对象是否被锁定,如果被锁定则进入阻塞状态直到被占用的线程释放,如果没有被锁或者当前线程已存在操作对象的锁则进行上锁操作,操作完数据后进行释放操作。
当一个类对象被锁时,被Synchronized修饰的方法将产生阻塞,非Synchronized修饰的方法不会产生阻塞。
Synchronized通过可重入性解决自己锁死自己的情况;因为他是通过判断对象没有锁或者当前线程拥有当前对象的锁来进行加锁,如果没有重入性一类中两个同步方法互相调用就会造成死锁。
Synchronized也是一种非公平锁,因为它不会按申请锁的时间来分配锁,而是通过竞争的形式来获取锁,这样提高了执行性能。
方法锁:synchronized修饰方法时,每个实例对象对应一把锁。
对象锁:synchronized修饰方法或代码块,每个实例对象对应一把锁。
类锁:synchronized修饰静态方法或者静态代码块,所有的实例对象共用同一把锁,我们称之为类锁。
在一个类中,同时存在类锁方法和对象锁方法。多线程访问两个方法的时候,线程会不会阻塞。
2、锁升级
从低到高分为:偏向锁、轻量级锁(自旋锁)、重量级锁,锁只能升级不能降级;
为什么需要进行锁升级: ** 在是一个线程多次获得同一个锁的情况下,如果每次都要竞争锁会增大很多没有必要的代价,为了降低CPU的开销,提供了执行效率。**
升级锁的实现,依赖于对象头中的Mark Word,里面会记录当前第一个获取锁的线程的ID,以及锁状态;
- 偏向锁:当一个线程A抢到锁后,将线程A的ID记录到对象头中,并且锁升级为偏向锁(锁标志-01(无锁于偏向都是01),是否偏向为1);后续线程A再次获取该对象的锁时,发现对象处于偏向锁状态,对象头中的线程ID与线程A一致,此时会直接获取到偏向锁;
- 轻量级锁:当另外一个线程B获取锁时,发现锁以及处于偏向状态,此时线程B会通过CAS的方式尝试性的争抢锁【修改对象头中的线程ID】(判断线程A是否存活,存活就不能进行修改),如果偏向锁抢锁失败,则偏向锁就升级为轻量级锁,如果抢锁成功则执行代码;
- 重量级锁:轻量级锁是通过自旋的方式争抢锁,并且适用于线程持有锁的时间也不长的情况**(因为阻塞线程需要进行CPU状态,代价比较大,所以自旋)**;当线程的自旋次数超过阈值(默认是10)的时候为了防止cpu空转,会将自旋锁升级为重量级锁,并且将没有获取锁的线程进行阻塞;
轻量级锁修改线程ID的方式:
偏向锁升级为轻量级锁之后,线程B将锁对象的markword拷贝到线程本身的markword空间中,然后通过cas的方式去设置锁对像中的线程ID值;