城市直播房产教育博客汽车
投稿投诉
汽车报价
买车新车
博客专栏
专题精品
教育留学
高考读书
房产家居
彩票视频
直播黑猫
投资微博
城市上海
政务旅游

Java中synchronized的底层实现原理

1月25日 囍孤女投稿
  一、对象头、MarkWord、monitor、synchronized怎么关联起来
  (1)首先java里面每个对象JVM底层都会为它创建一个监视器monitor,这个是JVM层次为我们保证的。这个监视器就类似一个锁,哪个线程持有这个monitor的操作权,就相当于获取到了锁
  (2)其次synchronized修饰的代码或者方法,底层会生成两条指令分别为monitorenter、monitorexit。
  (3)进入synchronized的代码块之前会执行monitorenter指令,去申请monitor监视器的操作权,如果申请成功了,就相当于获取到了锁。如果已经有别的线程申请成功monitor了,这个时候它就得等着,等别的线程执行完synchronized里面的代码之后就会执行monitorexit指令释放monitor监视器,这样其它在等待的线程就可以再次申请获取monitor监视器了。
  monitor又是个啥东西?为什么monitor能当做锁?首先既然你知道每个对象都有一个monitor监视器,那你知道每个对象是怎么和它的monitor监视器关联起来的不?
  通过synchronized进行加锁,就是通过对象头的MarkWord关联起来的,里面记录着锁状态和占有锁的线程地址指针。
  当MarkWord中最后两位的锁标志位是10的时候,MarkWord的前面是monitor监视器的地址,我现在就给你画出来对象头、MarkWord和monitor之间的关系图(32位):
  二、monitor内部结构
  monitor叫做对象监视器、也叫作监视器锁,JVM规定了每一个java对象都有一个monitor对象与之对应,这monitor是JVM帮我们创建的,在底层使用C实现的。
  其实monitor在C底层也是某个类的对象,那个类就是ObjectMonitor,它拥有的属性也字段如下:结构体如下ObjectMonitor::ObjectMonitor(){非常重要,表示锁计数器,count0表示还没人加锁,count0表示加锁的次数非常重要,指向加锁成功的线程,ownernull时候表示没人加锁wait线程的集合,在synchorized代码块中调用wait()方法的线程会被加入到此集合中沉睡,等待别人叫醒它waitsetL非常重要,等待队列,加锁失败的线程会被加入到这个等待队列中,等待再次争抢锁spinF获取锁之前的自旋的次数获取之前每次锁自旋的时间ownerIsT}3。1、monitor加锁原理
  count:这个属性非常重要,直接表示有没有被加锁,如果没被线程加锁则count0,如果count大于0则说明被加锁了
  owner:这个属性也非常重要,直接指向加锁的线程,比如线程A获取锁成功了,则owner线程A;当ownernull的时候表示没线程加锁
  waitset:当持有锁的线程调用wait()方法的时候,那个线程就会释放锁,然后线程被加入到monitor的waitset集合中等待,然后线程就会被挂起。只有有别的线程调用notify将它唤醒。entrylist:这个就是等待队列,当线程加锁失败的时候被block住,然后线程会被加入到这个entrylist队列中,等待获取锁。
  spinFreq:获取锁失败前自旋的次数;JDK1。6之后对synchronized进行优化;原先JDK1。6以前,只要线程获取锁失败,线程立马被挂起,线程醒来的时候再去竞争锁,这样会导致频繁的上下文切换,性能太差了。JDK1。6后优化了这个问题,就是线程获取锁失败之后,不会被立马挂起,而是每个一段时间都会重试去争抢一次,这个spinFreq就是最大的重试次数,也就是自旋的次数,如果超过了这个次数抢不到,那线程只能沉睡了。spinClock:上面说获取锁失败每隔一段时间都会重试一次,这个属性就是自旋间隔的时间周期,比如50ms,那么就是每隔50ms就尝试一次获取锁。
  下面通过图文展示加锁过程:
  (1)首先呢,没有线程对monitor进行加锁的时候是这样的:
  说明:count0表示加锁次数是0,也就是没线程加锁;owner指向null,也就是没线程加锁
  (2)然后呢,这个时候线程A、线程B来竞争加锁了,如下图所示:
  (3)线程A竞争到锁,将count修改为1,表示加锁次数为1,将owner线程A,也就是指向自己,表示线程A获取到了锁。在count0,ownernull的时候,表示monitor没人加锁,这个时候线程A和线程B同时请求加锁,也就是竞争将count改为1。由于线程A这哥们动作比较快,它将count改为1,获取锁成功了。它还嘚瑟了一下,同时将onwer线程A,表示自己获取了锁,告诉线程B,兄弟不好意思了,是我获取了锁,我先去操作了。
  既然加锁就是将count设置为1,同时将owner指向自己。那反过来推测,释放锁的时候是不是将count设置为0,将owner设置为null就OK了?是的,释放锁的过程就是这么简单:
  加锁和释放锁说完了,我们接下来将的是
  spinFreq、spinclock、entrylist
  这几个东西:
  上面解释字段属性的时候说spinFreq是等待锁期间自旋的次数、spinclock是自旋的周期也就是每次自旋多久时间、entrylist这个就是自旋次数用完了还没获取锁,只能放到entrylist等待队列挂起了。
  让我们继续接着图来讲:
  (1)首先线程B获取锁的时候发现monitor已经被线程A加锁了(2)然后monitor里面记录的spinFreq、spinclock信息告诉线程B,你可以每隔50ms来尝试加锁一次,总共可以尝试10次(3)如果线程B在10次尝试加锁期间,获取锁成功了,那线程B将count设置为1,owner指向自己表示自己获取锁成功了(4)如果10次尝试获取锁此时都用完了,那没辙了,它只能放到等待队列里面先睡觉去了,也就是线程B被挂起了spinFreq和spinclock这两个monitor的属性主要是让线程自旋的时候使用的吧。entryList作用是当线程自旋次数都用完了之后,只能进入等待队列进行休眠了。4。6、轻量级锁
  轻量级锁模式下,加锁之前会创建一个锁记录,然后将MarkWord中的数据备份到锁记录中(MarkWord存储hashcode、GC年龄等很重要数据,不能丢失了),以便后续恢复MarkWord使用。这个锁记录放在加锁线程的虚拟机栈中,加锁的过程就是将MarkWord前面的30位指向锁记录地址。所以markword的这个地址指向哪个线程的虚拟机栈中,就说明哪个线程获取了轻量级锁。就好比下面的图,线程A获取了轻量级锁,锁记录存在线程A的虚拟机栈中,然后MarkWord的前面30位存储锁记录的地址。
  了解了轻量级加锁的原理之后,我们继续,来讲讲偏向锁升级为轻量级锁的过程:
  (1)首先线程A持有偏向锁,然后正在执行synchronized块中的代码
  (2)这个时候线程B来竞争锁,发现有人加了偏向锁并且正在执行synchronized块中的代码,为了避免上述说的线程A一直持有锁不释放的情况,需要对锁进行升级,升级为轻量级锁
  (3)先将线程A暂停,为线程A创建一个锁记录LockRecord,将MarkWord的数据复制到锁记录中;然后将锁记录放入线程A的虚拟机栈中
  (4)然后将MarkWord中的前30位指向线程A中锁记录的地址,将线程A唤醒,线程A就知道自己持有了轻量级锁
  4。6。2、在轻量级锁模式下,多线程是怎么竞争锁和释放锁的?
  (1)线程A和线程B同时竞争锁,在轻量级锁模式下,都会创建LockRecord锁记录放入自己的栈帧中
  (2)同时执行CAS操作,将MarkWord前30位设置为自己锁记录的地址,谁设置成功了,锁就获取到锁
  上面讲了加锁的过程,轻量级锁的释放很简单,就将自己的LockRecord中的MarkWord备份的数据恢复回去即可,恢复的时候执行的是CAS操作将MarkWord数据恢复成加锁前的样子。Javasynchronized偏向锁后hashcode存在哪里?jdk8偏向锁是默认开启,但是是有延时的,可通过参数:XX:BiasedLockingStartupDelay0关闭延时。hashcode是懒加载,在调用hashCode方法后才会保存在对象头中。当对象头中没有hashcode时,对象头锁的状态是可偏向(biasable,101,且无线程id)。如果在同步代码块之前调用hashCode方法,则对象头中会有hashcode,且锁状态是不可偏向(001),这时候再执行同步代码块,锁直接是轻量级锁(thinlock,00)。如果是在同步代码块中执行hashcode,则锁是从偏向锁直接膨胀为重量级锁。
