有一个多线程环境下的存取款协调控制的程序
程序通过一个旗标标识账户中是否已经有存款。当旗标为false时表示账户中没有存款,存款者线程可以向下执行,当存款者把钱存入账户后,将旗标设置为true,并调用notify或notifyAll方法来唤醒其他线程;当存款者线程进入线程体后,如
果旗标为true则调用wait方法阻塞该线程。当旗标为true时表示账户中已经存款,则取款者线程可以向下执行,当取款者把钱从账户中取出后,将旗标设置为false,并调用notify或notifyAll方法来唤醒其他线程;当取款者线程进入线程体后,如果旗标为false则调用wait方法阻塞该线程。
/**
 * 账户类
 * 
 * @author Bank
 * 
 */
public class Account {
private String id;// 账号
private double balance;// 余额
private boolean flag = false;// 旗标为false表示没有存款,为true表示已经存款 public Account(String id, double balance) {
this.id = id;
this.balance = balance;
} public String getId() {
return id;
} public void setId(String id) {
this.id = id;
} public double getBalance() {
return balance;
} public void setBalance(double balance) {
this.balance = balance;
} /**
 * 取款方法
 * 
 * @param drawAmount
 *            取款金额
 */
public synchronized void draw(double drawAmount) { try {
if (!flag) {// 如果flag为false,表示账户中还没有存款进去,则取款方法阻塞
wait();
} else {
// 执行取款
System.out.println(Thread.currentThread().getName()
+ "取钱成功!吐出钞票:" + drawAmount); this.setBalance(this.getBalance() - drawAmount);// 修改余额
System.out.println("余额为:" + this.getBalance()); flag = false; // 将标识账户是否已经存款的旗标设置为false;
notifyAll();// 唤醒其他线程
}
} catch (InterruptedException e) {
e.printStackTrace();
} } /**
 * 存款方法
 * 
 * @param depositAmount
 *            存款金额
 */
public synchronized void deposit(double depositAmount) {
try {
if (flag) {// 如果flag为true,表示该账户已经已经有人存款进去,则存款方法阻塞
wait();
} else {
// 执行存款 System.out.println(Thread.currentThread().getName() + "存款:"
+ depositAmount); this.setBalance(this.getBalance() + depositAmount);// 修改余额
System.out.println("余额为:" + this.getBalance()); flag = true; // 将标识账户是否已经存款的旗标设置为true;
notifyAll();// 唤醒其他线程
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}}
/**
 * 存钱的线程类 根据指定账户、存钱数量进行存钱操作
 * 
 * @author Administrator
 */
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;
} /**
 * 重复10次存款操作
 */
public void run() {
for (int i = 0; i < 10; i++) {
this.account.deposit(this.depositAmount);
}
}
}
/**
 * 取钱的线程类 根据指定账户、取钱数量进行取钱操作
 * 
 * @author Administrator
 */
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;
} /**
 * 重复10次取款操作
 */
public void run() {
for (int i = 0; i < 10; i++) {
this.account.draw(this.drawAmount);
}
}}
/**
 * 测试类
 * 
 * @author Bank
 * 
 */
public class Test {
public static void main(String args[]) { Account account = new Account("123456", 0); // 创建一个账户
// 生成2个线程同时存取款
new DrawThread("取款者A", account, 800).start();
new DepositThread("存款者甲", account, 800).start(); }
}
运行结果:存款者甲存款:800.0
余额为:800.0
取款者A取钱成功!吐出钞票:800.0
余额为:0.0
存款者甲存款:800.0
余额为:800.0
取款者A取钱成功!吐出钞票:800.0
余额为:0.0
存款者甲存款:800.0
余额为:800.0
取款者A取钱成功!吐出钞票:800.0
余额为:0.0
存款者甲存款:800.0
余额为:800.0
取款者A取钱成功!吐出钞票:800.0
余额为:0.0
存款者甲存款:800.0
余额为:800.0
取款者A取钱成功!吐出钞票:800.0
余额为:0.0
疑惑:
取款线程和存款线程各自循环了10次,应该会打印10次存取款啊,怎么只打印了5次存取款?试了好几次都这样。

解决方案 »

  1.   

    你这个正常的, 你要分析阻塞线程被唤醒后从哪开始接着执行. if (!flag)  // 如果flag为false,表示账户中还没有存款进去,则取款方法阻塞
    {
    wait();
    }看上面的程序片断,这是取自取款线程. 在没有款的时候,进入等待了. 当存款线程存款后,notifyAll(),将唤醒此取款线程。接着 wait() 后继续运行,但程序什么也不干就退出了。 等于这次取款被放弃了。要到下一循环,才取款。(循环2次取一次款)。
    改正方法是: 把else语句后的语句,加在wait()后就应该可以了。
    那个存款线程也一样。