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 }
相关文章
相关标签/搜索