ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

浅谈Synchronized关键字

2021-07-21 18:30:30  阅读:147  来源: 互联网

标签:CAS 浅谈 Synchronized 对象 解锁 关键字 线程 重量级 偏向


浅谈Synchronized

  1. synchronized简介

synchronized可以说是并发编程的元老级角色,大部分时候被称为重量级锁,但是在1.6之后的为了减弱这种重量级的影响,对其进行了各种优化,像是在1.6的优化中引入了偏向锁和轻量级锁以及锁的消除和锁的升级

  1. synchronized锁的范围

可以这样说,java中任何一个对象都可以作为锁,具体可以表现为下面三种形式
对于普通的同步方法,锁的是当前实例对象
对于静态同步方法,锁的是当前类的CLASS对象
对于同步的方法块,锁的是括号内的对象

  1. synchronized的实现原理

从JVM操作规范中,我们可以知道,JVM几区进入和退出Monitor对象来实现方法和代码块的同步
这里要知道,两者的细节是不同的
代码块的同步使用的monitorenter和monitorexit指令实现
方法使用了另一种来实现的,具体并没有详细说明,但是方法的同步同样可以使用这两条指令来实现
原理就是monitorenter在编译的时候添加到同步代码块开始的位置,monitorexit插入到同步代码块结束和异常的位置,JVM保证每个monitorenter都有与之对应的monitorexit指令,每个对象都有一个monitor对象,当他的monitor被持有之后,就会被认为是被占有也就是加锁了,当线程执行到这个指令的时候,就回去尝试获取monitor,也就是去请求获取锁
在这里插入图片描述

  1. Java对象头

synchronized的锁存放于对象的对象头中,对象是数组类型,会用三个字宽,非数组类型占用两个字宽
在这里插入图片描述
而Mark Word详细内容如下
在这里插入图片描述
因为标记位的不同,可能会存储不同的数据,详细如下
这是32位虚拟机的情况在这里插入图片描述
64位虚拟机的情况又略有不同
在这里插入图片描述

  1. 锁的状态

JDK1.6的时候为了减少获得锁和释放锁带来的内存消耗,引入了偏向锁和轻量级锁的概念,这样锁一共有了四种状态:偏向锁状态,无锁状态,轻量级锁状态,重量级锁状态,锁可以升级不能降级
偏向锁
在研究中发现,大多数情况锁不存在多线程竞争,总是由同一个线程获得锁,这样就引入了偏向锁的概念,具体实现就是当一个线程访问同步代码块获取锁的时候,会使用CAS将线程ID设置到对象的对象头,之后只要是这个线程是自己的就表示没有竞争,所以就不需要进行CAS操作,当获取锁失败,就会查看对象头标识是否设置了偏向锁,如果没有就CAS竞争锁,如果设置了,就尝试使用CAS将对象头中的偏向锁指向该线程
在这里插入图片描述
这里要重点注意,偏向锁是等到有竞争的时候才会释放锁的机制
这里就出现了锁撤销的问题,撤销的时候首先会暂停拥有偏向锁的线程,检查持有偏向锁的线程是否还活着,如果不处于活动状态他会将他设置成无锁,如果仍然活着,那么就会出现两种情况
一种是栈中的锁记录重新偏向其他线程
一种是恢复到无锁,或者进行锁升级
在这里插入图片描述
这里可以看的出只有在偏向锁不是本线程ID并且CAS失败的时候,才会升级为轻量级锁
轻量级锁
这里可以从轻量级锁加锁和解锁开始谈起
在执行同步代码块的时候,首先会在栈帧中创建存储锁记录的空间,空间存储对象的MarkWord,之后使用CAS来将对象头中的MarkWord替换为锁记录的指针,成功的话就代表获取了锁,失败的话就自旋的获取锁,如果自选获取锁失败,那么就会升级为重量级锁
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

这里CAS失败会出现两种情况,一种是已经升级为重量级锁
另一种是锁重入
解锁的时候如果锁记录的值不是null,那么就是使用CAS进行恢复,成功的话就会解锁成功
失败的话说明轻量级锁膨胀为重量级锁,进入重量级锁解锁过程
解锁升级为重量级锁的过程
在这里插入图片描述
首先我的Thread-0已经获取了锁,锁记录已经和markword进行交换,这是Thread-1来获取锁,CAS失败,这是就会升级为重量级锁,将对象指向Monitor,并且将Thread-1放进Monitor锁对象的EntryList的队列里,此时Monitor的owner指向Thread-0
在这里插入图片描述
这是Thread-0解锁,进行CAS将锁记录和MarkWord进行交换,这时因为已经升级成了重量级锁,对象中存储的已经不是锁记录,所以CAS失败,就会进入重量级锁的解锁流程,也就是将owner置为null,并且唤醒EntryList中阻塞的线程,进行锁的竞争
在这里插入图片描述
这里是一个重量级锁的解锁流程

上述问题说完之后,引申出来三个新的概念,自旋锁,批量重偏向,批量撤销
自旋锁
就是当一个线程获取锁之后,另一个线程会循环等待尝试获取锁
有点就是在于线程会一直保持用户态,当线程没有获取锁阻塞住的时候,会进入内核态,下次尝试获取锁的时候会再切换回用户态,这样就产生了消耗
批量重偏向
如果对象被多个线程访问没有竞争,这时偏向t1的仍有机会偏向t2,重偏向会终止对象线程id,
当撤销偏向锁超过20次,jvm会认为偏向错误,于是会在加锁时进行重新偏向
批量撤销
当撤销超过40次,就会认为不该进行偏向,从而把对象都变成不可偏向的

在这里插入图片描述

标签:CAS,浅谈,Synchronized,对象,解锁,关键字,线程,重量级,偏向
来源: https://blog.csdn.net/weixin_44809858/article/details/118940038

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有