请大家帮我分析这段代码造成死锁的原因

ly954772930 2019-01-29 04:53:09
尊敬的各位论坛的小伙伴们,对于下列代码不能解释清楚死锁的原因:
首先贴代码吧:
Account.java
public class Account {
private String acccountNo;
private double balance;
private volatile boolean flag = false;
private int i = 0;

public Account() {

}

public Account(String accountNo, double balance) {
this.acccountNo = acccountNo;
this.balance = balance;
}

public String getAcccountNo() {
return acccountNo;
}

public void setAcccountNo(String acccountNo) {
this.acccountNo = acccountNo;
}

public double getBalance() {
return this.balance;
}

public void draw(double drawAmount) {
synchronized (Account.class) {
if (!flag) {
try {
Account.class.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} else {
System.out.println(Thread.currentThread().getName() + "取钱:" + drawAmount);
balance -= drawAmount;
System.out.println("账户余额为:" + balance);
// 将标识账户是否有存款的旗标设为false
if (balance < 0) {
i++;
System.out.println(
"******************************************************************************************************************************************"
+ i);
flag = false;
Account.class.notifyAll();
}
}
System.out.println(flag);
}

}

public void deposit(double depositAmount) {
synchronized (Account.class) {
if (flag) {
try {
Account.class.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} else {
System.out.println(Thread.currentThread().getName() + "存款:" + depositAmount);
balance += depositAmount;
System.out.println("账户余额为:" + balance);
if (balance > 0) {
flag = true;
Account.class.notifyAll();
}
}
System.out.println(flag);
}
}
}
DepositThread.java
public class DepositThread extends Thread {
// 模拟用户账户
private Account account;
private double depositAmount;

public DepositThread(String name, Account account, double depositAmount) {
super(name);
this.account = account;
this.depositAmount = depositAmount;
}

@Override
public void run() {
for (int i = 0; i < 100; i++) {
account.deposit(depositAmount);
}
}

}
DrawThread.java
public class DrawThread extends Thread {
private Account account;
private double drawAmount;

public DrawThread(String name, Account account, double drawAmount) {
super(name);
this.account = account;
this.drawAmount = drawAmount;
}

@Override
public void run() {
for(int i=0;i<100;i++) {
account.draw(drawAmount);
}
}
}
测试代码:
DrawTest.java
public class DrawTest {
public static void main(String[] args) {
// 创建一个账户
Account acct = new Account("1234567", 0);
new DrawThread("取钱者甲", acct, 80000).start();
new DrawThread("取钱者乙", acct, 80000).start();
new DrawThread("取钱者丙", acct, 80000).start();

new DepositThread("存钱者张", acct, 80000).start();
new DepositThread("存钱者王", acct, 80000).start();
new DepositThread("存钱者刘", acct, 80000).start();
}

}
请大家帮我分析这段代码造成死锁的原因
...全文
664 8 打赏 收藏 转发到动态 举报
写回复
用AI写文章
8 条回复
切换为时间正序
请发表友善的回复…
发表回复
liuzhou127 2019-02-23
  • 打赏
  • 举报
回复
控制条件一般都写成while
it-partner 2019-02-19
  • 打赏
  • 举报
回复
把等待条件做成两个变量,一个控制一个,就不会死锁了,被等待线程被唤醒的时候,不能保证就能执行,还是有一个竞争的过程的。
qq_39936465 2019-02-15
  • 打赏
  • 举报
回复
因为notifyAll是随机唤醒,开始的时候可能draw的3个进程都运行了1次全部进入await状态,然后deposit的一个线程运行一次后,又被draw的3个进程抢先运行后又分别进入await状态 。。。。最后造成的结果就是draw的3个进程100次都用完了,deposit起码有2个进程的次数还没用完,这样肯定死锁咯
咫尺天涯$ 2019-02-14
  • 打赏
  • 举报
回复
其实你这里有一个误区,就是 draw 线程的 notifyAll 一定会唤醒 deposit 线程,而 deposit 线程的 notifyAll 一定会唤醒 draw 线程,如果两个方法各自只有一个线程的话确实是如此,也不会出现死锁,比如这样
// 创建一个账户
        Account acct = new Account("1234567", 0);
        new DrawThread("取钱者甲", acct, 80000).start();
        //new DrawThread("取钱者乙", acct, 80000).start();
        //new DrawThread("取钱者丙", acct, 80000).start();

        new DepositThread("存钱者张", acct, 80000).start();
        //new DepositThread("存钱者王", acct, 80000).start();
        //new DepositThread("存钱者刘", acct, 80000).start();
问题的关键是 notifyAll 方法是随机唤醒一个监听此对象的线程,那么当 draw 线程唤醒了另一个 draw 线程,或者 deposit 线程唤醒了另一个 deposit 线程的时候,此时由于 flag 进入 await 条件一致,那么这个被唤醒的线程将会进入 await 状态(循环了 100 次,所以有机会),这个时候整个程序所有的线程都处于 await
:: 2019-02-13
  • 打赏
  • 举报
回复
我看了下你这是存款或者取款一方的执行次数(就是循环的次数)用完,另一方没用完导致的。比如存款者全部循环了100次,取款者甲还有循环次数然而当前余额小于0就是死锁了。
qq_39936465 2019-01-30
  • 打赏
  • 举报
回复
你判断用if的话,全部唤醒后,不会再执行判断,肯定死锁,这里要用while继续判断flag


public void draw(double drawAmount) {
synchronized (Account.class) {
while (!flag) {
try {
Account.class.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + "取钱:" + drawAmount);
balance -= drawAmount;
System.out.println("账户余额为:" + balance);
// 将标识账户是否有存款的旗标设为false
if (balance < 0) {
i++;
System.out.println(
"******************************************************************************************************************************************"
+ i);
flag = false;
Account.class.notifyAll();
}

System.out.println(flag);
}

}



public void deposit(double depositAmount) {
synchronized (Account.class) {
while (flag) {
try {
Account.class.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + "存款:" + depositAmount);
balance += depositAmount;
System.out.println("账户余额为:" + balance);
if (balance > 0) {
flag = true;
Account.class.notifyAll();
}

System.out.println(flag);
}
}
anakin_feng 2019-01-29
  • 打赏
  • 举报
回复
因为Account.class.notifyAll()不能确定是存钱者还是取钱者被唤醒,当其中一个执行完之后,flag就不会修改了
ly954772930 2019-01-29
  • 打赏
  • 举报
回复
欢迎大家热烈指正

62,612

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