Java中的線程--線程的互斥與同步通訊

  Java中的線程以前也提到過,可是仍是想再詳細的學習一下,跟着張孝祥老師,系統的再學習一下。面試

1、線程中的互斥安全

線程安全中的問題解釋:線程安全問題能夠用銀行中的轉帳ide

例題描述:oop

線程A與線程B分別訪問同一個對象的方法,這樣就會存在線程安全的問題,方法的做用是打印出字符串中的每個字符,方法以下:學習

1 public void output(String name) { 2   int len = name.length(); 3   for (int i = 0; i < len; i++) { 4  System.out.print(name.charAt(i)); 5  } 6  System.out.println(); 7 }

線程A和線程B代碼以下:(直接寫在了init()方法中了)測試

 1     private void init() {  2         outputer outputer = new outputer();  3         new Thread(new Runnable() {  4  @Override  5             public void run() {  6                 while (true) {  7                     try {  8                         Thread.sleep(10);  9                     } catch (InterruptedException e) { 10  e.printStackTrace(); 11  } 12                     outputer.output("songshengchao"); 13  } 14  } 15  }).start(); 16 
17         new Thread(new Runnable() { 18  @Override 19             public void run() { 20                 while (true) { 21                     try { 22                         Thread.sleep(10); 23                     } catch (InterruptedException e) { 24  e.printStackTrace(); 25  } 26                     outputer.output("songxiaochao"); 27  } 28  } 29  }).start(); 30     }

測試一下,確定會出現線程不安全的問題,這是母庸質疑的事實,測試代碼以下:優化

1     public static void main(String[] args) { 2         new TraditionalThreadSynchronized().init(); 3     }

三種解決辦法,代碼以下:this

 1 public class outputer {  2         public void output(String name) {  3             int len = name.length();  4             synchronized (this) { // 傳進來當前調用方法的對象,要求線程用的是同一個對象  5             //synchronized (outputer.class) { // 這樣和outputer3方法達到線程互斥
 6                 for (int i = 0; i < len; i++) {  7  System.out.print(name.charAt(i));  8  }  9  System.out.println(); 10  } 11  } 12 
13         // 方法上的鎖對象用的就是this當前對象
14         public synchronized void output2(String name) { 15             int len = name.length(); 16             for (int i = 0; i < len; i++) { 17  System.out.print(name.charAt(i)); 18  } 19  System.out.println(); 20  } 21 
22         // output3 想和output方法達到線程互斥
23         public static synchronized void output3(String name) { 24             int len = name.length(); 25             for (int i = 0; i < len; i++) { 26  System.out.print(name.charAt(i)); 27  } 28  System.out.println(); 29  } 30     }

注意:至於第三種靜態的synchronized方法,在和第一個方法共用時,第一種方法必定是用當前對象的class字節碼文件,才能確保兩個方法用的同一個對象。spa

 2、線程互斥與通訊的經典面試題線程

面試題:子線程循環10次,接着主線程循環100次,接着又回到子線程循環10次,接着在主線程循環100次,如此循環50次,程序如何寫???

經驗之談,設計思想,設計思路:

要用到共同數據(包括同步鎖)的若干個方法應該歸在同一個類上,這種設計正好提現了程序的高內聚與健壯性

思路:先寫主線程與子線程的循環,而後在考慮輪流執行。先考慮循環,代碼以下:

 1 public class TraditionalThreadCommunication {  2 
 3     public static void main(String[] args) {  4 
 5         new Thread(new Runnable() {  6 
 7  @Override  8             public void run() {  9                 for (int i = 1; i <= 50; i++) { 10                     synchronized (TraditionalThreadCommunication.class) { 11                         for (int j = 1; j <= 10; j++) { 12                             System.out.println("sub thread sequece of" + j + ", loop of " + i); 13  } 14  } 15 
16  } 17  } 18  }).start(); 19 
20         // 自己main方法就是主線程,直接能夠寫循環代碼
21         for (int i = 1; i <= 50; i++) { 22             synchronized (TraditionalThreadCommunication.class) { 23                 for (int j = 1; j <= 100; j++) { 24                     System.out.println("main thread sequece of" + j + ", loop of " + i); 25  } 26  } 27  } 28 
29  } 30 }

代碼優化,用面向對象的思想,將那些代碼放到一個公共的類中,而後執行類中的不一樣方法,優化成一個公共的類,代碼以下:

 1 public class Business {  2 
 3     public synchronized void sub(int i){  4         for (int j = 1; j <= 10; j++) {  5             System.out.println("sub thread sequece of" + j + ", loop of " + i);  6  }  7  }  8     
 9     public synchronized void main(int i){ 10         for (int j = 1; j <= 100; j++) { 11             System.out.println("main thread sequece of" + j + ", loop of " + i); 12  } 13  } 14 } 15 
16 ----------------------------------------------------------------------------------------------
17 
18 public class TraditionalThreadCommunication { 19 
20     
21     public static void main(String[] args) { 22         Business business = new Business(); 23         new Thread(new Runnable() { 24 
25  @Override 26             public void run() { 27                 for (int i = 1; i <= 50; i++) { 28  business.sub(i); 29  } 30  } 31  }).start(); 32 
33         // 自己main方法就是主線程,直接能夠寫循環代碼
34         for (int i = 1; i <= 50; i++) { 35  business.main(i); 36  } 37 
38  } 39 
40 }

最終的完整代碼以下(詳細註釋):

 1 public class Business {  2 
 3     // 是不是子線程執行 默認子線程先執行
 4     private boolean bShouldSub = true;  5 
 6     public synchronized void sub(int i) {  7         // 不是子線程應該執行 讓給主線程 子線程執行等待的方法
 8         while (!bShouldSub) {  9             try { 10                 this.wait(); 11             } catch (InterruptedException e) { 12  e.printStackTrace(); 13  } 14  } 15         for (int j = 1; j <= 10; j++) { 16             System.out.println("sub thread sequece of" + j + ", loop of " + i); 17  } 18         // 子線程執行完畢後 讓給主線程執行
19         bShouldSub = false; 20         // 喚醒主線程
21         this.notify(); 22  } 23 
24     public synchronized void main(int i) { 25         // 是子線程應該執行 讓給子線程執行 主線程執行等待的方法
26         while (bShouldSub) { 27             try { 28                 this.wait(); 29             } catch (InterruptedException e) { 30  e.printStackTrace(); 31  } 32  } 33         for (int j = 1; j <= 100; j++) { 34             System.out.println("main thread sequece of" + j + ", loop of " + i); 35  } 36         // 主線程執行費完畢後 交給子線程執行
37         bShouldSub = true; 38         // 喚醒子線程
39         this.notify(); 40  } 41 } 42 ------------------------------------------------------------------------------------------------
43 
44 public class TraditionalThreadCommunication { 45 
46     public static void main(String[] args) { 47         Business business = new Business(); 48         new Thread(new Runnable() { 49 
50  @Override 51             public void run() { 52                 for (int i = 1; i <= 50; i++) { 53  business.sub(i); 54  } 55  } 56  }).start(); 57 
58         // 自己main方法就是主線程,直接能夠寫循環代碼
59         for (int i = 1; i <= 50; i++) { 60  business.main(i); 61  } 62 
63  } 64 
65 }
相關文章
相關標籤/搜索