java進階(38)--線程安全

文檔目錄:安全

1、概念多線程

2、解決方案併發

3、舉例說明ide

---------------------------------------分割線:正文--------------------------------------------------------測試

1、概念this

關注數據在多線程併發時安全問題,共享數據有修改的行爲。spa

2、解決方案線程

一、線程排隊執行,不能併發,即線程同步機制。code

二、使用synchronized(){}線程同步代碼塊,()內填寫須要同步的共享對象對象

三、局部變量永遠不存在線程安全問題,由於局部變量是不會共享的

3、舉例說明

一、編寫程序模擬兩個線程同時對同一個帳戶進行去取款操做

(1)變成帳戶類

 1 package JAVAADVANCE;  2 
 3 public class Account {  4     //帳戶與餘額
 5     private String actNo;  6     private double balance;  7 
 8     public Account(String actNo, double balance) {  9         this.actNo = actNo; 10         this.balance = balance; 11  } 12 
13     public String getActNo() { 14         return actNo; 15  } 16 
17     public void setActNo(String actNo) { 18         this.actNo = actNo; 19  } 20 
21     public double getBalance() { 22         return balance; 23  } 24 
25     public void setBalance(double balance) { 26         this.balance = balance; 27  } 28     //取款
29     public void withdraw(double money){ 30         //取款以前的餘額
31         double before=this.getBalance(); 32         //取款以後的餘額
33         double after = before-money; 34         //更新餘額
35         this.setBalance(after); 36  } 37 
38 }

(2)編寫帳戶線程類

 1 package JAVAADVANCE;  2 
 3 public class AccountThread extends Thread {  4     //兩個線程必須共享同一個帳戶對象
 5     private Account act;  6     //經過構造方法傳遞過來的帳戶對象
 7     public AccountThread(Account act){  8         this.act=act;  9  } 10  @Override 11     public void run() { 12         //run方法執行表示取款操做 13         //假設取款5000
14         double money=5000; 15         //取款
16  act.withdraw(money); 17         System.out.println(Thread.currentThread().getName()+"對帳戶"+act.getActNo()+"取款成功,餘額爲:"+act.getBalance()); 18  } 19 }

(3)測試類進行取款操做

 1 package JAVAADVANCE;  2 
 3 public class TestAdvance38TestThreadSafe01 {  4     public static void main(String[] args) {  5         //建立帳戶對象,只建立一個
 6         Account act=new Account("act-001",10000);  7         //建立兩個線程
 8         Thread t1=new AccountThread(act);  9         Thread t2=new AccountThread(act); 10         //設置name
11         t1.setName("t1"); 12         t2.setName("t2"); 13         //啓動線程取款
14  t1.start(); 15  t2.start(); 16  } 17 
18 }

(4)查看運行結果,必定概率出現錢被取完,餘額未更新,出現線程安全問題

t2對帳戶act-001取款成功,餘額爲:5000.0 t1對帳戶act-001取款成功,餘額爲:5000.0

二、改進代碼,使用線程同步機制來解決以上問題

 (1)加入synchronized ()線程同步代碼塊

()內須要填寫多線程共享的數據,才能達到多線程排隊。

 1     //取款
 2     public void withdraw(double money){  3         //增長線程同步機制,裏面是線程同步代碼塊
 4         synchronized (this){  5             //取款以前的餘額
 6             double before=this.getBalance();  7             //取款以後的餘額
 8             double after = before-money;  9             try { 10                 Thread.sleep(1000); 11             } catch (InterruptedException e) { 12  e.printStackTrace(); 13  } 14             //更新餘額
15             this.setBalance(after); 16  } 17 
18     }

改進後再次執行,多線程不會併發

t1對帳戶act-001取款成功,餘額爲:5000.0 t2對帳戶act-001取款成功,餘額爲:0.0

(2)whithdraw調用時候增長,synchronized ()線程同步代碼塊,擴大了同步範圍,執行效率變低

 1  @Override  2     public void run() {  3         //run方法執行表示取款操做  4         //假設取款5000
 5         double money=5000;  6         //取款
 7         synchronized (act){  8  act.withdraw(money);}  9         System.out.println(Thread.currentThread().getName()+"對帳戶"+act.getActNo()+"取款成功,餘額爲:"+act.getBalance()); 10     }

執行效果同上:多線程不會併發

(3)將實例方法使用synchronized

缺點:必定須要鎖this,整個方法體都須要同步,可能會擴大同步範圍致使程序效率太低

有點:代碼比較少,簡介

 1     //取款
 2     public synchronized void withdraw(double money){  3         //增長線程同步機制,裏面是線程同步代碼塊  4 // synchronized (this){  5             //取款以前的餘額
 6             double before=this.getBalance();  7             //取款以後的餘額
 8             double after = before-money;  9             try { 10                 Thread.sleep(1000); 11             } catch (InterruptedException e) { 12  e.printStackTrace(); 13  } 14             //更新餘額
15             this.setBalance(after); 16         }
相關文章
相關標籤/搜索