浅谈锁升级

简介: 以下内容均为原创转载须标注出处。能力有限,仅供参考。

我觉得在了解锁之前了解对象的内存布局是有必要的
在这里插入图片描述
上图为普通对象的内存布局

markwordclass pointerdatapadding
属于对象头部分包含hashCode、分代年龄、锁信息。总共占8个字节java miror镜像的地址,负责找到方法区中对象的一些信息。开启指针压缩的情况下占4个字节,不开启的情况占8个字节,默认开启表示对象的数据补齐操作,在64位计算机中每次读8个字节数据,当对象的大小正好为8的倍数时读取效率最高所以会有一个补齐操作

 这几个中我们重点研究markword中的数据
在这里插入图片描述
上面表格是当一个对象为不同锁时markword的存储占用情况,下面我们说说锁升级的过程
首先
一个对象当没有线程占用时为第一个状态,此时对象头中锁信息为无偏向锁标志位为01,
然后
如果此时一个线程需要锁住这个对象了,就会给当前对象一个偏向锁,偏向锁也可以叫无锁因为本身只是将线程ID写入对象头中以及改变一个是否偏向,
若此时
又有一个线程进来需要锁住这个对象,但是此时线程发现这个对象已经有线程占用了,这时两个线程会在自己线程栈中生成一个lock record的锁记录同时进行CAS操作,将这个锁记录的地址放入到markword中,哪个线程放进去了,哪个线程就占用了这个对象,其他线程继续进行CAS操作,这个操作称为自旋,自旋的用处主要是如果占用资源的线程很快就能结束那么就可以省去了线程休眠和唤醒的操作了,可以提高效率,但是当线程自旋次数超过一定阈值,或者自旋的线程超过一定的阈值,就会升级为重量级锁,这个叫做自适应自旋。
一旦
需要升级为重量级锁,虚拟机就会向操作申请一把重量级锁,此时cpu从用户态转化为内核态,去找一找有没有锁时空闲的,如果有将锁的地址写在markword上,这里的重量级锁就是mutex(互斥量)的一种结构,其余线程放入等待队列中,,轮到谁用谁出队。
  说人话就是要上锁的对象是饮品店的饮料机,一个人刚来的时候只有他自己买,就可以直接做了(现在就是偏向锁),此时如果第二个人来了,也需要用这个饮料机,正好第一个人的还没开始做,这时就需要竞争,谁先抢到饮料机谁就先做,没抢到的等着(现在就是轻量级锁),等着的人多了,或者抢的次数多了,饮品店老板不高兴了,别抢了,都去后边排队吧,叫到谁谁过来拿来。
值得注意的是
  偏向锁其实还是有很大缺点的,现在的大部分产品的并发量都很高,线程对资源的抢夺基本是必须的,所有对于偏向锁而言,加锁解锁的开销变得多余,还是有点有点影响性能的,我认为他的存在就是为了解决锁的重入的。这里其实有一个Epoch批量加锁解锁的东西。
  还有就是锁升级后,hashCode还有分代年龄的东西会放入到线程栈中,还是可以访问的,因为markword 的内存有限。
关于锁的一些优化
锁的粗化
比如说

    StringBuffer s = new StringBuffer();
        for (int i = 0; i < 50; i++) {
            s.append(i);   
        }

对于这个操作如果不对锁进行粗化就会有50次锁的加锁解锁所以虚拟机会自动优化为将锁放在for循环外边
锁的消除

	public void synchornDel(){
        StringBuffer s = new StringBuffer();
        for (int i = 0; i < 50; i++) {
            s.append(i);
        }
    }

  对于上述代码,s对象并不会逃逸出该方法,更不会存在线程安全问题所以虚拟机就会对锁进行消除
  这篇文章讲了锁的升级过程以及java自带的所有话策略。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值