[本文是我对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).
分享到:
相关推荐
进程调度与死锁-作业 帮你复习所学的东西
操作系统课程设计 死锁的避免---银行家算法
该代码是操作系统中为了避免死锁而编写的银行家算法。
有关表死锁的详细图片 博文链接:https://meteor-1988.iteye.com/blog/1568695
解决死锁问题的三种方法:预防死锁,检测死锁及避免死锁。
课程设计-模拟银行家算法避免死锁.doc
银行家算法避免死锁 VM软件 Linux系统 C语言 成功编译 成功运行 内附完整课设报告,代码,运行cpp 附有哲学家进餐简略一题 原课设要求:死锁避免 (1)请设计一个程序演示死锁避免算法(银行家算法)。 (2)要求该...
本文档是使用C#编写的银行家算法避免死锁的程序设计。里面包含数组初始化,利用递归判断输入整数,输出安全序列等函数,希望对大家有帮助。如有错误,请多多指教~
2015 Oracle 技术嘉年华(OTN)分会场11何登成 - 管中窥豹——MySQL(InnoDB)死锁分析之道
docker mysql_一些常见的mysql死锁案例_笔记记录
这是计算机操作系统(第三版)关于利用银行家算法避免死锁的代码及程序,利用银行家算法避免死锁是最具代表性的算法(Dijkstra)
操作系统中最重要的组成部分,处理机调度问题,各种调度算法的介绍等。
oracle数据库账户被锁原因查找及处理,oracle修改用户密码后账号死锁原因查找及解决办法(Windows操作系统,Linux操作系统套路一样)
设计模拟实现死锁避免的程序,要求: 1,输入并显示资源类型数,进程数,每类资源的个体数; 2,输入每个进程对每类资源的最大需求量,已分量,算出其剩余需求量。算出系统每类资源的当前剩余量;显示输入和计算出的...
死锁1deadlock---马克-to-win java视频的详细描述与介绍
死锁2deadlock---马克-to-win java视频的详细的描述与介绍
对系统资源的申请和分配,主要是为了避免死锁问题。
计算机操作系统课本中 第三章 处理机的调度与死锁 中避免死锁的实现代码,最具代表的避免死锁的算法Dijkstra的银行家算法,和安全性检测算法。
这个程序主要通过模拟系统死锁避免的实现,使用银行家算法来避免死锁加深对死锁避免,系统安全状态等的理解。 (1)输入1执行算法,输入2退出程序,其他输入无效。算法要用到的资源种类有10种,每种资源的数目为1~10...
本次课程设计通过编写和调试一个仿真模拟银行家算法避免死锁的程序,观察产生死锁的条件,并采用银行家算法,有效地避免死锁的发生。这是我们的操作系统课程设,用.net做的。 银行家算法避免死锁,其中有三个模块,...