欢迎来到《并发王者课》,本文是该系列文章中的第13篇

在上篇文章中,我们介绍了避免死锁的几种策略。虽然死锁臭名昭著,然而在并发编程中,除了死锁之外,还有一些同样重要的线程活跃性问题值得关注。它们的知名度不高,但破坏性极强,本文将介绍的正是其中的线程饥饿活锁问题

一、饥饿的产生

所谓线程 饥饿(Starvation) 指的是在多线程的资源竞争中,存在贪婪的线程一直锁定资源不释放,其他的线程则始终处于等待状态,然而这个等待是没有结果的,它们会被活活地饿死

独占者的贪婪是饥饿产生的原因之一,概括来说,饥饿一般由下面三种原因导致:

(1)线程被无限阻塞

当获得锁的线程需要执行无限时间长的操作时(比如IO或者无限循环),那么后面的线程将会被无限阻塞,导致被饿死。

(2) 线程优先级降低没有获得CPU时间

当多个竞争的线程被设置优先级之后,优先级越高,线程被给予的CPU时间越多。在某些极端情况下,低优先级的线程可能永远无法被授予充足的CPU时间,从而导致被饿死。

(3) 线程永远在等待资源

在青铜系列文章中,我们说过notify在发送通知时,是无法唤醒指定线程的。当多个线程都处于wait时,那么部分线程可能始终无法被通知到,以至于挨饿。

二、饥饿与公平

为了直观体验线程的饥饿,我们创建了下面的代码。

创建哪吒、兰陵王等四个英雄玩家,他们以竞争的方式打野,杀死野怪可以获得经济收益。

public class StarvationExample {public static void main(String[] args) {final WildMonster wildMonster = new WildMonster();String[] players = {"哪吒","兰陵王","铠","典韦"};for (String player: players) {Thread playerThread = new Thread(new Runnable() {public void run() {wildMonster.killWildMonster();}});playerThread.setName(player);playerThread.start();}}
}
 public class WildMonster {public synchronized void killWildMonster() {while (true) {String playerName = Thread.currentThread().getName();System.out.println(playerName + "斩获野怪!");try {Thread.sleep(500);} catch (InterruptedException e) {System.out.println("打野中断");}}}}

运行结果如下:

哪吒斩获野怪!
哪吒斩获野怪!
哪吒斩获野怪!
哪吒斩获野怪!
哪吒斩获野怪!
哪吒斩获野怪!
哪吒斩获野怪!
哪吒斩获野怪!
哪吒斩获野怪!
哪吒斩获野怪!
哪吒斩获野怪!Process finished with exit code 130 (interrupted by signal 2: SIGINT)

从结果中可以看到,在几个线程的运行中,始终只有哪吒可以斩获野怪,其他英雄束手无策等着被饿死。为什么会发生这样的事?

仔细看WildMonster类中的代码,问题出在killWildMonster同步方法中。一旦某个英雄进入该方法后,将一直持有对象锁,其他线程被阻塞而无法再进入

当然,解决的方法也很简单,只要打破独占即可。比如,我们在下面的代码中把Thread.sleep改成wait,那么问题将迎刃而解。

 public static class WildMonster {public synchronized void killWildMonster() {while (true) {String playerName = Thread.currentThread().getName();System.out.println(playerName + "斩获野怪!");try {wait(500);} catch (InterruptedException e) {System.out.println("打野中断");}}}}

运行结果如下:

哪吒斩获野怪!
铠斩获野怪!
兰陵王斩获野怪!
典韦斩获野怪!
兰陵王斩获野怪!
典韦斩获野怪!Process finished with exit code 130 (interrupted by signal 2: SIGINT)

从结果中可以看到,四个英雄都获得了打野的机会,在一定程度上实现了公平。(备注:wait会释放锁,但sleep不会,对此不理解的可以查看青铜系列文章。)

如何让线程之间公平竞争,是线程问题中的重要话题。虽然我们无法保证百分百的公平,但我们仍然要通过设计一定的数据结构和使用相应的工具类来增加线程之间的公平性。

关于线程之间的公平性,在本文中重要的是理解它的存在和重要性,关于如何优雅地解决,我们会在后续的文章中介绍相关的并发工具类

三、活锁的麻烦

相对于死锁,你可能对活锁没有那么熟悉。然而,活锁所造成的负面影响并不亚于死锁。在结果上,活锁和死锁都是灾难性的,都将会造成应用程序无法提供正常的服务能力

所谓活锁(LiveLock),指的是两个线程都忙于响应对方的请求,但却不干自己的事。它们不断地重复特定的代码,却一事无成

不同于死锁,活锁并不会造成线程进入阻塞状态,但它们会原地打转,所以在影响上和死锁相似,程序会进入无线死循环,无法继续进行。

如果你无法直观理解活锁是什么,相信你在走路时一定遇到过下面这种情况。两人相向而行,出于礼貌两人互相让行,让来让去,结果两人仍然无法通行。活锁,也是这个意思。

小结

以上就是关于线程饥饿与活锁的全部内容。在本文中,我们介绍了线程产生饥饿的原因。对待线程饥饿,没有百分百的方案,但可以尽可能地实现公平竞争。我们没有在本文列举线程公平性的一些工具类,因为我认为对问题的理解要比解决方案更重要。如果没有对问题的理解,方案在落地时也会出现知其然而不知其所以然的情况。另外,虽然活锁并不像死锁那样知名度,但是对活锁的恰当理解仍然非常必要,它是并发知识体系中的一部分。

正文到此结束,恭喜你又上了一颗星✨

夫子的试炼

  • 编写代码设置不同线程的优先级,体验线程饥饿并给出解决方案。

