尊敬的各位论坛的小伙伴们,对于下列代码不能解释清楚死锁的原因:
首先贴代码吧:
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();
}}
请大家帮我分析这段代码造成死锁的原因

解决方案 »

  1.   

    因为Account.class.notifyAll()不能确定是存钱者还是取钱者被唤醒,当其中一个执行完之后,flag就不会修改了
      

  2.   

    你判断用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);
    }
    }
      

  3.   

    其实你这里有一个误区,就是 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
      

  4.   

    因为notifyAll是随机唤醒,开始的时候可能draw的3个进程都运行了1次全部进入await状态,然后deposit的一个线程运行一次后,又被draw的3个进程抢先运行后又分别进入await状态 。最后造成的结果就是draw的3个进程100次都用完了,deposit起码有2个进程的次数还没用完,这样肯定死锁咯
      

  5.   

    控制条件一般都写成while