试想一个场景:同一个银行账户有1000RMB,两个对象同时对该账户取钱,两人各取800,流程如下:
-
输入帐号、密码,验证成功
-
输入取钱金额,系统比较账户余额和取钱金额
-
验证成功,允许取钱操作,然后,两个人一起开开心心的拿着1.6k回家了。剩下一个余额为-600的账户默默哭泣。
这就是我们常说的:多线程并发操作线程安全问题。
就取钱例子模拟代码实现:
1、定义一个账户类,封装了账户ID和余额两个属性
2、提供取钱线程,执行根据账户信息、取钱数量进行取钱操作
public class Account
{
private String accountNo;
private String balance;
//省略两个属性的get set方法
//构造器
public Account(String accountNo,Stringbalance)
{
this.accountNo = accountNo;
this.balance = balance;
}
public int hashCode()
{
return accountNo.hashCode();
}
public boolean equals(Object obj)
{
if (obj != null&&obj.getClass()==Account.class)
{
Account target=(Account)obj;
returntarget.getAccountNo().equals(accountNo);
}
return false;
}
}
public class DrawThread extends Thread
{
//模拟用户帐户
private Account account;
private double drawAmount;
public DrawThread(String name,Accountaccount,double drawAmount)
{
super(name);
this.account=account;
this.drawAmount=drawAmount;
}
//当多条线程同时修改一个共享数据时,将涉及数据安全问题
public void run()
{
//帐户余额>取钱数目
if(account.getBalance()>=drawAmount)
{
//取钞成功
System.out.println(getName()+"取钱成功,取钱金额为"+drawAmount);
try{
Thread.sleep(1);
}catch(InterruptedException ex)
{
ex.printStackTrace();
}
//修改账户余额
account.setBalance(account.getBalance()-drawAmount);
System.out.println("余额为"+account.getBalance());
}
else
{
System.out.println(getName()+"余额不足");
}
}
}
public class TestDraw
{
public static void main(String[] args)
{
//创建一个账户
Account account=newAccount("123",1000);
//模拟两个线程同时对一个账户取钱
newDrawThread("Max",account,800).start();
newDrawThread("Jason",account,800).start();
}
}