并发编程中,如何区分临界区、阻塞、非阻塞、死锁、饥饿和活锁?

2026-05-27 16:461阅读0评论SEO资源
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计1878个文字,预计阅读时间需要8分钟。

并发编程中,如何区分临界区、阻塞、非阻塞、死锁、饥饿和活锁?

本文简要介绍并发编程中的基本概念,并列举一些常见概念,如并发与并行、同步与异步、锁与信号量等。参考《并发编程专栏》,以下是一些基本概念:

1. 并发与并行:并发指多个任务同时执行,而并行指多个任务在同一时刻执行。在多核处理器上,并行可以实现真正的多任务同时执行。

2. 同步与异步:同步指任务之间有明确的执行顺序,如使用互斥锁保证数据一致性;异步指任务之间没有固定的执行顺序,如使用事件驱动。

3. 锁与信号量:锁用于保证数据的一致性,防止多个线程同时访问共享资源;信号量用于控制对共享资源的访问,如PV操作。

4. 线程与进程:线程是进程的一部分,共享进程的地址空间;进程是系统进行资源分配和调度的基本单位。

5. 线程池:线程池是管理一组线程的机制,可以避免频繁创建和销毁线程,提高程序性能。

6. 线程安全:线程安全指多个线程同时访问共享资源时,程序仍能正常运行,不出现数据不一致等问题。

7. 死锁:死锁指多个线程在执行过程中,因争夺资源而陷入无限等待的状态。

8. 活锁:活锁指线程在执行过程中,因条件不满足而不断尝试,但最终无法完成任务的状况。

9. 饥饿:饥饿指线程因资源不足而无法执行的状态。

通过了解这些基本概念,有助于更好地理解和应用并发编程技术。

本文介绍并发编程中的若干概念,实际上在笔者之前的文章中,已经介绍过很多概念。比如:并发与并行、同步与异步、锁与信号量等等。参考《并发编程专栏》,本文计息介绍一些相对深入一些的概念

一、临界区

为了方便大家理解,我们先看下面的这样一张图,我们可以把房子看作一个进程,每个房子里面的住户及其活动看作一个线程,饮水机、健身器材、厕所都属于共享资源。这里的共享资源实际就是临界区的概念,临界区的资源在同一时间只能被一个线程(住户)使用,所以一旦临界资源被占用,其他的线程(住户)能做的就只有等待。

并发编程中,如何区分临界区、阻塞、非阻塞、死锁、饥饿和活锁?

比如,在一个出租房内,住户A占用了厕所,在他使用厕所的这段时间内厕所这个资源就是他独占的。如果住户B此时也想上厕所,就只能等待住户A上完厕所之后才可以继续使用该资源。

二、阻塞和非阻塞

了解了临界区的概念之后,阻塞概念就好理解了。一个线程先占用了临界区的资源,此时如果其他的线程想使用临界区资源就必须等待。这种占用临界区资源,阻塞其他线程继续执行的情况就是线程阻塞(Blocking)。

然而说到非阻塞,一般说的就是是否对当前线程自己产生阻塞,比如:

  • 我执行一个任务,比如使用饮水机接水。我拿了一个杯子接水,而我必须在饮水机前面等着水接完,这种就是阻塞式线程。
  • 如果我拿了杯子接水,把杯子放到饮水机下面,饮水机会在杯子接满水之后,自动对我发出异步通知(比如声音告警)。我可以在此期间做其他的事情,这种就是非阻塞式线程(Non-Blocking)。非阻塞式线程,从编程的角度一般都是通过回调函数,或者响应式编程(Reactive programming)实现的。
