java源碼展示:
銀行:Account.java
package testsynchrozied; /** * 賬戶類 * @author superdrew * */ public class Account { private int balance = 600;//余額 //顯示余額 public int getBalance(){ return balance; } //取款 public void draw(int money){ balance = balance - money; } }
銀行線程:AccountRunnable.java
package testsynchrozied; public class AccountRunnable implements Runnable{ Account account = new Account();//取款的賬戶 Object obj = new Object(); public void run() { synchronized(obj){ //synchronized 同步 加鎖 默認是 open狀態 --close()--open //省略 300行代碼 if(account.getBalance()>=400){//余額大於400就取錢 try { Thread.sleep(1);//第一個線程 進入阻塞,取錢了 線程死亡了 //第二個線程 進入阻塞 取錢了 線程死亡了 } catch (InterruptedException e) { e.printStackTrace(); } account.draw(400); System.out.println("取款成功,當前余額:"+account.getBalance()+"當前線程為:"+Thread.currentThread().getName()); }else{ System.out.println("余額不足,當前余額:"+account.getBalance()+"當前線程為:"+Thread.currentThread().getName()); } //省略 500行代碼 } //解鎖 釋放鎖 } public void method1(){ synchronized(obj){ } } public void method2(){ synchronized(account){ } } public void method3(){ synchronized(account){ } } }
測試銀行取款主線程:TestSynchronized.java
package testsynchrozied; /** * 功能:多個用戶同時對一個賬戶取款 * 使用線程的同步 * * 1.設計一個賬戶類 余額,取款,顯示余額 * 2.取款的線程 * 3.用戶同時取款 * * 解決方案1:同步代碼塊 synchronized(account){ .... } * * 總結:1.認識同步監視器 account * synchronized(同步監視器){ ... } * 1.必須是引用類型的數據,不能是基本數據類型 * 2.在同步代碼塊中,不要改變引用類型數據的值,屬性的值可以修改 * 3.盡量不要使用String 和 包裝類做同步監視器,除非代碼塊中不會改變其內容 * 4.一般是使用共享資源作為同步監視器 (account) * 5.可以新建一個專門的同步監視器 Object 沒有具體的業務含義 * * 2.之前見過的同步監視器 * StringBuffer Hashtabale vector * * 3.同步代碼塊的執行過程 * 1.第一個線程來到同步代碼塊,發現同步監視器是open狀態,需要close,進去執行里面的代碼 * 2.執行里面的代碼發生了一些情況 ,切換(阻塞,就緒),第一個線程失去cpu,鎖 還是close * 3.第二個線程來到同步代碼塊,發現同步監視器是close狀態,無法執行,其中的代碼也不能執行, * 第二個線程進入阻塞狀態 * 4.第一個線程再次獲取cpu,接着執行后續代碼,執行完畢,鎖 open 第一個線程進入死亡狀態 * 5.第二個線程再次獲取cpu,又同步代碼塊,發現鎖是open狀態,執行后續代碼.重復第一個線程的過程 * * 4.線程同步的有點和缺點 * 優點:安全 * 缺點:效率低下,有可能出現死鎖 * * 5.多個同步代碼塊使用的是同一個同步監視器(鎖),鎖住其中一個代碼塊同時也會鎖住其它的所有使用該同步監視器(鎖)代碼塊 * 其它線程無法訪問其中任何一個代碼塊 * 但是沒有鎖住其它的同步監視器代碼塊 */ public class TestSynchronized { public static void main(String[] args) { AccountRunnable ar = new AccountRunnable(); Thread th1 = new Thread(ar); th1.setName("Drew"); Thread th2 = new Thread(ar); th2.setName("Super"); th1.start(); th2.start(); } }
結果展示: