专栏电商日志财经减肥爱情
投稿投诉
爱情常识
搭配分娩
减肥两性
孕期塑形
财经教案
论文美文
日志体育
养生学堂
电商科学
头戴业界
专栏星座
用品音乐

一种比读写锁更快的锁,还不赶紧认识一下

  摘要:一起来聊聊在高并发环境下比ReadWriteLock更快的锁StampedLock。
  本文分享自华为云社区《【高并发】高并发场景下一种比读写锁更快的锁,看完我彻底折服了!!(建议收藏)云社区华为云》,作者:冰河。什么是StampedLock?
  ReadWriteLock锁允许多个线程同时读取共享变量,但是在读取共享变量的时候,不允许另外的线程多共享变量进行写操作,更多的适合于读多写少的环境中。那么,在读多写少的环境中,有没有一种比ReadWriteLock更快的锁呢?
  答案当然是有!那就是我们今天要介绍的主角JDK1。8中新增的StampedLock!没错,就是它!
  StampedLock与ReadWriteLock相比,在读的过程中也允许后面的一个线程获取写锁对共享变量进行写操作,为了避免读取的数据不一致,使用StampedLock读取共享变量时,需要对共享变量进行是否有写入的检验操作,并且这种读是一种乐观读。
  总之,StampedLock是一种在读取共享变量的过程中,允许后面的一个线程获取写锁对共享变量进行写操作,使用乐观读避免数据不一致的问题,并且在读多写少的高并发环境下,比ReadWriteLock更快的一种锁。StampedLock三种锁模式
  这里,我们可以简单对比下StampedLock与ReadWriteLock,ReadWriteLock支持两种锁模式:一种是读锁,另一种是写锁,并且ReadWriteLock允许多个线程同时读共享变量,在读时,不允许写,在写时,不允许读,读和写是互斥的,所以,ReadWriteLock中的读锁,更多的是指悲观读锁。
  StampedLock支持三种锁模式:写锁、读锁(这里的读锁指的是悲观读锁)和乐观读(很多资料和书籍写的是乐观读锁,这里我个人觉得更准确的是乐观读,为啥呢?我们继续往下看啊)。其中,写锁和读锁与ReadWriteLock中的语义类似,允许多个线程同时获取读锁,但是只允许一个线程获取写锁,写锁和读锁也是互斥的。
  另一个与ReadWriteLock不同的地方在于:StampedLock在获取读锁或者写锁成功后,都会返回一个Long类型的变量,之后在释放锁时,需要传入这个Long类型的变量。例如,下面的伪代码所示的逻辑演示了StampedLock如何获取锁和释放锁。publicclassStampedLockDemo{创建StampedLock锁对象publicStampedLockstampedLocknewStampedLock();获取、释放读锁publicvoidtestGetAndReleaseReadLock(){longstampstampedLock。readLock();try{执行获取读锁后的业务逻辑}finally{释放锁stampedLock。unlockRead(stamp);}}获取、释放写锁publicvoidtestGetAndReleaseWriteLock(){longstampstampedLock。writeLock();try{执行获取写锁后的业务逻辑。}finally{释放锁stampedLock。unlockWrite(stamp);}}}
  StampedLock支持乐观读,这是它比ReadWriteLock性能要好的关键所在。ReadWriteLock在读取共享变量时,所有对共享变量的写操作都会被阻塞。而StampedLock提供的乐观读,在多个线程读取共享变量时,允许一个线程对共享变量进行写操作。
  我们再来看一下JDK官方给出的StampedLock示例,如下所示。classPoint{privatedoublex,y;privatefinalStampedLockslnewStampedLock();voidmove(doubledeltaX,doubledeltaY){anexclusivelylockedmethodlongstampsl。writeLock();try{xdeltaX;ydeltaY;}finally{sl。unlockWrite(stamp);}}doubledistanceFromOrigin(){Areadonlymethodlongstampsl。tryOptimisticRead();doublecurrentXx,currentYy;if(!sl。validate(stamp)){stampsl。readLock();try{currentXx;currentYy;}finally{sl。unlockRead(stamp);}}returnMath。sqrt(currentXcurrentXcurrentYcurrentY);}voidmoveIfAtOrigin(doublenewX,doublenewY){upgradeCouldinsteadstartwithoptimistic,notreadmodelongstampsl。readLock();try{while(x0。0y0。0){longwssl。tryConvertToWriteLock(stamp);if(ws!0L){stampws;xnewX;ynewY;break;}else{sl。unlockRead(stamp);stampsl。writeLock();}}}finally{sl。unlock(stamp);}}}
  在上述代码中,如果在执行乐观读操作时,另外的线程对共享变量进行了写操作,则会把乐观读升级为悲观读锁,如下代码片段所示。doubledistanceFromOrigin(){Areadonlymethod乐观读longstampsl。tryOptimisticRead();doublecurrentXx,currentYy;判断是否有线程对变量进行了写操作如果有线程对共享变量进行了写操作则sl。validate(stamp)会返回falseif(!sl。validate(stamp)){将乐观读升级为悲观读锁stampsl。readLock();try{currentXx;currentYy;}finally{释放悲观锁sl。unlockRead(stamp);}}returnMath。sqrt(currentXcurrentXcurrentYcurrentY);}
  这种将乐观读升级为悲观读锁的方式相比一直使用乐观读的方式更加合理,如果不升级为悲观读锁,则程序会在一个循环中反复执行乐观读操作,直到乐观读操作期间没有线程执行写操作,而在循环中不断的执行乐观读会消耗大量的CPU资源,升级为悲观读锁是更加合理的一种方式。StampedLock实现思想
  StampedLock内部是基于CLH锁实现的,CLH是一种自旋锁,能够保证没有饥饿现象的发生,并且能够保证FIFO(先进先出)的服务顺序。
  在CLH中,锁维护一个等待线程队列,所有申请锁,但是没有成功的线程都会存入这个队列中,每一个节点代表一个线程,保存一个标记位(locked),用于判断当前线程是否已经释放锁,当locked标记位为true时,表示获取到锁,当locked标记位为false时,表示成功释放了锁。
  当一个线程试图获得锁时,取得等待队列的尾部节点作为其前序节点,并使用类似如下代码判断前序节点是否已经成功释放锁:while(pred。locked){省略操作}
  只要前序节点(pred)没有释放锁,则表示当前线程还不能继续执行,因此会自旋等待;反之,如果前序线程已经释放锁,则当前线程可以继续执行。
  释放锁时,也遵循这个逻辑,线程会将自身节点的locked位置标记为false,后续等待的线程就能继续执行了,也就是已经释放了锁。
  StampedLock的实现思想总体来说,还是比较简单的,这里就不展开讲了。StampedLock的注意事项
  在读多写少的高并发环境下,StampedLock的性能确实不错,但是它不能够完全取代ReadWriteLock。在使用的时候,也需要特别注意以下几个方面。StampedLock不支持重入
  没错,StampedLock是不支持重入的,也就是说,在使用StampedLock时,不能嵌套使用,这点在使用时要特别注意。StampedLock不支持条件变量
  第二个需要注意的是就是StampedLock不支持条件变量,无论是读锁还是写锁,都不支持条件变量。StampedLock使用不当会导致CPU飙升
  这点也是最重要的一点,在使用时需要特别注意:如果某个线程阻塞在StampedLock的readLock()或者writeLock()方法上时,此时调用阻塞线程的interrupt()方法中断线程,会导致CPU飙升到100。例如,下面的代码所示。publicvoidtestStampedLock()throwsException{finalStampedLocklocknewStampedLock();Threadthread01newThread((){获取写锁lock。writeLock();永远阻塞在此处,不释放写锁LockSupport。park();});thread01。start();保证thread01获取写锁Thread。sleep(100);Threadthread02newThread(()阻塞在悲观读锁lock。readLock());thread02。start();保证T2阻塞在读锁Thread。sleep(100);中断线程thread02会导致线程thread02所在CPU飙升thread02。interrupt();thread02。join();}
  运行上面的程序,会导致thread02线程所在的CPU飙升到100。
  这里,有很多小伙伴不太明白为啥LockSupport。park();会导致thread01会永远阻塞。这里,冰河为你画了一张线程的生命周期图,如下所示。
  这下明白了吧?在线程的生命周期中,有几个重要的状态需要说明一下。NEW:初始状态,线程被构建,但是还没有调用start()方法。RUNNABLE:可运行状态,可运行状态可以包括:运行中状态和就绪状态。BLOCKED:阻塞状态,处于这个状态的线程需要等待其他线程释放锁或者等待进入synchronized。WAITING:表示等待状态,处于该状态的线程需要等待其他线程对其进行通知或中断等操作,进而进入下一个状态。TIMEWAITING:超时等待状态。可以在一定的时间自行返回。TERMINATED:终止状态,当前线程执行完毕。
  看完这个线程的生命周期图,知道为啥调用LockSupport。park();会使thread02阻塞了吧?
  所以,在使用StampedLock时,一定要注意避免线程所在的CPU飙升的问题。那如何避免呢?
  那就是使用StampedLock的readLock()方法或者读锁和使用writeLock()方法获取写锁时,一定不要调用线程的中断方法来中断线程,如果不可避免的要中断线程的话,一定要用StampedLock的readLockInterruptibly()方法获取可中断的读锁和使用StampedLock的writeLockInterruptibly()方法获取可中断的悲观写锁。
  最后,对于StampedLock的使用,JDK官方给出的StampedLock示例本身就是一个最佳实践了,小伙伴们可以多看看JDK官方给出的StampedLock示例,多多体会下StampedLock的使用方式和背后原理与核心思想。
  点击下方,第一时间了解华为云新鲜技术
  华为云博客大数据博客AI博客云计算博客开发者中心华为云

