线程同步:银行帐户存、取款问题

1.银行账户类

package com.bankAccount.test;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Account {
	//显式定义Lock对象
	private final Lock lock=new ReentrantLock(); 
	//获得指定Lock对象对应的Condition
	private final Condition cond=lock.newCondition();
	//封装账户编号,账户余额的两个成员变量
	private String accoutNo;
	private double balance;
	//标识账户中是否已有存款的旗标
	private boolean flag=false;
	public Account(){}
	//构造器
	public Account(String accountNo,double balance)
	{
		this.accoutNo=accountNo;
		this.balance=balance;
	}
	public String getAccoutNo() {
		return accoutNo;
	}
	public void setAccoutNo(String accoutNo) {
		this.accoutNo = accoutNo;
	}
	//因为账户余额不可以随便修改,所以只为balance提供getter方法
	public double getBalance() {
		return this.balance;
	}
	public void draw(double drawAmount)
	{
		//加锁
		lock.lock();
		try{
			if(!flag)
			{
				cond.await();
			}
			else
			{
				//执行取钱操作
				System.out.println(Thread.currentThread().getName()+
						"取钱:"+drawAmount);
				balance-=drawAmount;
				System.out.println("账户余额为:"+balance);
				//将标识账户是否已有存款的旗标设为false
				flag=false;
				//唤醒其他进程
				cond.signalAll();
			}
		}
		catch(InterruptedException ex)
		{
			ex.printStackTrace();
		}
		finally
		{
			lock.unlock();
		}		
	}
	public void deposit(double depositAmount)
	{
		lock.lock();
		try{
			//如果flag为真,表明账户中已经有人存钱进去,存钱方法阻塞
			if(flag)
			{
				cond.await();
			}
			else
			{
				//执行存款操作
				System.out.println(Thread.currentThread().getName()+
						"存款:"+depositAmount);
				balance+=depositAmount;
				System.out.println("账户余额为:"+balance);
				//将表示是否已有存款的旗标设为true
				flag=true;
				//唤醒其他线程
				cond.signalAll();
			}
		}
		catch(InterruptedException ex)
		{
			ex.printStackTrace();
		}
		finally{
			lock.unlock();
		}
	}
	public int hashCode()
	{
		return accoutNo.hashCode();
	}
	public boolean equals(Object obj)
	{
		if(this==obj)
			return true;
		if(obj!=null&&obj.getClass()==Account.class)
		{
			Account target=(Account)obj;
			return target.getAccoutNo().equals(accoutNo);
		}
		return false;
	}
}

2.存款线程

package com.bankAccount.test;
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;
	}
	public void run()
	{
		for(int i=0;i<100;i++)
		{
			account.deposit(depositAmount);
		}
	}
}

3.取款线程

package com.bankAccount.test;
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;
	}
	//当多个线程修改同一个共享数据时,将涉及数据安全问题
	public void run()
	{
		//使用account作为同步监视器,任何线程进入下面同步代码块之前
		//必须先获得对account账户的锁定---其他线程无法获得锁,也就无法修改它
		//该做法符合:"加锁->修改->释放锁"
		for(int i=0;i<100;i++)
		{
			account.draw(drawAmount);
		}
	}
}
4.测试类

package com.bankAccount.test;
public class DrawTest {
	public static void main(String[] args) {
		//创建一个账户
		Account acct=new Account("123",0);
		//模拟两个线程对同一个账户取 钱
		new DrawThread("取钱者",acct,800).start();
		new DepositThread("存款者甲",acct,800).start();
		new DepositThread("存款者乙",acct,800).start();
		new DepositThread("存款者丙",acct,800).start();
	}
}

结果:














































©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页