三、死锁、饥饿和活锁
  • 死锁:我们来看上面的这张图,在十字路口A车道的A1车像转向B车道,但B车道入口被B1车占用;在十字路口B车道的B1车像转向C车道,但C车道入口被C1车占用;在十字路口C车道的C1车像转向D车道,但D车道入口被D1车占用;在十字路口D车道的D1车像转向A车道,但A车道入口被A1车占用;也就是说:线程因为资源竞争,彼此需要资源又都无法释放,导致线程无法获取下一步执行所需的资源,导致死锁产生。

  • 饥饿:举个例子农民给小鸡喂食,如果有五只鸡每次都刚好给五只鸡的饲料量。无法避免的是有的鸡吃的量超过规划量,最总导致某一只鸡无法吃到足够的饲料。由于它无法迟到足够的饲料,它就比较瘦弱,抢食的能力弱。恶性循环,最终很可能被饿死。具体到编程层面,就是某一线程A的优先级比较低,然后优先级高的线程又经常占用资源不释放,线程A长期无法得到有效执行,处于饥饿状态。极端情况下,可能被饿死。

  • 活锁:相对于死锁和饥饿,活锁是一种相对好的状态。大家在生活中肯定遇到过这样一种情况,你在楼梯拐角遇到一个同事,空间有限所以二人茬住了。你向左移动,你的同事也向左移动;你向右移动,你的同事也向右移动;所以你们两个人都无法向前移动,这就是一个典型的活锁。因为人是高智慧的动物,又都懂得礼让,所以对于人来说活锁的问题很好解决,只要其中一个人原地不动,另一个人动一下就过去了。但是多线程面对活锁的时候就没有那么智能了,有可能出现不断地释放资源(向左移)、占用资源(向右移)的循环中,即使最终活锁被解开,其资源开销及时间成本都是很大的。

欢迎关注我的博客,更多精品知识合集

本文转载注明出处(必须带连接,不能只转文字):字母哥博客 - zimug.com

觉得对您有帮助的话,帮我点赞、分享!您的支持是我不竭的创作动力!。另外,笔者最近一段时间输出了如下的精品内容,期待您的关注。

  • 《kafka修炼之道》
  • 《手摸手教你学Spring Boot2.0》
  • 《Spring Security-JWT-OAuth2一本通》
  • 《实战前后端分离RBAC权限管理系统》
  • 《实战SpringCloud微服务从青铜到王者》

本文共计1878个文字,预计阅读时间需要8分钟。

并发编程中,如何区分临界区、阻塞、非阻塞、死锁、饥饿和活锁?

本文简要介绍并发编程中的基本概念,并列举一些常见概念,如并发与并行、同步与异步、锁与信号量等。参考《并发编程专栏》,以下是一些基本概念:

1. 并发与并行:并发指多个任务同时执行,而并行指多个任务在同一时刻执行。在多核处理器上,并行可以实现真正的多任务同时执行。

2. 同步与异步:同步指任务之间有明确的执行顺序,如使用互斥锁保证数据一致性;异步指任务之间没有固定的执行顺序,如使用事件驱动。

3. 锁与信号量:锁用于保证数据的一致性,防止多个线程同时访问共享资源;信号量用于控制对共享资源的访问,如PV操作。

4. 线程与进程:线程是进程的一部分,共享进程的地址空间;进程是系统进行资源分配和调度的基本单位。

5. 线程池:线程池是管理一组线程的机制,可以避免频繁创建和销毁线程,提高程序性能。

6. 线程安全:线程安全指多个线程同时访问共享资源时,程序仍能正常运行,不出现数据不一致等问题。

7. 死锁:死锁指多个线程在执行过程中,因争夺资源而陷入无限等待的状态。

8. 活锁:活锁指线程在执行过程中,因条件不满足而不断尝试,但最终无法完成任务的状况。

9. 饥饿:饥饿指线程因资源不足而无法执行的状态。

通过了解这些基本概念,有助于更好地理解和应用并发编程技术。

本文介绍并发编程中的若干概念,实际上在笔者之前的文章中,已经介绍过很多概念。比如:并发与并行、同步与异步、锁与信号量等等。参考《并发编程专栏》,本文计息介绍一些相对深入一些的概念

一、临界区

