-
synchronized实现原理:
synchronized实现同步的基础是:Java中每一种对象都可以作为锁。具体表现为以下3中形式:
1、对于普通同步方法,锁是当前实例对象
2、对于静态同步方法,锁是当前类的Class对象
3、对于同步方法块,锁是synchronized括号里配置的对象
-
锁信息存储位置和锁里包含的内容:
1、synchronized用的锁是存储在Java对象头里的,如果对象是数组类型,则用3个字宽存储对象头,如果对象是非数组类型,则用2个字宽存储。对象头包含3部分(数组类型对象):Mark Word:存储对象的hashcode和锁信息;Class Metadata Address:存储对像类型数据的指针;Array length:数组的长度
2、锁里的内容包括:锁状态、(对象分代年龄、线程ID等)、锁标志位
-
锁升级:无锁->偏向锁->轻量级锁->重量级锁
偏向锁:
1、偏向锁的思想(乐观锁):锁不仅不存在竞争,而且总是由同一线程多次获得,等到竞争出现才释放锁
2、偏向锁的实现:当一个线程访问同步块区域并获取锁时,会在对象头的Mark Word和栈帧中的锁记录里存储偏向锁的线程ID,以后该线程在进入和退出同步块区域时不需要进行cas操作来加锁和释放锁,只会检查对象头里是否存储着指向当前线程的偏向锁。
3、偏向锁的撤销:当有其他线程竞争偏向锁时,持有偏向锁的线程才会释放锁,偏向锁的撤销需要等到全局安全点
轻量级锁:
1、当偏向锁出现其他线程竞争锁时,会升级锁,尝试使用cas对像头的偏向锁执行当前线程。
2、轻量级的实现:线程在执行同步块之前,JVM会先在当前线程的栈帧中创建用户存储锁记录的空间,并将对象头中的Mark Word赋值到锁记录中,然后线程尝试使用CAS将对象头中的Mark Word替换位执行锁记录地址的指针,如果成为获得锁,如果失败,当前线程尝试自旋来获得锁。
3、轻量级锁的解锁:使用cas方式将锁记录的Mark Word替换回对象头中,如果成功,没有发生锁竞争,如果失败,存在锁竞争,膨胀为重量级锁
-
锁的优缺点:
偏向锁:加锁和解锁不需要额外消耗,执行速度快;如果线程间存在竞争时,会有额外锁撤销的消耗,适应单线程访问同步块
轻量级锁:线程竞争不会阻塞,速度块;自旋消耗cpu;
重量级锁:不会消耗cpu;线程阻塞,响应时间慢