* 線程同步 :使用同步方法,實現線程同步
* 同步synchronized方法的對象監視鎖爲this,當前對象
* 多個線程使用同一把鎖,若是線程安全必需確保:多個線程使用的是同一個this對象(Runnable適用於共享同一對象[如:this],若是Thread繼承就會有問題[推薦使用Runnable])
* 全部訪問此對象方法的線程都在方法外等待,都會判斷同步鎖,下降效率,但確保線程安全問題
* java的每一個對象都有一個內置鎖,當用synchronized關鍵字修飾方法時,內置鎖會保護整個方法。在調用該方法前,線程須要得到內置鎖,不然就處於阻塞狀態java
* synchronized關鍵字也能夠修飾靜態方法,此時若是調用該靜態方法,將會鎖住整個類面試
此例子中使用synchronized關鍵字:安全
private synchronized void makeWithdraw(int amount){...}多線程
BankAccount.java併發
1 public class BankAccount { 2 //餘額 3 private int balance = 500; 4 //查詢 5 public int getBalance(){ 6 return balance; 7 } 8 //取款 9 public void withdraw(int amount){ 10 balance = balance - amount; 11 } 12 //存款 13 public void deposit(int amount){ 14 balance = balance + amount; 15 } 16 }
SyncMethod.javaide
1 /** 2 * 此線程類實現Runnable接口 3 * 線程同步 :使用同步方法,實現線程同步 4 * 同步synchronized方法的的對象監視鎖爲this,當前對象 5 * 多個線程使用同一把鎖,若是線程安全必需確保:多個線程使用的是同一個this對象 6 * 全部訪問此對象方法的線程都在方法外等待,都會判斷同步鎖,下降效率,但確保線程安全問題 7 * */ 8 public class SyncMethod implements Runnable { 9 // 全部Thread多線程線程都共享Runnable(接口對象)和account對象 10 private BankAccount account = new BankAccount(); 11 @Override 12 public void run() { 13 for (int i = 0; i < 5; i++) {// 總共取款5次 14 makeWithdraw(100); // 每次取款100 15 if (account.getBalance() < 0) { 16 System.out.println("☆" + Thread.currentThread().getName()+ " 透支了!"); 17 } 18 } 19 } 20 21 /** 22 * makeWithdraw 帳戶取款 23 * @param amount取款金額 24 * 打印log記錄取款過程 25 * */ 26 private synchronized void makeWithdraw(int amount){ 27 if(account.getBalance() >= amount){//若是餘額足夠則取款 28 System.out.println("☆" + Thread.currentThread().getName() + " 準備取款!"); 29 try { 30 Thread.sleep(500); 31 } catch (InterruptedException e) { 32 System.out.println(Thread.currentThread().getName() + " 準備取款,等待0.5s線程中斷!" + e.getMessage()); 33 } 34 account.withdraw(amount); 35 System.out.println("☆" + Thread.currentThread().getName() + " 完成" + amount + "取款!餘額爲" + account.getBalance()); 36 }else{//餘額不足則提示 37 System.out.println("☆" + "餘額不足以支付" + Thread.currentThread().getName() + amount + " 的取款,餘額爲" + account.getBalance()); 38 } 39 } 40 }
TreadSyncTest.java單元測試
1 public class TreadSyncTest { 2 3 /* 4 Junit不適合多線程併發測試。 5 由於線程還在激活狀態的時候,Junit已經執行完成。 6 在Junit的TestRunner中,它沒有被設計成搜尋Runnable實例, 7 而且等待這些線程發出報告,它只是執行它們而且忽略了它們的存在。 8 綜上,不可能在Junit中編寫和維護多線程的單元測試。 9 */ 10 /* 11 @Test 12 public void test() { 13 } 14 */ 15 16 public static void main(String[] args) { 17 //實現Runnable:全部Thread多線程線程都共享Runnable(接口對象) 18 //NoSync target =new NoSync(); 19 SyncMethod target = new SyncMethod(); 20 //建立羅密歐和朱麗葉兩個線程實現取款(同時) 21 Thread romeoThread = new Thread(target); 22 romeoThread.setName("羅密歐"); 23 Thread julietThread = new Thread(target); 24 julietThread.setName("朱麗葉"); 25 //調用Thread對象的start()方法,啓動線程,執行run()方法(OS) 26 romeoThread.start(); 27 julietThread.start(); 28 } 29 }
運行結果:測試
正常運行結果1: ☆羅密歐 準備取款! ☆羅密歐 完成100取款!餘額爲400 ☆羅密歐 準備取款! ☆羅密歐 完成100取款!餘額爲300 ☆羅密歐 準備取款! ☆羅密歐 完成100取款!餘額爲200 ☆羅密歐 準備取款! ☆羅密歐 完成100取款!餘額爲100 ☆羅密歐 準備取款! ☆羅密歐 完成100取款!餘額爲0 ☆餘額不足以支付朱麗葉100 的取款,餘額爲0 ☆餘額不足以支付朱麗葉100 的取款,餘額爲0 ☆餘額不足以支付朱麗葉100 的取款,餘額爲0 ☆餘額不足以支付朱麗葉100 的取款,餘額爲0 ☆餘額不足以支付朱麗葉100 的取款,餘額爲0. 正常運行結果2: ☆羅密歐 準備取款! ☆羅密歐 完成100取款!餘額爲400 ☆羅密歐 準備取款! ☆羅密歐 完成100取款!餘額爲300 ☆羅密歐 準備取款! ☆羅密歐 完成100取款!餘額爲200 ☆羅密歐 準備取款! ☆羅密歐 完成100取款!餘額爲100 ☆朱麗葉 準備取款! ☆朱麗葉 完成100取款!餘額爲0 ☆餘額不足以支付朱麗葉100 的取款,餘額爲0 ☆餘額不足以支付朱麗葉100 的取款,餘額爲0 ☆餘額不足以支付朱麗葉100 的取款,餘額爲0 ☆餘額不足以支付羅密歐100 的取款,餘額爲0 ☆餘額不足以支付朱麗葉100 的取款,餘額爲0 正常運行結果3: ☆羅密歐 準備取款! ☆羅密歐 完成100取款!餘額爲400 ☆羅密歐 準備取款! ☆羅密歐 完成100取款!餘額爲300 ☆羅密歐 準備取款! ☆羅密歐 完成100取款!餘額爲200 ☆朱麗葉 準備取款! ☆朱麗葉 完成100取款!餘額爲100 ☆朱麗葉 準備取款! ☆朱麗葉 完成100取款!餘額爲0 ☆餘額不足以支付朱麗葉100 的取款,餘額爲0 ☆餘額不足以支付朱麗葉100 的取款,餘額爲0 ☆餘額不足以支付朱麗葉100 的取款,餘額爲0 ☆餘額不足以支付羅密歐100 的取款,餘額爲0 ☆餘額不足以支付羅密歐100 的取款,餘額爲0
若是不用synchronized關鍵字的結果:this
☆羅密歐 準備取款! ☆朱麗葉 準備取款! ☆朱麗葉 完成100取款!餘額爲300 ☆羅密歐 完成100取款!餘額爲300 ☆羅密歐 準備取款! ☆朱麗葉 準備取款! ☆朱麗葉 完成100取款!餘額爲100 ☆朱麗葉 準備取款! ☆羅密歐 完成100取款!餘額爲100 ☆羅密歐 準備取款! ☆羅密歐 完成100取款!餘額爲0 ☆餘額不足以支付羅密歐100 的取款,餘額爲0 ☆餘額不足以支付羅密歐100 的取款,餘額爲0 ☆朱麗葉 完成100取款!餘額爲-100 ☆朱麗葉 透支了! ☆餘額不足以支付朱麗葉100 的取款,餘額爲-100 ☆朱麗葉 透支了! ☆餘額不足以支付朱麗葉100 的取款,餘額爲-100 ☆朱麗葉 透支了!
此博文轉載並整理於:http://blog.csdn.net/typa01_kk/article/details/46738459spa