投诉 评论 转载

vivoX90Pro深度评测一英寸大底蔡司光学影像旗舰,出片vivoX系列手机在影像着方面一直走在行业前列,我从X60Pro一直用到现在的X90Pro,每一代产品都没有让我失望,的确是没有最好,只有更好,所以对喜欢手机拍摄的朋友来说,v……请欣赏宁波家庭年宴(第一波)我和妻都是大家族,过年从各个长辈家一轮吃下来,春节这几天休息日根本不够,加上家族中有几对是外地媳妇或外地女婿,春节还要拖儿带女回老家住上几天,给当地长辈拜岁。所以在宁波的……12月时薪增长明显降温,美联储会放慢加息吗?记者崔璞玉美国劳动力市场继续保持强劲,但工资增速有所降温,为美联储放缓加息提供了空间。美国劳工部周五发布的数据显示,去年12月美国非农就业人数新增22。3万,低于下……落后43分,落后25分!3。4亿豪阵现原形,王朝终结者作茧自NBA常规赛激战正酣,30支球队大展拳脚,联盟格局初具雏形,每一支球队的崛起都有方法,每一支球队的挣扎都有原因。将时光拨回到常规赛开打之前,西部的勇士、快船,东部的篮网、绿军、……西施有礼文创品牌发布IP新形象开启西子嘉年华活动为迎接西施故里旅游区新产品、新业态的全面亮相,1月8日,由诸暨市文化旅游集团主办的西子嘉年华暨西施故里新品发布活动在西施故里旅游区举行,现场发放总额3000万元的西施有礼春暖暨……机迷游戏日报米哈游起诉三七互娱NIKKE总收入超1。7亿美元【《鹅鸭杀》Steam最高同时在线人数已突破56万】据SteamDB数据显示,《鹅鸭杀》Steam最高同时在线已经突破56。3万人,官方曾表示四十万左右是服务器的极限,看……凌晨突发!巴西球王贝利去世防控是否放开太快?国家卫健委回应!来看昨夜重要消息。北京时间12月30日凌晨,巴西圣保罗市阿尔伯特爱因斯坦医院发布公告称,巴西知名运动员、球王贝利因结肠癌引发多器官衰竭去世,终年82岁。贝利本名埃德……强大的新粒子,主宰初期宇宙,但最后消失了,怎么回事?图:早期的宇宙抽象图及量子物理当原始宇宙还处于第二阶段时,一种奇怪的超级粒子(实际上并不是粒子)主宰了整个时空,并释放出阵阵涟漪。这种被称为示波器的物质可能充满能量波,并……Java中synchronized的底层实现原理一、对象头、MarkWord、monitor、synchronized怎么关联起来(1)首先java里面每个对象JVM底层都会为它创建一个监视器monitor,这个是JV……女人过得好不好,看心就知道作家王尔德说:我们都生活在阴沟里,但仍有人仰望星空。面对生活的不如意,有的人难免心怀怨念,或者灰心丧气,但有的人,却可以把目光投向星辰大海。同样的困境,不同的结局,……对亲人暴躁,对外人和气的人,多半是这种生活状态,看完值得反思来源:大河报对陌生人和气,对亲人暴躁,大多数人好像都如此。迫于生活的压力,出门在外,对别人礼貌客气,回家就变成了易燃易爆炸。一边控制不住脾气,一边又感到后悔不已。总……PTQ(PostTrainingQuantization)源PTQ(PostTrainingQuantization)源码阅读一最近在做模型量化相关工作,就研究下PTQ的原理和代码实现。PTQ原理部分已经有很多文章讲的都很好,有时……
旅拍要美更要好大理的心情什么是眼中风男生热门发型百度地图与地图版竞品分析从轻量级工具向聚合平台迈讲故事是营销的一大利器一句话的四大名著童年的故事永久造句用永久造句大全德甲多特蒙德VS拜仁慕尼黑,狭路相逢?国家造句用国家造句大全总投资260亿元!淮南再添一新能源产业基地脱发美女完全“求生计”读《狼王梦》有感变化多端的老师不一样的周末多肉植物白凤怎么养,4个步骤教你养殖白凤雪人造句用雪人造句大全最新消息联想拯救者Y70海报公布写自己的作文参考加油站加油员注意事项妈妈如何正确给新生儿洗澡公主家小仙瓶成分安全吗公主家小仙瓶精华液好用吗清莲不妖

友情链接:中准网聚热点快百科快传网快生活快软网快好知文好找