多執行緒共享物件問題
進行多執行緒要注意同步的問題,當同時有多個執行緒進行時,若該程式需要某一執行緒執行完畢後,才能執行下一個執行緒,此時就需要進行同步化
製作一程式ATM,同時有三個執行緒進行提款
類別圖
程式碼
class Account { private int balance;//餘額 //建構子 public Account(int balance) { this.balance = balance; } //getter public int getBalance() { return balance; } //setter public void setBalance(int balance) { this.balance = balance; } //提款 public void withdraw(int amount) { this.balance = getBalance();//先取得Account帳戶還有多少餘額 交易進行中();//模擬交易處理時間 balance -= amount;//提款後餘額 this.setBalance(balance); } //模擬交易處理時間 private void 交易進行中() { int delay = (int) (Math.random() * 3000); try { Thread.sleep(delay);//讓執行緒暫停,模擬交易時間 } catch (InterruptedException ex) { System.out.println(ex); } } } //執行緒 class ATM extends Thread { private Account account; //宣告 //建構子 public ATM(Account account) { //設定帳戶 this.account = account; } public void run() { String atmName = Thread.currentThread().getName();//取得執行緒名稱 System.out.println(atmName + "提款中..."); account.withdraw(1);//對帳戶提款一元 System.out.println(atmName + "完成提款,餘額:" + account.getBalance()); } } public class ATMTTest { public static void main(String[] args) { Account acc = new Account(100); //設立帳戶,餘額100 System.out.println("帳戶餘額:" + acc.getBalance()); //建立三個執行緒,共同使用一個帳戶 ATM atm1 = new ATM(acc); ATM atm2 = new ATM(acc); ATM atm3 = new ATM(acc); //設定執行緒名稱 atm1.setName("ATM1"); atm2.setName("ATM2"); atm3.setName("ATM3"); //啟動 atm1.start(); atm2.start(); atm3.start(); } }
顯示結果
因為沒有進行同步化,所以3台ATM同時提款,這邊要修改為當有ㄧ台ATM在執行,其他兩台ATM要先暫停
同步化方法只允許一個執行緒在其中執行,只要有執行緒在同步化方法 中,其他執行緒必須等候
class Account { private int balance;//餘額 //建構子 public Account(int balance) { this.balance = balance; } //getter public int getBalance() { return balance; } //setter public void setBalance(int balance) { this.balance = balance; } /* 同步化方法 ( synchronized ) 同步化方法只允許一個執行緒在其中執行,只要有執行緒在同步化方法 中,其他執行緒必須等候 */ //提款 public void withdraw(int amount) { //這邊可以在最前方加入同步化(synchronized)或是在執行緒內容加入 this.balance = getBalance();//先取得Account帳戶還有多少餘額 交易進行中();//模擬交易處理時間 balance -= amount;//提款後餘額 this.setBalance(balance); } //模擬交易處理時間 private void 交易進行中() { int delay = (int) (Math.random() * 3000); try { Thread.sleep(delay);//讓執行緒暫停,模擬交易時間 } catch (InterruptedException ex) { System.out.println(ex); } } } //執行緒 class ATM extends Thread { private Account account; //宣告 //建構子 public ATM(Account account) { //設定帳戶 this.account = account; } public void run() { String atmName = Thread.currentThread().getName();//取得執行緒名稱 //使用同步化synchronized //因為多個ATM對同一個帳戶提款需要前一個動作完成才能給下一個提款,所以需要做同步化獨佔 synchronized(account){ //鎖定account物件(獨佔) System.out.println(atmName + "提款中..."); account.withdraw(1);//對帳戶提款一元 System.out.println(atmName + "完成提款,餘額:" + account.getBalance()); } //未同步化 // System.out.println(atmName + "提款中..."); // account.withdraw(1);//對帳戶提款一元 // System.out.println(atmName + "完成提款,餘額:" + account.getBalance()); } } public class ATMTTest { public static void main(String[] args) { Account acc = new Account(100); //設立帳戶,餘額100 System.out.println("帳戶餘額:" + acc.getBalance()); //建立三個執行緒,共同使用一個帳戶 ATM atm1 = new ATM(acc); ATM atm2 = new ATM(acc); ATM atm3 = new ATM(acc); //設定執行緒名稱 atm1.setName("ATM1"); atm2.setName("ATM2"); atm3.setName("ATM3"); //啟動 atm1.start(); atm2.start(); atm3.start(); } }
顯示結果
這邊有兩種方式,ㄧ種是直接在Account的提款mothod最前方加入synchronized,另一種是採用同步化區塊 ( synchronized blocks ),撰寫程式的彈性較大,執行緒可指定要獨佔哪個物件,並設定同步化程式的範圍
沒有留言:
張貼留言