標籤:trace star 使用 引入 string 同步機制 成員 name 小例子
關於線程的安全問題,這裡舉一個很簡單的銀行取錢的問題:
- 使用者輸入帳號,密碼,系統判斷是否匹配
- 使用者輸入取錢金額
- 系統判斷取錢金額是否合理,是否大於餘額數
- 如果取錢金額小於等於餘額,取錢成功,大於則失敗
當兩個使用者使用同一個帳號取錢時,相當於兩個線程並發取錢,則可能出現錯誤。
出現錯誤的原因是因為run()方法不具有同步安全性。為瞭解決這個問題,java多線程支援引入同步監視器,使用同步監視器的格式如下:
sysnchronized(boj){
..........
}
其運行邏輯是:加鎖>修改>釋放鎖
synchronized關鍵字可以修飾方法,代碼塊,不能修飾構造器,成員變數
如下幾種情況會釋放同步監視器:
- 當前執行線程的同步方法或者同步代碼塊執行結束
- 當前執行線程的同步方法或者同步代碼遇到break,return終止了該方法或者代碼塊
- 當前執行線程的同步方法或者同步代碼的程式中執行了同步監視器對象的wait()方法
如下幾種情況不會釋放同步監視器
- 線程執行同步方法或者同步代碼塊時,程式調用了Thread.sleep(),Thread.yield()方法
- 線程執行代碼塊時,其他線程執行該線程的suspend()方法將該線程掛起
這裡放一個銀行取錢的小例子:
package com.tc.test;public class Acount { private String accountNo; private double balance; public Acount(String accountNo, double balance) { super(); this.accountNo = accountNo; this.balance = balance; } public String getAccountNo() { return accountNo; } public void setAccountNo(String accountNo) { this.accountNo = accountNo; } public double getBalance() { return balance; }// public void setBalance(double balance) {// this.balance = balance;// } public synchronized void draw(double drawAmount){ if( balance > drawAmount ){ System.out.println(Thread.currentThread().getName() +"取錢成功"+drawAmount); try{ Thread.sleep(1); } catch(InterruptedException e){ e.printStackTrace(); } //修改餘額 balance-=drawAmount; System.out.println("餘額為:"+balance); }else{ System.out.println("取錢失敗,餘額不足!!!"); } }}
package com.tc.test;public class DrawThread extends Thread { private Acount account; private double drawAmount; public DrawThread(String name , Acount account, double drawAmount) { super(name); this.account = account; this.drawAmount = drawAmount; } public void run(){ account.draw(drawAmount); } }
package com.tc.test;public class DrawTest { public static void main(String[] args) { Acount ac=new Acount("123",1000); new DrawThread("第一個",ac,800).start(); new DrawThread("第二個",ac,800).start(); }}
同步鎖
從jdk1.5開始,java提供了一種功能更強大的線程同步機制————通過顯示定義同步鎖對象來實現同步,在這種機制下,同步鎖由Lock對象充當。
Lock是控制對個線程對共用資源的進行訪問的工具,通常鎖提供了對共用資源的獨佔訪問,每次只能有一個線程對lock加鎖,線程在訪問共用資源之前必須先獲得Lock對象
java8新增了新型的StampedLock類,為讀寫提供了三種鎖模式:Writing,ReadOptimistic,Reading 。
死結
當兩個線程互相等待對方釋放同步監視器時就會發生死結,java虛擬機器並沒有檢測,也沒有採取措施來處理死結,一旦出現死結,整個程式不會發生任何異常,也不會有任何提示,只是所有線程處於阻塞狀態。
java線程之線程同步