[本文是我对Java Concurrency In Practice C10的归纳和总结. 转载请注明作者和出处, 如有谬误, 欢迎在评论中指正. ]
如果多个线程以不同的顺序持有多个锁, 可能发生死锁:
public class AccountTrans {
public void transferMoney(Account fromAccount, Account toAccount, DollarAmount amount)
throws InsufficientFundsException {
synchronized (fromAccount) {
synchronized (toAccount) {
if (fromAccount.getBalance().compareTo(amount) < 0)
throw new InsufficientFundsException();
else {
fromAccount.debit(amount);
toAccount.credit(amount);
}
}
}
}
}
transferMoney方法先后锁定fromAccount和toAccount对象. 如果2个线程以如下的方式调用transferMoney方法:
A: transferMoney(myAccount, yourAccount, 10);
B: transferMoney(yourAccount, myAccount, 20);
死锁有可能就会发生.
关键在于需要保证以相同的顺序获取多个锁:
public class AccountTrans {
// 额外的锁
private static final Object tieLock = new Object();
public void transferMoney(final Account fromAcct, final Account toAcct, final DollarAmount amount)
throws InsufficientFundsException {
class Helper {
public void transfer() throws InsufficientFundsException {
if (fromAcct.getBalance().compareTo(amount) < 0)
throw new InsufficientFundsException();
else {
fromAcct.debit(amount);
toAcct.credit(amount);
}
}
}
// 计算fromAcct和toAcct的hashCode值
int fromHash = System.identityHashCode(fromAcct);
int toHash = System.identityHashCode(toAcct);
// 根据hashCode值确定获取锁的顺序
if (fromHash < toHash) {
synchronized (fromAcct) {
synchronized (toAcct) {
new Helper().transfer();
}
}
} else if (fromHash > toHash) {
synchronized (toAcct) {
synchronized (fromAcct) {
new Helper().transfer();
}
}
} else {
// 当hashCode值相同时, 无法确定fromAcct和头Acct锁的获取顺序, 因此增加额外的锁
synchronized (tieLock) {
synchronized (fromAcct) {
synchronized (toAcct) {
new Helper().transfer();
}
}
}
}
}
}
open call
所谓open call是指在未持有锁时调用外部方法. 持有锁的时候调用外部方法, 如果被调用的方法需要获取其他的锁, 可能带来死锁的风险. 如果被调用的方法发生阻塞, 当前线程将长时间持有锁, 其他等待获取该锁的线程就会被阻塞.
因此我们应该尽量在未持有锁的时候进行方法的调用.
资源死锁
比如线程A持有数据库D1的连接, 并等待获取数据库D2的连接. 而线程B持有数据库D2的连接, 并等待获取数据库D1的连接. 此时就发生了死锁.
资源死锁的另一种形式是线程饥饿死锁, 参见第八章.
避免死锁
1. 尽量不要同时持有多个锁.
2. 如果必须同时持有多个锁, 那么保证以一致的顺序获取锁.
3. 尽量在未持有锁的情况下进行方法的调用(open call).
分享到:
相关推荐
操作系统课程设计死锁的避免---银行家算法 死锁是操作系统中的一种常见问题,它会导致系统性能下降甚至崩溃,因此避免死锁是操作系统设计中的一项重要任务。银行家算法是避免死锁的一种常用方法,本文将对银行家...
银行家算法是操作系统中避免死锁的一种方法,其主要思想是通过引入银行家模型来避免死锁的发生。在该模型中,操作系统将资源看作是一家银行,进程是银行的客户,每个进程可以请求一定数量的资源,当某个进程请求的...
最后,为了避免死锁的发生,开发人员和数据库管理员应进行充分的性能监控和调优,理解事务的执行路径,合理规划资源的获取顺序,并定期审查和更新数据库设计。通过这种方式,可以显著降低死锁的发生概率,保证Oracle...
针对这一问题,数据库管理系统通常采用三种策略来解决:预防死锁、检测死锁以及避免死锁。 ### 预防死锁 预防死锁是最为保守的策略,其核心思想是在事务开始前就尽可能避免死锁的发生。这主要通过以下几种方式实现...
### 进程调度与死锁-作业 #### 进程调度与死锁基础知识解析 **进程调度**在操作系统中扮演着至关重要的角色,它决定了进程何时以及如何使用处理器和其他系统资源。进程调度策略多种多样,包括但不限于先进先出...
银行家算法避免死锁知识点 银行家算法的背景和目的 在多道程序系统中,多个进程的并发执行可以提高系统的利用率和吞吐量,但是可能会发生死锁,导致进程无法继续执行。死锁是多个进程在运行过程中因争夺资源而造成...
银行家算法避免死锁 VM软件 Linux系统 C语言 成功编译 成功运行 内附完整课设报告,代码,运行cpp 附有哲学家进餐简略一题 原课设要求:死锁避免 (1)请设计一个程序演示死锁避免算法(银行家算法)。 (2)要求该...
3. **死锁避免**:在应用层实现死锁避免算法,例如,每次请求资源前检查是否会导致死锁。 4. **合理使用索引**:优化查询语句,减少全表扫描,避免不必要的间隙锁。 5. **并发控制**:考虑使用乐观锁或悲观锁策略...
本文档是使用C#编写的银行家算法避免死锁的程序设计。里面包含数组初始化,利用递归判断输入整数,输出安全序列等函数,希望对大家有帮助。如有错误,请多多指教~
本实验主要目的是让学生通过实践操作,深入理解操作系统中死锁避免的相关理论和技术,并能够掌握如何利用编程手段来实现银行家算法,以此来检验和避免系统进入不安全状态,防止死锁的发生。通过本次实验,学生能够更...
死锁1deadlock---马克-to-win java视频的详细描述与介绍
死锁2deadlock---马克-to-win java视频的详细的描述与介绍
对系统资源的申请和分配,主要是为了避免死锁问题。
操作系统实验报告-利用银行家算法避免死锁 本实验报告的目的是为了加深了解有关资源申请、避免死锁等概念,并体会和了解死锁和避免死锁的具体实施方法。通过使用银行家算法,有效地防止和避免死锁的发生。 一、...
这个程序主要通过模拟系统死锁避免的实现,使用银行家算法来避免死锁加深对死锁避免,系统安全状态等的理解。 (1)输入1执行算法,输入2退出程序,其他输入无效。算法要用到的资源种类有10种,每种资源的数目为1~10...
本次课程设计通过编写和调试一个仿真模拟银行家算法避免死锁的程序,观察产生死锁的条件,并采用银行家算法,有效地避免死锁的发生。这是我们的操作系统课程设,用.net做的。 银行家算法避免死锁,其中有三个模块,...
银行家算法是一种最有代表性的避免死锁的算法。在避免死锁方法中允许进程动态地申请资源,但系 [银行家算法] 银行家算法 统在进行资源分配之前,应先计算此次分配资源的安全性,若分配不会导致系统进入不安全状态,...
InnoDB引擎通过死锁检测机制来识别并解决这类问题,但了解死锁产生的原因能帮助我们更好地避免它们。 二、不常见死锁情况1:索引顺序不同 当两个事务分别按照不同的顺序访问同一组资源时,可能会导致死锁。例如,...