为了方便大家理解,我们先看下面的这样一张图,我们可以把房子看作一个进程,每个房子里面的住户及其活动看作一个线程,饮水机、健身器材、厕所都属于共享资源。这里的共享资源实际就是临界区的概念,临界区的资源在同一时间只能被一个线程(住户)使用,所以一旦临界资源被占用,其他的线程(住户)能做的就只有等待。

并发编程中,如何区分临界区、阻塞、非阻塞、死锁、饥饿和活锁?

比如,在一个出租房内,住户A占用了厕所,在他使用厕所的这段时间内厕所这个资源就是他独占的。如果住户B此时也想上厕所,就只能等待住户A上完厕所之后才可以继续使用该资源。

二、阻塞和非阻塞

了解了临界区的概念之后,阻塞概念就好理解了。一个线程先占用了临界区的资源,此时如果其他的线程想使用临界区资源就必须等待。这种占用临界区资源,阻塞其他线程继续执行的情况就是线程阻塞(Blocking)。

然而说到非阻塞,一般说的就是是否对当前线程自己产生阻塞,比如:

  • 我执行一个任务,比如使用饮水机接水。我拿了一个杯子接水,而我必须在饮水机前面等着水接完,这种就是阻塞式线程。
  • 如果我拿了杯子接水,把杯子放到饮水机下面,饮水机会在杯子接满水之后,自动对我发出异步通知(比如声音告警)。我可以在此期间做其他的事情,这种就是非阻塞式线程(Non-Blocking)。非阻塞式线程,从编程的角度一般都是通过回调函数,或者响应式编程(Reactive programming)实现的。
三、死锁、饥饿和活锁
  • 死锁:我们来看上面的这张图,在十字路口A车道的A1车像转向B车道,但B车道入口被B1车占用;在十字路口B车道的B1车像转向C车道,但C车道入口被C1车占用;在十字路口C车道的C1车像转向D车道,但D车道入口被D1车占用;在十字路口D车道的D1车像转向A车道,但A车道入口被A1车占用;也就是说:线程因为资源竞争,彼此需要资源又都无法释放,导致线程无法获取下一步执行所需的资源,导致死锁产生。

  • 饥饿:举个例子农民给小鸡喂食,如果有五只鸡每次都刚好给五只鸡的饲料量。无法避免的是有的鸡吃的量超过规划量,最总导致某一只鸡无法吃到足够的饲料。由于它无法迟到足够的饲料,它就比较瘦弱,抢食的能力弱。恶性循环,最终很可能被饿死。具体到编程层面,就是某一线程A的优先级比较低,然后优先级高的线程又经常占用资源不释放,线程A长期无法得到有效执行,处于饥饿状态。极端情况下,可能被饿死。

  • 活锁:相对于死锁和饥饿,活锁是一种相对好的状态。大家在生活中肯定遇到过这样一种情况,你在楼梯拐角遇到一个同事,空间有限所以二人茬住了。你向左移动,你的同事也向左移动;你向右移动,你的同事也向右移动;所以你们两个人都无法向前移动,这就是一个典型的活锁。因为人是高智慧的动物,又都懂得礼让,所以对于人来说活锁的问题很好解决,只要其中一个人原地不动,另一个人动一下就过去了。但是多线程面对活锁的时候就没有那么智能了,有可能出现不断地释放资源(向左移)、占用资源(向右移)的循环中,即使最终活锁被解开,其资源开销及时间成本都是很大的。

欢迎关注我的博客,更多精品知识合集

本文转载注明出处(必须带连接,不能只转文字):字母哥博客 - zimug.com

觉得对您有帮助的话,帮我点赞、分享!您的支持是我不竭的创作动力!。另外,笔者最近一段时间输出了如下的精品内容,期待您的关注。

  • 《kafka修炼之道》
  • 《手摸手教你学Spring Boot2.0》
  • 《Spring Security-JWT-OAuth2一本通》
  • 《实战前后端分离RBAC权限管理系统》
  • 《实战SpringCloud微服务从青铜到王者》