江苏淮安值得收藏推荐的十五个旅游景点里运河文化长廊景区淮安版现代清明上河图的繁华盛景里运河文化长廊景区,位于中国运河之都江苏省淮安市,景区分为起承转和四大板块,集高端论坛文化旅游生态养生商务休闲以及特色主题乐园多功能四川成都天光墟,晚上开张天亮收摊,不强买强卖,不退不换大家都知道我国各地的生活习俗有很大不同!例如有些地方开宴席时女人与小孩子不上桌有些省份外嫁女不能回娘家过年三十在西南一些地方,很注重老人家的69岁生日,但在北方一些乡镇又很忌讳过6闹中取静净境悠远的逸仙湖公园广东省中山市因为是孙中山先生的故乡,故市内有很多和中山先生相关的名胜古迹。逸仙,是中山先生的字。想必逸仙湖也是对中山先生的一种敬意和怀念吧。中山市内公园极多各具特色,散落在市区,闹共襄盛会,国际张蓄势积能再出发这个冬季,备受关注的首届湖南旅游发展大会拉开帷幕。作为举办地的张家界敞开怀抱迎接四方宾朋,张家界更是以此次大会为契机,秉承着办一次会,兴一座城的目标,在创意山水道路交通游玩保障购物上榜BestinTravel2023的最佳火车旅途,究竟有什么魅力?JohnWrefordShutterstock后疫情时代,打卡目的地已经变得没那么重要,人们更渴望的是旅行所带来的自由疗愈与成长,以及如何更好地实践可持续旅行。这也是LonelyP回国攻略没有签证也可通过日韩中转回国了吗?一个多月以来,中日中韩往返航班都在大量增班,日韩赴华机票下跌趋势明显。很多小伙伴都咨询我们说想走日韩中转赴华。但按照之前的政策,在中转地需要再次申请健康码才能赴华。然而日韩机场中转长白天下雪燃粉雪制燥奇趣长白山万达这里是林海雪原和雾凇的代名词,有雪白高耸的山峰有三江之源的碧蓝湖泊天池来自西伯利亚的冷风和轻柔细腻的雪花交融后的清新感让无数滑雪爱好者对这里充满无限向往这里是与五岳齐名的关东第一山全球第13519旅行限制的国家地区美属维京群岛01所有国内旅客和国际旅客不需要Covid测试疫苗接种证明或检疫证明。不再需要线上填写USVI旅行筛查或出示经批准的绿色二维码即可前往USVI。萨巴岛02前往萨巴岛的所读南明史,看君臣内斗,只剩叹息每次看书我都习惯性从头看到尾,读南明史时,我时常被书中的内容气到停下来。本书的作者顾诚是北京师范大学历史系教授,博士生导师,当代公认的明清史大家。南明史在写作时引用了很多档案,书中成吉思汗的死有多不堪?真死于西夏王妃之口?为啥史书都耻于记载元太祖成吉思汗一生戎马征战开疆拓土,将中国的版图扩张到了极致。1000多年前,由成吉思汗所建立的一代盛世之国蒙古帝国,自亚洲最东端一直向西延伸到了欧洲域内,北起极寒的西伯利亚一直延专业球队北京国安输给业余县级球队甘肃泾川文汇,心里不是滋味近日,北京国安足球队再次让我们看到了,足球赛场上,输赢一切皆有可能。一支专业球队输给了一支业余球队的事实依然让很多球迷感觉不是滋味,其实我又何尝不一样。北京国安北京国安球队的队员都
(社会)国庆假期乐出游国庆假期,人们纷纷走出家门,放松身心,乐享美好时光。10月3日,游客在河南洛阳龙门石窟景区内游览。新华社发(贾方文摄)10月3日,游客在南京玄武湖公园划船游玩(无人机照片)。新华社壮观!武当山惊现海市蜃楼奇观,网友拍到神奇一幕十堰广电讯(全媒体记者许海芳通讯员徐正国)10月3日晚八点,有网友向记者反映,雨后的南岩宫景区惊现海市蜃楼。这种现象在灯光下持续了约十五分钟,远远望去美轮美奂,仿佛天上仙宫,令人惊沪上曾经的四大儿童公园,这两个就在阿拉长宁20世纪80年代,儿童交通公园华山儿童公园爱思儿童公园和嘉定儿童公园并称沪上四大儿童公园,承载了那一代人儿时的欢乐记忆,其中,儿童交通公园和华山儿童公园就在阿拉长宁!儿童交通公园儿闽山闽水物华新三明等秋来不如追秋去,马上开启国庆赏秋之旅发现三明秋之美国庆假期已至,三明文旅以发现三明秋之美为主题,推出一批赏秋古村品秋民宿秋意景区秋色森林,为旅游消费者推荐最有秋意的国庆假期文旅产品。秋意景区秋之趣味,莫过于景区谁说三波罗的海世界最大半咸水海,世界最淡的海,世界盐度最低的海波罗的海的海水,又浅又淡特别容易结冰,是世界上最大的半咸水水域,被称为世界上最淡的海!它是欧洲北部的内海,北冰洋的边缘海,大西洋的属海波罗的海地理位置波罗的海在斯堪的纳维亚半岛与欧假期户外露营,哪些消防安全要注意?国庆假期已经开始由于受疫情的影响不少人会选择周边游露营也势必成为微度假的新宠近年来因为露营发生的意外也屡见不鲜01hr案例一2022年4月10日15时50分,江苏省南京市江北新区桥国庆,来头条小组,翻开这本美好记事簿撒花红旗飘扬,与国同庆。惊喜激动人心的国庆节终于到啦,在这个悠长的假期,发生了许多美好的事情。在这个特别的时刻,头条小组诚邀各位友友们,翻开这本属于国庆的美好记事簿,一起来感受美好2028年中国将迎来核聚变发电,距离发电还有6年?核聚变是有多重要核聚变有多重要?从上世纪开始,各个国家就全心投入到核聚变的研究当中了。重要到什么程度呢?风能重要吧!太阳能也很重要吧!但它远超风能太阳能以及其他能源,在某种程度上,核聚变称得上是电做时代的漫游者,去往未来度假上海时装周记者周芳颖编辑楼婍沁XUZHIFlneur漫游者在瞬息万变的城市生活中,总有这样一群漫游者,静静观察熙熙攘攘的人群。波德莱尔称他们为现代生活的画家,在漫无目的的闲逛中,瞥见了现代大面向世界和未来,开辟中国诺奖赛道中国在汽车工业领域开设了新能源电动汽车赛道并初步取得了一些先发优势。由于能源安全问题及致力于环境保护和绿色发展,加速发展新能源,减少化石能源使用,实现碳达峰碳中和已成为世界未来发展不撞南墙不回头!德国议员赴台窜访,未来别想过大陆这一关正所谓屋漏偏逢连夜雨,船迟又遇顶头风。眼下德国朔尔茨政府就面临这样的艰难处境。日前,德国与俄罗斯合作的北溪2号能源管道发生爆炸,加剧了德国的能源危机,该国还爆发了大规模抗议游行活动
友情链接:快好知快生活快百科快传网中准网文好找聚热点快软网