【java并发编程实战4】偏向锁-轻量锁-重量锁的那点秘密(synchronize实现原理)

目录

【SpringBoot2.0文章汇总目录,java多线程教程文章汇总 长期更新系列

请多多支持

在多线程并发编程中,synchronized一直都是元老级别的角色,人们都通常称呼它为重量锁,但是在jdk1.6版本之后,jdk就对synchronized做了大量的优化,这时候我们就不能称呼它为重量锁了,有的时候它也是很的,那么接下来我们就调调,synchronized是怎么被优化的,它跟偏向锁、轻量锁、重量锁又有什么渊源。

synchronized

回顾一下synchronized是怎么使用的呢。

1、同步普通方法

public synchronized void  sync1() {
    // do somethings
}

在该方法中,synchronized锁的是当前实例的对象

2、同步静态方法

public static synchronized void sync2() {
    // do somethings
}

由于该方法是一个静态方法,那么它锁的当前类的class对象。

3、同步方法块

public void sync3() {
    synchronized(this) {
        // do somethings
    }
}

public void sync4() {
    synchronized(MyTest.css) {
        // do somethings
    }
}

那么同步方法块是需要根据方法中具体同步的对象来实现的。

在上面代码中其实sync3()跟同步普通方法一样,锁的是当前实例对象;那么sync4方法就与同步静态方法一样,锁的是当前类的class对象。

从上面代码可以看出来的,我们通过使用synchronized关键字可以很简单的解决并发问题,但是其实是jvm底层通过使用一种叫内置锁的手段,简化了开发人员实现并发的复杂度,在jdk1.6以前 synchronized是基于重量锁实现的,即每次遇到同步代码都要获取锁,然后释放锁,在jdk1.6之后对其优化,根据不同场景使用不同的策略,这也就是 偏向锁、轻量锁、重量锁的来由。在介绍他们之前我先介绍一下另一个锁-自旋锁。听到这么多锁,是不是头晕,当初我学习的时候也是这样的。但是当你慢慢学习深入,你就会很容易的理解每个锁的作用。

自旋锁

自旋锁顾名思义,就是自己旋转转圈等待,那么它有什么作用呢?

  • 当前线程尝试去竞争锁
  • 竞争失败,准备阻塞自己
  • 但是并没有阻塞自己,而是采用自旋锁,进入自旋状态
  • 进入自旋状态,并且重新不断竞争锁
  • 如果在自旋期间成功获取锁,那么结束自旋状态,否则进入阻塞状态

如果在自旋期间成功获取锁,那么就减少一次线程的切换。

根据上面解释我们可以很容易的明白自旋锁的意义,因为cpu从内核态切换至用户态,线程的阻塞与恢复会浪费资源的,但是通过自旋而不是去阻塞当前线程,那么就会节省这个一个cpu状态切换。

所以自旋锁适合在** 持有锁的时间长,且竞争不激烈**的场景下使用。

使用-XX:-UseSpinning参数关闭自旋锁优化;-XX:PreBlockSpin参数修改默认的自旋次数

偏向锁

在实际场景中,如果一个同步方法,没有多线程竞争,并且总是由同一个线程多次获取锁,如果每次还有阻塞线程,唤醒cpu从用户态转核心态,那么对于cpu是一种资源的浪费,为了解决这类问题,旧引入了偏向锁的概念。

“偏向”的意思是,偏向锁假定将来只有第一个申请锁的线程会使用锁(不会有任何线程再来申请锁),因此,只需要在Mark Word中CAS记录owner(本质上也是更新,但初始值为空),如果记录成功,则偏向锁获取成功,记录锁状态为偏向锁,以后当前线程等于owner就可以零成本的直接获得锁;否则,说明有其他线程竞争,膨胀为轻量级锁

具体的步骤如下

  • 访问同步代码块

  • 检查对象头是否owner是否存储当前现成的id

  • 如果没有,进行CAS尝试替换mark word中的owner 如果有执行同步代码(代表获取锁成功)

  • 修改成功 (代表无竞争)owner修改为当前线程id,执行同步代码 修改失败(代表有竞争) 进入撤销偏向锁,暂停线程并将owner置空,进入轻量锁。

899685-20161025102843468-151954717.png

偏向锁无法使用自旋锁优化,因为一旦有其他线程申请锁,就破坏了偏向锁的假定。

如果你确定应用程序中所有的锁通常是在竞争状态,你可以通过JVM参数关闭偏向锁

UseBiasedLocking = false,那么程序会默认进入轻量锁状态。

轻量锁

如果说偏向锁是为了解决同步代码在单线程下访问性能问题,那么轻量锁是为了解决减少无实际竞争情况下,使用重量级锁产生的性能消耗

轻量锁,顾名思义,轻量是相对于重量的问题,使用轻量锁时,不需要申请互斥量(mutex)

,而是将mark word中的信息复制到当前线程的栈中,然后通过cas尝试修改mark word并替换成轻量锁,如果替换成功则执行同步代码。如果此时有线程2来竞争,并且他也尝试cas修改mark word但是失败了,那么线程2会进入自旋状态,如果在自旋状态也没有修改成功,那么轻量锁将膨胀成状态,mark word会被修改成重量锁标记(10) ,线程进入阻塞状态。

当然,由于轻量级锁天然瞄准不存在锁竞争的场景,如果存在锁竞争但不激烈,仍然可以用自旋锁优化,自旋失败后再膨胀为重量级锁

重量锁

在jvm规范中,synchronized是基于监视器锁(monitor)来实现的,它会在同步代码之前添加一个monitorenter指令,获取到该对象的monitor,同时它会在同步代码结束处和异常处添加一个monitorexit指令去释放该对象的monitor,需要注意的是每一个对象都有一个monitor与之配对,当一个monitor被获取之后 也就是被monitorenter,它会处于一个锁定状态,其他尝试获取该对象的monitor的线程会获取失败,只有当获取该对象的monitor的线程执行了monitorexit指令后,其他线程才有可能获取该对象的monitor成功。

所以从上面描述可以得出,监视器锁就是monitor它是互斥的(mutex)。由于它是互斥的,那么它的操作成本就非常的高,包括系统调用引起的内核态与用户态切换、线程阻塞造成的线程切换等。因此,后来称这种锁为“重量级锁”。

小结

偏向锁、轻量级锁、重量级锁适用于不同的并发场景:

  • 偏向锁:无实际竞争,且将来只有第一个申请锁的线程会使用锁。
  • 轻量级锁:无实际竞争,多个线程交替使用锁;允许短时间的锁竞争。
  • 重量级锁:有实际竞争,且锁竞争时间长。

另外,如果锁竞争时间短,可以使用自旋锁进一步优化轻量级锁、重量级锁的性能,减少线程切换。

如果锁竞争程度逐渐提高(缓慢),那么从偏向锁逐步膨胀到重量锁,能够提高系统的整体性能。
同时需要注意锁可以升级,但是不能降级

另外通过这次学习,大家应该也知道自从jdk1.6以后 synchronized已经被优化了,性能不会比Lock

所以jdk.16版本及其以后版本的同学可以放心大胆的使用了。

最后附一张从偏向锁膨胀至重量锁的完全的流程图

4491294-e3bcefb2bacea224.png

最后欢迎大家关注一下我的个人公众号。一起交流一起学习,有问必答。


公众号
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,298评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,701评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 107,078评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,687评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,018评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,410评论 1 211
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,729评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,412评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,124评论 1 239
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,379评论 2 242
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,903评论 1 257
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,268评论 2 251
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,894评论 3 233
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,014评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,770评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,435评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,312评论 2 260

推荐阅读更多精彩内容