文檔目錄:安全
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 }