多线程死锁、活锁、无锁、饥饿

并发编程的核心在于维护和处理多线程,理解并发中存在的各种异常,死锁、活锁、无锁、饥饿都是可能让多线程异常阻塞的场景

所属分类 概念

相关标签 多线程异常

前言

充分理解多线程可能产生异常阻塞的场景,有利于我们并发编程时更加详尽的考虑问题

死锁、活锁、无锁、饥饿都是可能让多线程异常阻塞的场景

死锁

死锁是多线程中最差的一种情况,多个线程相互占用对方的资源的锁,又相互等对方释放锁。

这些线程则一直处理阻塞的假死状态,形成死锁。

举例:

  • 假设工具库只有一个锤子和起子。
  • A 要做一件事情,需要先用锤子,再用起子,他先拿起来锤子。
  • B 同时也要做一件事情,需要先用起子,再用锤子,他先拿起了起子。
  • A 锤子用完了,准备用起子,事情没做完前,A 不会把锤子放回工具库,但是现在没有起子,A 就等 B 把起子放回去。
  • B 起子用完了,准备用锤子,事情没做完前,B 也不会把起子放回工具库,但是现在没有锤子,B 也在等 A 把锤子放回去。
  • 于是,A 和 B 都在等待对方放回去。
  1. 互斥条件:线程在某一时间内独占资源(A 拿了锤子,B 没得用)

  2. 请求与保持条件:线程因请求资源而阻塞时(等待资源锁),对已获得的资源保持不放(事不做完 A 不把锤子放回去)

  3. 不剥夺条件:线程已获得资源,在末使用完之前,不能强行剥夺(事不做完 A 的锤子谁也拿不到)

  4. 循环等待条件:线程之间形成一种头尾相接的循环等待资源关系(A 等 B 的起子,B 等 A 的锤子)

  1. 锁粒度提升:一次锁定获取所有需要的资源,比如例子中直接锁定整个工具箱,A 直接把箱子端走。
  2. 分布式锁或乐观锁机制的引入。

活锁

活锁和死锁相反,双方拿到资源,但是非常绅士的让别人使用。

你让我,我让你,最后多个线程都无法使用资源。

举例:

  • A 和 B 都要用工具箱。
  • A 拿到工具箱后发现 B 也要用工具箱,于是把工具箱递给 B。
  • B 拿到工具箱后发现 A 也要用工具箱,于是把工具箱递给 A。
  • 离离原上谱。

无锁

无锁,即没有对资源进行锁定,即所有的线程都能访问并修改同一个资源。

但时同时只有一个线程能修改成功。

无锁是一种锁实现形式,它可能产生问题,也有可能很效率(我们常说的乐观锁就是无锁实现)。

无锁的特点,修改操作在一个循环内进行,线程会不断的尝试修改共享资源,没有冲突就修改成功并退出(大名鼎鼎的CAS就是如此)。

因此,多个线程修改同一个值必定会有一个线程能修改成功,而其他修改失败的线程会不断重试直到修改成功。

当持续时间存在大量并发是,无锁可能产生性能问题,但是某些场合下确实非常高效。

饥饿

又称饿死。

由于某些原因,线程可能始终无法获得资源锁,导致一直无法执行。

比如我们常说的线程优先级概念,高优先级的线程总会优先抢占资源并执行。

饥饿和死锁不同,饥饿在经过一段时间后,终归会被执行,比如高优先级线程都执行结束了。

米虫

做一个有理想的米虫,伪全栈程序猿,乐观主义者,坚信一切都是最好的安排!

本站由个人原创、收集或整理,如涉及侵权请联系删除

本站内容支持转发,希望贵方携带转载信息和原文链接

本站具有时效性,不提供有效、可用和准确等相关保证

本站不提供免费技术支持,暂不推荐您使用案例商业化

选择个人头像

昵称

邮箱

QQ

网址

评论提示

  • 头像:系统为您提供了12个头像自由选择,初次打开随机为你选择一个
  • 邮箱:可选提交邮箱,该信息不会外泄,或将上线管理员回复邮件通知
  • 网址:可选提交网址,评论区该地址将以外链的形式展示在您的昵称上
  • 记忆:浏览器将记忆您已选择或填写过得信息,下次评论无需重复输入
  • 审核:提供一个和谐友善的评论环境,本站所有评论需要经过人工审核