java中常见的死锁以及解决方法代码中常见的死锁以及解决方法代码
主要介绍了java中常见的死锁以及解决方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一
定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
在java中我们常常使用加锁机制来确保线程安全,但是如果过度使用加锁,则可能导致锁顺序死锁。同样,我们使用线程池和
信号量来限制对资源的使用,但是这些被限制的行为可能会导致资源死锁。java应用程序无法从死锁中恢复过来,因此设计时
一定要排序那些可能导致死锁出现的条件。
1.一个最简单的死锁案例一个最简单的死锁案例
当一个线程永远地持有一个锁,并且其他线程都尝试获得这个锁时,那么它们将永远被阻塞。在线程A持有锁L并想获得锁M
的同时,线程B持有锁M并尝试获得锁L,那么这两个线程将永远地等待下去。这种就是最简答的死锁形式(或者叫做"抱
死")。
2.锁顺序死锁锁顺序死锁
如图:leftRight和rightLeft这两个方法分别获得left锁和right锁。如果一个线程调用了leftRight,而另一个线程调用了rightLeft,
并且这两个线程的操作是交互执行,那么它们就会发生死锁。
死锁的原因就是两个线程试图以不同的顺序来获得相同的锁。所以,如果所有的线程以固定的顺序来获得锁,那么在程序中就
不会出现锁顺序死锁的问题。
2.1.动态的锁顺序死锁动态的锁顺序死锁
我以一个经典的转账案例来进行说明,我们知道转账就是将资金从一个账户转入另一个账户。在开始转账之前,首先需要获得
这两个账户对象得锁,以确保通过原子方式来更新两个账户中的余额,同时又不破坏一些不变形条件,例如 账户的余额不能
为负数。
所以写出的代码如下:
//动态的锁的顺序死锁
public class DynamicOrderDeadlock {
public static void transferMoney(Account fromAccount,Account toAccount,int amount,int from_index,int to_index) throws Exception {
System.out.println("账户 "+ from_index+"~和账户~"+to_index+" ~请求锁");
synchronized (fromAccount) {
System.out.println(" 账户 >>>"+from_index+" <<<获得锁");
synchronized (toAccount) {
System.out.println(" 账户 "+from_index+" & "+to_index+"都获得锁");
if (fromAccount.compareTo(amount) < 0) {
throw new Exception();
}else {
fromAccount.debit(amount);
toAccount.credit(amount);
}
}
}
}
static class Account {
private int balance = 100000;//这里假设每个人账户里面初始化的钱
private final int accNo;
private static final AtomicInteger sequence = new AtomicInteger();
public Account() {
accNo = sequence.incrementAndGet();
}
void debit(int m) throws InterruptedException {
Thread.sleep(5);//模拟操作时间
balance = balance + m;
评论10