「并发」无锁、偏向锁、轻量级锁、重量级锁

89 阅读3分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第6天,点击查看活动详情

区分原因

按照锁对资源消耗的级别区分:一般能用低级就不用高级

四锁的概念

无锁(直接放行):没有对资源进行锁定,所有线程访问同一个资源。但是同时只有一个线程进行修改。循环修改的一种实现 CAS就是无锁

偏向锁(有吊牌):这个关键代码只有一个线程会访问。那么这个访问的时候看到是这个线程,就自动给他锁而不用检查锁的状态(相当于管大门的认识了老王,就不需要登记就直接放行)

轻量级锁(需要登记):有一个线程访问偏向锁,偏向锁发现这个线程不是我等的那个线程,所以就将该锁进化成轻量级锁。其他线程需要进行自旋等待来尝试获取锁(多个线程的多次CAS)(门卫本来以为只有老王会来,结果来了老杨,就让后面来的都进行登记并且玩会手机等着老杨出来才能进入)

重量级锁(厕所关门):就是遇到没有钥匙就得阻塞该线程,CPU切换到别的线程执行(门卫跟老杨说,今天只能老王进来,你明天再来吧)

四锁的关系

这个过程可以称为锁的升级,也可以称为锁的膨胀

只能正向升级,不能降级。

偏向锁相对于无锁增加了Mark Word来标示锁

轻量级锁相对于偏向锁增加了自旋锁(适应性自旋锁) 操作来竞争锁

重量级锁相对于轻量级锁增加了阻塞等待或者说悲观锁来实现

四锁的实现

锁的实现

锁存放在对象头的Mark word中(对象存放在堆中,对象包含对象头、实例数据、对齐填充),对象头包括Mark word,类指针,arrayLength(数组的时候有数组长度)。

markword的最后两位:

锁类型锁标示对象头中存储的内容(依次增加)
无锁011. hashCode 2. 分代年龄 3. 是否是偏向锁(0)
偏向锁014. 偏向线程 5. 偏向时间戳 6. 是偏向锁(1)
轻量级锁00指向栈中Monitor的指针
重量级锁10指向重量级锁的指针

无锁:通过不断的尝试修改进行对同一个资源的修改

偏向锁:通过记录偏向锁的线程id,来允许对应线程直接访问资源。而如果出现一个其他线程访问。两种情况

  • 仍然是偏向锁:将该次访问的线程id记录下来。之后该偏向锁归该线程id所有(老王儿子来了)
  • 不是偏向锁:升级成轻量级锁(门卫看管严了)

具体偏向锁升级成轻量级锁可以看大佬:java 偏向锁怎么升级为轻量级锁

这里有一个暂停原始线程的一个过程

对象头中存储的一些信息这里偏向锁用到的有这几个

  • 锁标志位
  • 是否是偏向锁
  • 偏向锁的线程ID

如果锁标志位是01,就去判断是否是偏向锁的值来决定是不是偏向锁。如果是,就去比较当前获取锁的ID是否是偏向锁的线程ID如果是就直接放行允许获取锁。

轻量级锁:多个线程访问同一个资源,使用自旋的方式进行等待。如果自旋超过一定的次数。对于其他线程来说,就会将该锁升级成重量级锁

重量级锁:阻塞等待,平常意义上的锁。CPU切换去干别的事情