延伸阅读与参考资料

  • 动态图片引用
  • 《并发王者课》大纲与更新进度总览

关于作者

关注公众号【庸人技术笑谈】,获取及时文章更新。记录平凡人的技术故事,分享有品质(尽量)的技术文章,偶尔也聊聊生活和理想。不贩卖焦虑,不做标题党。

如果本文对你有帮助,欢迎点赞关注监督,我们一起从青铜到王者

黄金3:雨露均沾-不要让你的线程在竞争中被“饿死”相关推荐

  1. 并发王者课-黄金3:雨露均沾-不要让你的线程在竞争中被“饿死”

    欢迎来到<并发王者课>,本文是该系列文章中的第13篇. 在上篇文章中,我们介绍了避免死锁的几种策略.虽然死锁臭名昭著,然而在并发编程中,除了死锁之外,还有一些同样重要的线程活跃性问题值得关 ...

  2. 李彦宏要给百度全员涨薪 连实习生都雨露均沾 :再没有行动,人都要被字节跳动给挖光了。

    李彦宏要给百度全员涨薪 连实习生都雨露均沾 尽管百度的市值又创新低,百度的员工却迎来一个好消息. 百度董事长.CEO李彦宏日前在内部会议中说,百度会全员涨薪,今年的涨薪幅度比去年还更多,有可能年终奖再 ...

  3. 计算机装机比赛感想,装机赛 篇一:一次雨露均沾的装机比赛

    装机赛 篇一:一次雨露均沾的装机比赛 2019-12-03 19:04:49 26点赞 61收藏 61评论 创作立场声明:装机大赛获奖作品分享 前言 今天给大家分享一下我在参加百度贴吧装机大赛的获奖作 ...

  4. “独得恩宠”OR “雨露均沾”,这个夏天你说了算

    盛夏已至,万物郁葱. 古人眼里的夏天 VS你眼里的夏天 古人眼里的夏天: 荷叶罗裙一色裁,芙蓉向脸两边开.--王昌龄<采莲曲> 黄梅时节家家雨,青草池塘处处蛙.--赵师秀<约客> ...

  5. 雨露均沾做音频增量,荔枝“回声计划”能让播客挖到宝?

    文|曾响铃 来源|科技向令说(xiangling0815) 移动音频蠢蠢欲动. 国际市场上,Spotify和苹果一对老冤家对垒,2月Spotify斥资3.4亿美元收购Gimlet和Anchor,7月媒 ...

  6. 基于均一化方法的Trip钢本构模型在Abaqus中umat子程序的实现

    一.问题提出 TRIP钢是一种典型的多相复合材料,且在形变过程中会发生马氏体相变,采用传统的本构模型难以准确地描述其力学行为.但是可以在建立马氏体相变和宏观应变的关系基础上,采取细观力学的方法对TRI ...

  7. 黄金三月,掌握这些,在六十万iOS程序员中脱颖而出

    前言 最近和圈内比较技术不错的开发者上周也聊到这一块.谈到iOS核心技术的进阶以及开发者的职业路线. 觉得还是比较符合大多数开发者需求的.也聊到现在iOS开发者的焦虑: 1.做了多年的开发,觉得自己会 ...

  8. 完美,这个世界上根本就没有完美的东西

    序言 风的形态...你追求风,风就在哪里,等你到了,风又换了一种形态... 银弹不存在,完美,也同样不会存在...只会在无穷大的时候趋近于完美... 风言风语 幻象...很多东西都是幻象,广告里面的总 ...

  9. 人工智能进入十年黄金窗口期

    https://www.toutiao.com/a6641329205768356355/ 2019-01-01 09:09:13 红刊财经 刘哲 微软.腾讯.阿里巴巴等科技巨头都纷纷进军了人工智能领 ...

最新文章

  1. 唐骏:毕业5年决定你命运
  2. Android实现模块 api 化
  3. 成为“首席AI架构师”的全流程方法论
  4. ASPNET开源项目
  5. Python之路--Django--form组件与model form组件
  6. 回首向来萧瑟处,也无风雨也无晴~小祁的2018
  7. 关于小型长周期项目的一些建议
  8. 干货|代码安全审计权威指南(附下载地址)
  9. 十字链表、邻接多重表
  10. vue监控指定div滑动触底
  11. Linux基础——怎么样从 Windows 通过 SSH 远程 Linux
  12. Node:项目文件使用async报错var _ref = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _calle
  13. 240.搜索二维矩阵II(力扣leetcode) 博主可答疑该问题
  14. MVC 《web考勤管理系统》 项目研发文献
  15. html网上购物系统界面,网上购物系统界面设计要点有哪些?设计思路是什么?...
  16. 中国智慧VS西方智慧-看中国IT风云
  17. CPU 显卡详细讲解
  18. thrift 编译报错 undefined reference
  19. Problem - 1335E2 - Codeforces(暴力+优化)
  20. java内存模型作用是什么意思_JMM(Java内存模型)是什么?为什么使用并发?

热门文章

  1. JS 返回上一步(退回上一步上一个网页)
  2. 一文了解怎样才是最好的代币经济模型,TPC藏宝计划。
  3. 财管公式计算机哪个是开平方,技巧篇丨中级财管计算器使用及公式快捷输入
  4. Android手机 全面屏(18:9屏幕)适配指南 点击打开链接
  5. 了解这些才能进行短视频app制作
  6. 桃花院长:找对象 从邂逅开始
  7. LruCache在美团DSP系统中的应用演进(生动诠释了计算机三幻神(缓存,高并发,分布式))
  8. OpenGL ES Emulator比较
  9. html2canvas.min.js 截图 多行文字错位 ;截图不全不完整
  10. TensorFlow:随机打散、批训练、预处理、循环训练