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

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();
}

}
请大家帮我分析这段代码造成死锁的原因
...全文
739 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
  • 打赏
  • 举报
回复
欢迎大家热烈指正
内容概要:本文介绍了一种基于多目标粒子群算法(MOPSO)的微电网优化调度模型,综合考虑风能、光伏、储能系统、柴油发电机、燃气轮机以及与主电网之间的能量交互等多种分布式能源的协同运行。通过构建以运行成本最小化、碳排放最低化和系统可靠性最优化为目标的多目标优化模型,利用Matlab平台实现MOPSO算法求解,完成对微电网在不同运行场景下的能量管理与调度方案优化。该模型能够有效平衡经济性与环保性之间的关系,适用于含多类型分布式电源的复杂微电网系统,具有较强的工程应用价值和科研参考意义; 适合人群:具备一定电力系统基础知识和Matlab编程能力的研究生、科研人员及工程技术人员,尤其适合从事微电网、智能电网、综合能源系统、可再生能源集成与优化调度等领域研究的专业人士; 使用场景及目标:①用于多能源耦合微电网系统的协同优化调度研究;②支持多目标智能优化算法在能源系统中的建模与求解实践,助用户掌握MOPSO在实际工程问题中的应用方法;③为学术论文复现、毕业设计、科研项目开发提供完整的代码实例与技术支撑; 阅读建议:建议读者结合Matlab代码与理论文档,深入理解目标函数构建、约束条件处理及Pareto最优解集生成机制,重点关注算法参数设置、多目标权衡分析与结果可视化,并可通过调整能源配置或引入新约束进行二次开发与创新研究。

62,622

社区成员

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

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