多线程学习笔记之 - 锁升级

1.CAS(Compare and Swap /比较再交换)

CAS是一种无锁算法,也叫自旋锁,它以不上锁的方式实现线程同步。


操作逻辑为:1.读取变量值 E

                      2.对该值进行操作,改变后的值为V

                      3.回写数据之前,再次取出E的值,判断与第一次取出时的值是否相同

                      4.如果相同,表示无人修改过E的值,那么当前线程就可以将修改后的值V写入E

                      5.如果不相同,表示E的值已经被修改,那么,当前线程的此次修改就无效了,需要重新读取E的值

但是,只用上面的逻辑,会遇到一个问题:

       1. 线程1读取到变量x的旧值为0,开始对其修改...

       2.线程2抢占,将变量x值改为了1

       3.线程3抢占,将变量x的值又改回了0

       4.线程1把0修改成了1,准备回写新值

       5.线程1发现,x的值为0,与读取时的值一致,回写x的值为1

以上问题被称为ABA问题。那么如何解决ABA呢?

其实很简单,即给变量x增加一个版本号。每个线程在修改x的值时,更新版本号,这样就能判断出此变量是否被修改过。

2.下图演示了synchronized的锁升级过程


过程大概如下:

    jvm中有关于偏向锁的参数,可以设置是否开启偏向锁。

java -XX:+PrintFlagsFinal    //该指令可以在控制台打印出所有的系统参数

java -XX:+PrintFlagsFinal | grep -i 'BiasedLock'   //查看所有的偏向锁相关参数

下图是执行结果。  其中 -UseBiasedLocking 参数表示默认开启偏向锁.

-BiasedLockingStartupDelay  表示延迟4秒开启

为什么要延迟开启偏向锁呢?  因为java 虚拟机中,存在许多synchronize的方法,而这些方法经过统计后,发现竞争比较激烈,开启偏向锁会产生多余的切换动作,消耗资源,因此在虚拟机启动时,关闭偏向锁能提高速度。

如果不开启偏向锁,则会直接由无锁状态转变为轻量级锁。

下面讨论的是默认开启偏向锁的情况。

在讲锁升级之前,还要引入一个东西:Mark Word,共64位,不同的位置标示不同的含义。如图:

在线程访问一个对象时,首先给线程上一个偏向锁。如果有其他线程来竞争此对象,升级为轻量级锁(自旋锁)。

当处于自旋锁状态的竞争激烈时(特定条件:如等待线程的个数超过N个,锁自旋的次数超过n次等),会升级成重量级锁。

3.偏向锁

HotSpot 的作者经过研究发现,大多数情况下,锁不仅不存在多线程竞争,而且总是由同一线程多次获得,为了让线程获得锁的代价更低而引入了偏向锁。当一个线程访问同步块并获取锁时,会在对象头和栈帧中的锁记录里存储锁偏向的线程ID,以后该线程在进入和退出同步块时不需要进行CAS操作来加锁和解锁,只需简单地测试一下对象头的Mark Word里是否存储着指向当前线程的偏向锁。

 如果测试成功,表示线程已经获得了锁。

如果测试失败,则需要再测试一下Mark Word中偏向锁的标识是否设置成1(表示当前是偏向锁)

如果没有设置,则使用CAS竞争锁;如果设置了,则尝试使用CAS将对象头的偏向锁指向当前线程

详细步骤:

     1.线程1首先获得了偏向锁

     2.线程2来竞争锁对象;

     3.判断当前对象头是否是偏向锁;

            是:判断拥有偏向锁的线程1是否还存在

                    存在:

                             4.暂停线程1,修改锁标志位,将锁升级成轻量级锁

                             5.线程1继续执行

                             6.线程2自旋,竞争锁对象

                    不存在:

                             4.使用cas替换偏向锁线程ID为线程2,锁不升级,仍为偏向锁(线程1执行完毕后,不会主动去释放偏向锁)

            否:线程2自旋来获取锁对象;

4.轻量级锁(自旋锁)

线程在执行同步块之前,JVM会先在当前线程的栈桢中创建用于存储锁记录的空间,并将对象头中的Mark Word复制到锁记录中,官方称为Displaced Mark Word。然后线程尝试使用CAS将对象头中的Mark Word替换替换为自己的线程id。如果成功,当前线程获得锁,如果失败,表示其他线程竞争锁,当前线程便尝试使用自旋来获取锁。

轻量级解锁时,会使用原子的CAS操作将Displaced Mark Word替换回到对象头,如果成功,则表示没有竞争发生。如果失败,表示当前锁存在竞争,就会开始自旋。自旋一定次数后轻量级锁会膨胀为重量级锁。


5.重量级锁

重量级锁依赖于底层操作系统的Mutex Lock,所有线程都会被阻塞住,线程之间的切换需要从用户态到内核态,切换成本非常高。

锁可以升级但不能降级,意味着偏向锁升级成轻量级锁后不能降级成偏向锁,这种锁升级却不能降级的策略,是为了提高获得锁和释放锁的效率

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