本文主要是通過一個銀行用戶取錢的實例,演示java編程多線程並發處理場景,具體如下。
從一個例子入手:實現一個銀行賬戶取錢場景的實例代碼。
第一個類:Account.java
賬戶類:
package cn.edu.byr.test;public class Account {private String accountNo;private double balance;public Account(){}public Account(String accountNo,double balance){this.accountNo = accountNo;this.balance = balance;}public int hashcode(){return accountNo.hashCode();}public String getAccountNo(){return this.accountNo;}public double getBalance(){return this.balance;}public void setBalance(double balance){this.balance = balance;}public Boolean equals(Object obj){if(this == obj) return true;if(obj != null && obj.getClass() == Account.class){Account target = (Account)obj;return target.getAccountNo().equals(accountNo);}return false;}}第二個類:DrawThread.java
取錢線程類:
package cn.edu.byr.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(){// synchronized (account) { if(account.getBalance() > drawAmount){System.out.println(getName() + "取錢成功,吐出鈔票:" + drawAmount);// try{ // Thread.sleep(1); // } // catch(InterruptedException e){ // e.printStackTrace(); // } account.setBalance(account.getBalance() - drawAmount);System.out.println("/t 餘額為: " + account.getBalance());} else System.out.println(getName() + "取錢失敗,餘額不足!");// }}public static void main(String[] args){Account acct = new Account("123456",1000);new DrawThread("A",acct,800).start();new DrawThread("B",acct,800).start();}}上面代碼中註釋掉的部分: (1)synchronized同步代碼塊(2)線程休眠。如果註釋掉(1)、(2),則運行結果有多種可能性,可能性之一(概率較小),符合正常邏輯:
B取錢成功,吐出鈔票:800.0
餘額為: 200.0
A取錢失敗,餘額不足!
應該是B先強找到取錢資源,並且正確修改餘額後,A才開始判斷用戶餘額;這種概率非常小,多數運行會類似以下情況:
A取錢成功,吐出鈔票:800.0
B取錢成功,吐出鈔票:800.0
餘額為: -600.0
餘額為: 200.0
這明顯是不符合邏輯的,從運行結果可以猜測,A先搶占資源,取出金額,但在修改餘額之前,資源被B搶占;由於餘額未被修改,則B看到餘額仍然是800,B仍然取出金額;A先運行修改餘額,但並未打印,B搶奪資源;B修改餘額,並打印餘額,為-600;A打印餘額,為200;
如果加上(2)線程休眠,則一定是錯誤狀況,因為A或B在取出金額後一定會因為sleep釋放CPU資源,JVM會調用其他處於準備狀態的進程。第二個取錢判斷餘額一定是錯誤的。
如果加上(1)synchronized同步代碼塊,在線程run方法體中對account進行加鎖;則每次都會保證執行邏輯正常:
A取錢成功,吐出鈔票:800.0
餘額為: 200.0
B取錢失敗,餘額不足!
可以設想一下執行過程:
A先搶占資源,在run方法體初始對account類進行加鎖;然後開始執行同步代碼塊;如果執行到中間某個環節,CPU資源被B搶占;B開始執行,一開始也會對account類進行加鎖。但是加鎖時會發現account已經被A佔用,則會調整為阻塞狀態等待A釋放資源;A執行完同步代碼塊後釋放account的鎖,B繼續執行;B運行時看到的餘額保證是A已經修改過的,會按照正確邏輯正常執行。
總結
以上就是本文關於java編程多線程並發處理實例解析的全部內容,希望對大家有所幫助。感興趣的朋友可以繼續參閱本站其他相關專題,如有不足之處,歡迎留言指出。感謝朋友們對本站的支持!