執行緒同步:銀行帳戶存、取款問題
阿新 • • 發佈:2019-01-22
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.取款執行緒
4.測試類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); } } }
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();
}
}
結果: