多线程间的通信问题

来源:互联网 发布:外贸进销存软件 编辑:程序博客网 时间:2024/06/06 01:16

一、线程间的通信


实例代码:

需求是:输入一个姓名和性别后,就输出一个姓名和性别

[html] view plaincopy
  1. class Resource  
  2. {  
  3.     String name;  
  4.     String sex ;  
  5. }  
  6. class Input implements Runnable  
  7. {  
  8.     Resource r;  
  9.     Input(Resource r)  
  10.     {  
  11.         this.r = r;  
  12.     }  
  13.     public void run()  
  14.     {  
  15.         int x = 0;  
  16.         while(true)  
  17.         {  
  18.             synchronized (r)   
  19.             {  
  20.                 if(x==0)  
  21.                 {  
  22.                     r.name = "BLF";  
  23.                     r.sex = "male";  
  24.                 }  
  25.                 else {  
  26.                     r.name = "妮妮妮妮";  
  27.                     r.sex = "female";  
  28.                 }  
  29.                 x = (++x)%2;  
  30.             }  
  31.         }  
  32.     }  
  33. }  
  34.   
  35. class Output implements Runnable  
  36. {  
  37.     Resource r;  
  38.     public Output(Resource r) {  
  39.         // TODO Auto-generated constructor stub  
  40.         this.r = r;  
  41.     }  
  42.     public void run()   
  43.     {  
  44.         while(true)  
  45.         {  
  46.             synchronized (r) //输入和输出都是应用同一个锁  
  47.             {  
  48.                 System.out.println(r.name+"..."+r.sex);  
  49.             }  
  50.         }  
  51.     }  
  52. }  
  53. public class Main   
  54. {  
  55.     public static void main(String[] args)  
  56.     {  
  57.         Resource r = new Resource();//共享同一资源  
  58.         Input in = new Input(r);  
  59.         Output out = new Output(r);   
  60.         Thread t1 = new Thread(in);  
  61.         Thread t2 = new Thread(out);  
  62.         t1.start();  
  63.         t2.start();  
  64.     }  
  65. }  

上述代码虽然解决了,多线程处理同一资源问题,但是出现了一个问题就是,打印很多一个人名和性别后再打印另一个,无法实现交替输出,原因:输入线程获取执行权后,不会执行一次,输入姓名和性别,输入线程还拥有执行权,一直赋值,等到切换到输出执行权后,输出最后输入的姓名和性别,但是输出线程也不会只输出一次,一直输出,所以出现打印很多同一姓名和性别的问题


二、线程的等待/唤醒机制:

用一个boolean值判断是否有数据,有就不放,没有就放

输入线程执行时判断是否有数据,有,就释放执行权,再释放执行资格,进入冻结状态,输出线程执行,输出后boolean值置为false


[html] view plaincopy
  1. Input:  
  2.          if(flag)//有值  
  3.            wait();//当前冻结,切换输出线程  
  4.          flag = true;  
  5.          notify();  
  6.   
  7. Output:  
  8.          if(!flag)  
  9.        wait();  
  10.          flag = false;//flag置为假,输出完毕  
  11.       notify();//唤醒输入线程  

等待/唤醒机制:

方法:

[html] view plaincopy
  1. 1.wait();//使线程进入冻结状态,CPU释放执行权和执行资格,被wait()的线程会被存储到线程池中  
  2. 2.notify();//唤醒线程池中的任意的一个线程  
  3. 3.notifyAll();//唤醒所有线程,使之处于运行状态或临时阻塞状态,总之,使其具备执行资格  

这些方法必须定义在同步中,这些方法是用于操作线程状态的方法,所以必须明确在哪个锁上的线程

(wait()A锁的线程,只能用A锁的notify唤醒A锁的线程。)

了解:而wait()等方法是定义在Object类中的,这些方法是监视器的方法,而监视器呢,就可以理解为锁,控制哪个锁所属下的线程,而锁又可以是任意的,而所有的类都是继承于Object类的,所以wait()等类是定义在Object里


下述代码就解决了上述代码的问题,实现了输入输出线程的交替执行

[html] view plaincopy
  1. class Resource extends Object  
  2. {  
  3.     String name;  
  4.     String sex ;  
  5.     boolean flag = false;  
  6. }  
  7. class Input implements Runnable  
  8. {  
  9.     Resource r;  
  10.     Input(Resource r)  
  11.     {  
  12.         this.r = r;  
  13.     }  
  14.     public void run()  
  15.     {  
  16.         int x = 0;  
  17.         while(true)  
  18.         {  
  19.             synchronized (r)   
  20.             {  
  21.                 if(r.flag)  
  22.                 {  
  23.                     try {  
  24.                         r.wait();  
  25.                     } catch (Exception e) {  
  26.                         // TODO: handle exception  
  27.                     }  
  28.                       
  29.                 }  
  30.                       
  31.                 if(x==0)  
  32.                 {  
  33.                     r.name = "BLF";  
  34.                     r.sex = "male";  
  35.                 }  
  36.                 else {  
  37.                     r.name = "妮妮妮妮";  
  38.                     r.sex = "female";  
  39.                 }  
  40.                 r.flag = true;  
  41.                 r.notify();  
  42.                 x = (++x)%2;  
  43.             }  
  44.         }  
  45.     }  
  46. }  
  47.   
  48. class Output implements Runnable  
  49. {  
  50.     Resource r;  
  51.     public Output(Resource r) {  
  52.         // TODO Auto-generated constructor stub  
  53.         this.r = r;  
  54.     }  
  55.     public void run()   
  56.     {  
  57.           
  58.         while(true)  
  59.         {  
  60.             synchronized (r)   
  61.             {  
  62.                 if(!r.flag)  
  63.                 {  
  64.                     try {  
  65.                         r.wait();  
  66.                     } catch (Exception e) {  
  67.                         // TODO: handle exception  
  68.                     }  
  69.                 }  
  70.                       
  71.                       
  72.                 System.out.println(r.name+"..."+r.sex);  
  73.                 r.flag = false;  
  74.                 r.notify();  
  75.             }  
  76.         }  
  77.     }  
  78. }  
  79. public class Main   
  80. {  
  81.     public static void main(String[] args)  
  82.     {  
  83.       
  84.         Resource r = new Resource();  
  85.         Input in = new Input(r);  
  86.         Output out = new Output(r);   
  87.         Thread t1 = new Thread(in);  
  88.         Thread t2 = new Thread(out);  
  89.         t1.start();  
  90.         t2.start();  
  91.     }  
  92. }  

三:等待唤醒机制代码优化


资源中的成员为了可控,应该为私有的,对外提供方法

所以同步的操作,就在Resource类中执行,应用同步函数

[html] view plaincopy
  1. class Resource extends Object  
  2. {  
  3.     private String name;  
  4.     private String sex ;  
  5.     private boolean flag = false;  
  6.     public synchronized void set(String name,String sex)   
  7.     {  
  8.         // TODO Auto-generated constructor stub  
  9.         if(flag)  
  10.         {  
  11.             try {  
  12.                 this.wait();  
  13.             } catch (Exception e) {  
  14.                 // TODO: handle exception  
  15.                   
  16.             }  
  17.         }  
  18.           
  19.         this.name = name;  
  20.         this.sex = sex;  
  21.           
  22.         flag = true;  
  23.         this.notify();  
  24.     }  
  25.     public synchronized void out()  
  26.     {  
  27.         if(!flag)  
  28.         {  
  29.             try {  
  30.                 this.wait();  
  31.             } catch (Exception e) {  
  32.                 // TODO: handle exception  
  33.             }  
  34.             System.out.println(name+"  :  "+sex);  
  35.             flag = false;  
  36.             this.notify();  
  37.         }  
  38.     }  
  39. }  
  40. class Input implements Runnable  
  41. {  
  42.     Resource r;  
  43.     Input(Resource r)  
  44.     {  
  45.         this.r = r;  
  46.     }  
  47.     public void run()  
  48.     {  
  49.         int x = 0;  
  50.         while(true)  
  51.         {  
  52.             if(x==0)  
  53.             {  
  54.                 r.set("BLF", "male");                 
  55.             }  
  56.             else   
  57.             {  
  58.                 r.set("妮妮妮妮", "female");  
  59.             }             
  60.             x = (++x)%2;  
  61.               
  62.         }  
  63.     }  
  64. }  
  65. class Output implements Runnable  
  66. {  
  67.     Resource r;  
  68.     public Output(Resource r) {  
  69.         // TODO Auto-generated constructor stub  
  70.         this.r = r;  
  71.     }  
  72.     public void run()   
  73.     {  
  74.         while(true)  
  75.         {  
  76.             r.out();  
  77.         }  
  78.     }  
  79. }  
  80. public class Main   
  81. {  
  82.     public static void main(String[] args)  
  83.     {  
  84.       
  85.         Resource r = new Resource();  
  86.         Input in = new Input(r);  
  87.         Output out = new Output(r);   
  88.         Thread t1 = new Thread(in);  
  89.         Thread t2 = new Thread(out);  
  90.         t1.start();  
  91.         t2.start();  
  92.     }  
  93. }  

0 0