一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第6天,点击查看活动详情。
区分原因
按照锁对资源消耗的级别区分:一般能用低级就不用高级
四锁的概念
无锁(直接放行):没有对资源进行锁定,所有线程访问同一个资源。但是同时只有一个线程进行修改。循环修改的一种实现 CAS就是无锁
偏向锁(有吊牌):这个关键代码只有一个线程会访问。那么这个访问的时候看到是这个线程,就自动给他锁而不用检查锁的状态(相当于管大门的认识了老王,就不需要登记就直接放行)
轻量级锁(需要登记):有一个线程访问偏向锁,偏向锁发现这个线程不是我等的那个线程,所以就将该锁进化成轻量级锁。其他线程需要进行自旋等待来尝试获取锁(多个线程的多次CAS)(门卫本来以为只有老王会来,结果来了老杨,就让后面来的都进行登记并且玩会手机等着老杨出来才能进入)
重量级锁(厕所关门):就是遇到没有钥匙就得阻塞该线程,CPU切换到别的线程执行(门卫跟老杨说,今天只能老王进来,你明天再来吧)
四锁的关系
这个过程可以称为锁的升级,也可以称为锁的膨胀
只能正向升级,不能降级。
偏向锁
相对于无锁
增加了Mark Word来标示锁
轻量级锁
相对于偏向锁
增加了自旋锁(适应性自旋锁) 操作来竞争锁
重量级锁
相对于轻量级锁
增加了阻塞等待或者说悲观锁来实现
四锁的实现
锁的实现
锁存放在对象头的Mark word
中(对象存放在堆中,对象包含对象头、实例数据、对齐填充),对象头包括Mark word
,类指针,arrayLength(数组的时候有数组长度)。
markword的最后两位:
锁类型 | 锁标示 | 对象头中存储的内容(依次增加) |
---|---|---|
无锁 | 01 | 1. hashCode 2. 分代年龄 3. 是否是偏向锁(0) |
偏向锁 | 01 | 4. 偏向线程 5. 偏向时间戳 6. 是偏向锁(1) |
轻量级锁 | 00 | 指向栈中Monitor的指针 |
重量级锁 | 10 | 指向重量级锁的指针 |
无锁:通过不断的尝试修改进行对同一个资源的修改
偏向锁:通过记录偏向锁的线程id,来允许对应线程直接访问资源。而如果出现一个其他线程访问。两种情况
- 仍然是偏向锁:将该次访问的线程id记录下来。之后该偏向锁归该线程id所有(老王儿子来了)
- 不是偏向锁:升级成轻量级锁(门卫看管严了)
具体偏向锁升级成轻量级锁可以看大佬:java 偏向锁怎么升级为轻量级锁
这里有一个暂停原始线程的一个过程
对象头中存储的一些信息这里偏向锁用到的有这几个
- 锁标志位
- 是否是偏向锁
- 偏向锁的线程ID
如果锁标志位
是01,就去判断是否是偏向锁
的值来决定是不是偏向锁。如果是,就去比较当前获取锁的ID是否是偏向锁的线程ID
如果是就直接放行允许获取锁。
轻量级锁:多个线程访问同一个资源,使用自旋的方式进行等待。如果自旋超过一定的次数。对于其他线程来说,就会将该锁升级成重量级锁
重量级锁:阻塞等待,平常意义上的锁。CPU切换去干别的事情