避免活跃性危险(第十章)

简介:

避免活跃性危险

在安全性与活跃性之间通常存在着某种制衡,我们使用加锁机制来确保线程安全,但如果过度地使用加锁,则可能导致“锁顺序死锁”。同样,我们使用线程池和信号量来限制对资源的使用,但这些被限制的行为可能会导致资源死锁。

1. 死锁

  • 锁顺序死锁:两个线程试图以不同的顺序来获得相同的锁,如果按照相同的顺序来请求锁,那么就不会出现循环的加锁依赖性,因此也就不会产生死锁。
    在制定锁的顺序时,可以使用System.identityHashCode方法,该方法返回有Object.hashCode返回的值,通过比较大小等方法定义锁的顺序。在某些情况下,两个对象可能拥有相同的散列值,此时必须通过某种方法来决定锁的顺序,而这可能会重新引入死锁,为了避免这种情况,可以使用“加时赛”锁,在获得两个对象的锁之前,首先获得这个加时赛锁,从而保证每次只有一个线程以未知的顺序获得这两个锁。
  • 在协作对象之间发生的死锁
    如果在持有锁的情况下调用某个外部方法,那么就需要警惕在协作对象之间发生死锁。

        如果在持有锁时调用某个外部方法,那么将出现活跃性问题,在这个外部方法中可能会获得其他锁(这可能会产生死锁),或者阻塞时间过长,导致其他线程无法及时获得当前被持有的锁。
        
    
  • 开放调用
    如果在调用某个方法时不需要持有锁,那么这种调用被称为开放调用。

        在程序中应尽量使用开放调用。与那些在持有锁时调用外部方法的程序相比,更易于对依赖于开放调用的程序进行死锁分析。
        
  • 资源死锁
  1. 线程饥饿死锁。如果某些任务需要等待其他任务的结果,那么这些任务往往是产生线程饥饿死锁的主要来源。
  2. 有界线程池/资源池与相互依赖的任务不能一起使用

2. 死锁的避免与诊断

  1. 如果一个程序每次至多只能获得一个锁,那么就不会产生锁顺序死锁。
  2. 如果必须获取多个锁,那么在设计时必须考虑锁的顺序:尽量减少潜在的加锁交互数量,将获取锁时需要遵循的协议写入正式文档并始终遵循这些协议。
  3. 在使用细粒度锁的程序中,可以通过使用一种两阶段策略来检查代码中的死锁:首先,找出在什么地方将获取多个锁,然后对所有这些实例进行全局分析,从而确保它们在整个程序中获取锁的顺序都保持一致。
  4. 使用显示锁Lock类中的定时tryLock功能,在等待超过指定时间后tryLock会放回一个失败信息。

3. 其他活跃性危险

  1. 饥饿:当线程由于无法访问它所需要的资源而不能继续执行时,就发生了“饥饿”。

引发饥饿的最常见资源就是CPU时钟周期,如果在Java应用程序中对线程的优先级使用不当,或者在持有锁时执行一些无法结束的结构(例如无限循环,或者无限制地等待某个资源),那么也可能导致饥饿,因为其他需要这个锁的线程将无法得到它。线程优先级并不是一种直观的机制,而通过修改线程优先级所带来的效果通常也不明显。当提高某个线程的优先级时,可能不会起到任何作用,或者也可能使得某个线程的调度优先级高于其他线程,从而导致饥饿。

  1. 活锁(Livelock)

活锁是另一种形式的活跃性问题,该问题不会导致线程阻塞,但也不能继续执行。因为线程将不断重复执行相同的操作,而且总会失败
活锁通常发生在处理事务消息的应用程序中:如果不能成功处理某个消息,那么消息处理机制将回滚整个事务,并将它重新放到队列的开头。当多个相互协作的线程都对彼此进行响应从而修改各自的状态,并使得任何一个线程无法继续执行时,就发生了活锁,在并发应用程序中,通过等待随机长度的时间和回退可以有效避免活锁的发生。

相关文章
|
4月前
|
测试技术
ACL 2024:大模型性能掺水严重?北大交出答卷:交互评估+动态出题,死记硬背也没用
【7月更文挑战第8天】北大研究团队推出KIEval框架,针对大语言模型(LLMs)的性能评估进行创新。KIEval采用互动评估和动态出题,通过多轮基于知识的对话测试模型理解和应用能力,旨在减少数据污染影响,挑战死记硬背的评估。然而,该方法可能增加计算需求,且评估结果可能受主观因素影响,不适用于所有类型LLMs。[论文链接:](https://arxiv.org/abs/2402.15043)**
89 24
|
4月前
|
缓存
线程操纵术并行策略问题之工作窃取机制问题如何解决
线程操纵术并行策略问题之工作窃取机制问题如何解决
|
6月前
|
算法 搜索推荐 数据挖掘
掌握程序员之剑:解析常见算法与其在生活和工作中的影响
掌握程序员之剑:解析常见算法与其在生活和工作中的影响
91 1
|
6月前
|
监控 安全
线程死循环是多线程应用程序开发过程中一个难以忽视的问题,它源于线程在执行过程中因逻辑错误或不可预见的竞争状态而陷入永久运行的状态,严重影响系统的稳定性和资源利用率。那么,如何精准定位并妥善处理线程死循环现象,并在编码阶段就规避潜在风险呢?谈谈你的看法~
避免线程死循环的关键策略包括使用同步机制(如锁和信号量)、减少共享可变状态、设置超时、利用监控工具、定期代码审查和测试、异常处理及设计简洁线程逻辑。通过这些方法,可降低竞态条件、死锁风险,提升程序稳定性和可靠性。
100 0
Zp
|
XML 算法 IDE
提升:抛弃七条不良编码习惯
提升:抛弃七条不良编码习惯
Zp
122 0
|
存储 安全 算法
重生之我在人间敲代码_Java并发基础_安全性、活跃性以及性能问题
并发编程中我们需要注意的问题有很多,很庆幸前人已经帮我们总结过了,主要有三个方面,分别是:安全性问题、活跃性问题和性能问题。
国外隔离迷惑行为:这个网站帮你复现办公室白噪音,还能自行决定同事数量
国外隔离迷惑行为:这个网站帮你复现办公室白噪音,还能自行决定同事数量
147 0
|
安全
细节是魔鬼——基于计数器的锁机制的实现准则
有点标题党了,本意是想把对内核锁机制的一些实现细节记录下来,但多少反映了锁机制实现时的一些准则。本文讨论的锁机制主要指基于计数器的锁机制例如 spinlock、mutex,不包括 RCU 这类锁机制。 ### parallesim 在讨论各种锁机制之前,有必要讨论系统的并行度,即有哪些潜在的竞争场景 1. 中断上下文与进程上下文对共享资源的访问,由于中断是异步进行的,因而中断与进程是并发执行
353 0
|
安全 Windows
蠕虫创建多重替身 利用伪装术迷惑用户
        蠕虫W32.Korron.B可谓“功能”繁多,创建多重替身、善于伪装的特点令用户难以察觉。  病毒名称:W32.Korron.B  病毒类型:蠕虫  受影响的操作系统:Windows 2000/XP/Vista/NT、Windows Server 2003  病毒分析:  修改系统设置、替换特定文件、结束杀毒软件进程—W32.Korron.B蠕虫可谓“功能”繁多;创建多重替身、善于伪装的特点也令用户难以察觉该蠕虫在系统中的存在和危害。
855 0