銀行取錢肯定不能透支這個是衆所周知的,實作此功能就需要借助多線程的知識!
先來看一下采取同步措施前産生的結果:
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiI0gTMx81dsQWZ4lmZf1GLlpXazVmcvwFciV2dsQXYtJ3bm9CX9s2RkBnVHFmb1clWvB3MaVnRtp1XlBXe0xCMy81dvRWYoNHLwEzX5xCMx8FesU2cfdGLwMzX0xiRGZkRGZ0Xy9GbvNGLpZTY1EmMZVDUSFTU4VFRR9Fd4VGdsYTMfVmepNHLrJXYtJXZ0F2dvwVZnFWbp1zczV2YvJHctM3cv1Ce-cmbw5yM4gTMyIzNyI2M3QWM3U2YyYzX3QDOxUTMzEzLcdDMyIDMy8CXn9Gbi9CXzV2Zh1WavwVbvNmLvR3YxUjLyM3Lc9CX6MHc0RHaiojIsJye.png)
好的,我們先來定義一個賬戶類:
/**
* 賬戶類,含卡号,還有餘額 通過同步方法防止出現餘額為負的情況
*
* @author Mr.Gao
*/
public class Account {
private String accountNo;
private double balance;
public Account(String accountNo, double balance) {
super();
this.accountNo = accountNo;
this.balance = balance;
}
public String getAccountNo() {
return accountNo;
}
public void setAccountNo(String accountNo) {
this.accountNo = accountNo;
}
public double getBalance() {
return balance;
}
public void setBalance(double balance) {
this.balance = balance;
}
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((accountNo == null) ? 0 : accountNo.hashCode());
long temp;
temp = Double.doubleToLongBits(balance);
result = prime * result + (int) (temp ^ (temp >>> 32));
return result;
}
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Account other = (Account) obj;
if (accountNo == null) {
if (other.accountNo != null)
return false;
} else if (!accountNo.equals(other.accountNo))
return false;
if (Double.doubleToLongBits(balance) != Double
.doubleToLongBits(other.balance))
return false;
return true;
}
public String toString() {
return "Account [accountNo=" + accountNo + ", balance=" + balance + "]";
}
/**
* 同步取錢方法,防止餘額為負
* @param accountAmount
*/
public synchronized void draw(double accountAmount) {
if (balance > accountAmount) {
System.out.println(Thread.currentThread().getName() + " 取錢 "
+ accountAmount + " 成功");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
balance -= accountAmount;
System.out.println("餘額為\t" + balance);
} else {
System.err.println("取錢失敗");
}
}
}
定義一個線程類,主要示範同步方法,注釋的部分為同步代碼塊的内容:
/**
* 取錢線程采用的是繼承的方式
* 無須自己實作取錢的操作,直接調用account的draw()方法實作,符合"加鎖--修改--釋放鎖"的邏輯
* 符合 領域驅動設計(每個類都是完整的領域對象,例如使用者賬戶提供相應的方法去處理賬戶所對應的需求)
* @author Mr.Gao
*
*/
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() {
// synchronized (account) {
// if (account.getBalance() > drawAmount) {
// System.out.println(this.getName() + " 取錢 " + drawAmount
// + " 成功");
//
// try {
// Thread.sleep(100);
// } catch (InterruptedException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
// account.setBalance(account.getBalance() - drawAmount);
// System.out.println("餘額為\t" + account.getBalance());
//
// } else {
// System.out.println("餘額不足");
// }
// }
/*
* 直接調用account對象的draw()方法,同步方法的同步螢幕是this,
* this代表調用draw()方法的對象,也就是說,再進入draw()方法前先對account對象進行加鎖
*/
account.draw(drawAmount);
}
}
測試代碼:
/**
* 結果測試
*
* @author Mr.Gao
*
*/
public class AccountTest {
public static void main(String[] args) {
Account acc = new Account("123", 1000);
new DrawThread("甲", acc, 800).start();
new DrawThread("乙", acc, 800).start();
}
}