A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 周昭民 中级黑马   /  2014-2-5 13:41  /  1421 人查看  /  2 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

  1. /**

  2. 多线程等待唤醒机制
  3. */
  4. package com.xiancheng;
  5.         class Res
  6.         {
  7.                 private String name;       
  8.                 private String sex;
  9.                 private boolean flag;        //定义一个标记,用于判断有无信息,默认为false

  10.                 synchronized void set(String name,String sex){
  11.                 /*        if(flag)
  12.                                 try{wait();}catch(Exception e){}
  13.                         this.name=name;
  14.                         this.sex=sex;
  15.                         flag=true;
  16.                         notify();
  17.                 */
  18.                         if(!flag){                        //当线程中并无信息时,则输入信息
  19.                                 this.name=name;
  20.                                 this.sex=sex;
  21.                                 flag=true;                //输入完成,将标记置为true
  22.                                 notify();                //使另一线程进入唤醒状态
  23.                         }else
  24.                                 try{wait();}catch(Exception e){}        //有信息时则线程进入等待状态
  25.                
  26.                 }

  27.                                
  28.                

  29.                 synchronized void get(){
  30.                         /*
  31.                         if(!flag)
  32.                                 try{wait();}catch(Exception e){}
  33.                         System.out.println(name+"的性别是"+sex);
  34.                         flag=false;
  35.                         notify();
  36.                         */
  37.                        
  38.                         if(flag){                        //当有信息时,打印信息
  39.                                 System.out.println(name+"的性别是"+sex);
  40.                                 flag=false;                //打印完成后将标记置为false
  41.                                 notify();                //使另一线程进入唤醒状态
  42.                         }else
  43.                                 try{wait();}catch(Exception e){}        //无信息打印时线程进入等待状态


  44.                 }
  45.         }

  46.         class Input implements Runnable                        //输入接口类
  47.         {
  48.                 private Res r;                       
  49.                
  50.                 Input(Res r){
  51.                         this.r=r;
  52.                 }

  53.                 public void run(){
  54.                         int x=0;               
  55.                         while(true){
  56.                                         if(x==0)                                //x为0时输入
  57.                                                 r.set("小明","男");        //调用输入方法
  58.                                         else                                        //否则输入
  59.                                                 r.set("meimei","woman");//调用输入方法
  60.                                         x=(x+1)%2;
  61.                         }
  62.                 }
  63.         }

  64.         class Output implements Runnable                //输出接口类
  65.         {
  66.                 private Res r;
  67.                 Output(Res r){
  68.                         this.r=r;
  69.                 }

  70.                 public void run(){
  71.                         while (true)
  72.                                 r.get();                                        //调用输出方法
  73.                         }
  74.         }


  75.         class InputOutputDemo
  76.         {
  77.                 public static void main(String args[]){
  78.                         Res r=new Res();                               
  79.                         Runnable r1=new Input(r);                //创建接口对象1
  80.                         Runnable r2=new Output(r);                //创建接口对象2

  81.                         Thread t1=new Thread(r1);                //将对象1作为参数传入创建线程1
  82.                         Thread t2=new Thread(r2);                //将对象2作为参数传入创建线程2

  83.                         t1.start();                                                //开启
  84.                         t2.start();                                                //开启
  85.                 }
  86.         }
复制代码


此代码的运行结果是输入一个打印一个,原本的程序是里面有两段注释的代码,根据毕老师的视频敲出来的,也没有问题。
但我最先敲的代码输出结果却不是和毕老师的一样,自己觉得好郁闷,我和老师的判断步骤就不一样了而已,结果就是有这么大的差异。求解
我的输出结果同一时间内全是一样,一段时间后又切到另一结果继续打印

评分

参与人数 1技术分 +1 收起 理由
黄晓东 + 1

查看全部评分

2 个回复

倒序浏览
代码我大概知道怎么改了,把else去掉就可以了。

只不过我还是不太懂得这里面的运行机制,虽然唤醒另一线程后本线程必须进入等待状态,所以else不加也可以。我只是加入else应该不是影响最终判断,下一次循环总会被判断到吧。只要flag标签发生了改变,它不是就会在下一次循环中执行了else里面的语句吗?

这几天都没人的吗?偌大的论坛,求解啊
回复 使用道具 举报
室长来帮你解答;P,昭明,你看好啦,请看下面分析:lol。
  1.     class Res
  2.         {
  3.                 private String name;        
  4.                 private String sex;
  5.                 private boolean flag=false;        //定义一个标记,用于判断有无信息,默认为false

  6.                 synchronized void set(String name,String sex){
  7.                
  8.                         if(!flag){                        //当线程中并无信息时,则输入信息
  9.                                 this.name=name;
  10.                                 this.sex=sex;
  11.                                 flag=true;                //输入完成,将标记置为true
  12.                                 notify();                //使另一线程进入唤醒状态
  13.                         }//else
  14.                                 try{wait();}catch(Exception e){}        //有信息时则线程进入等待状态
  15.                
  16.                 }

  17.                  /*
  18.                                  问题分析:

  19.                                  线程r1:

  20.                                          synchronized void set(String name,String sex){
  21.                
  22.                         if(!flag){                        //当线程中并无信息时,则输入信息
  23.                                 this.name=name;
  24.                                 this.sex=sex;
  25.                                 flag=true;                //输入完成,将标记置为true
  26.                                 notify();                //使另一线程进入唤醒状态
  27.                         }else
  28.                                 try{wait();}catch(Exception e){}        //有信息时则线程进入等待状态
  29.                
  30.                 }
  31.                                 线程r2:
  32.                                 synchronized void get(){
  33.                         
  34.                         
  35.                         if(flag){                        //当有信息时,打印信息
  36.                                 System.out.println(name+"的性别是"+sex);
  37.                                 flag=false;                //打印完成后将标记置为false
  38.                                 notify();                //使另一线程进入唤醒状态
  39.                         }else
  40.                                 try{wait();}catch(Exception e){}        //无信息打印时线程进入等待状态


  41.                 }
  42.                                         这两段代码你加了else之后再唤醒另一个线程,这样做事不行的。为什么?

  43.                                                 因为假设r1线程获取到cpu执行权后,运行到if(!flag){}语句里面,此时r1线程改变了属性值后,
  44.                                         将flag标记为true,之后notify()唤醒了r2线程,但是因为你加了else,所以在if语句中,即你唤醒r2线程后,
  45.                                         你没有 【 直接 】将r1线程sleep。(如果没有直接sleep的话,会继续与r2争夺资源!!!)

  46.                                         而此时你又将线程r2唤醒,假设此时cpu的执行权还在线程r1手上,那么r2即使被唤醒,那么他也只能处于等待状态,
  47.                                         直到线程r1释放cpu执行权后,r2才能够被执行。
  48.                                

  49.                                         接着,当线程r2拿到cpu执行权后,r2线程运行到if(flag){ }语句中,此时r2获取属性值后,也将flag标记为false,
  50.                                         之后notify()唤醒了线程r1,【同样因为在if语句没有sleep自己】,所以即使r1被唤醒,自己因为有cpu执行权而继续打印。

  51.                                
  52.                                         所以你的问题就是出在:在线程唤醒对方线程后,没有【及时】sleep自己线程,导致了cpu执行权在一段时间内没有被释放,
  53.                                         即使释放了(有唤醒对方线程了),【也有可能本线程再一次夺到cpu资源】,而继续执行。(如果该线程是r2,那么它就会一段时间一直打印相同内容)

  54.                                  */            
  55.                

  56.                 synchronized void get(){
  57.                         
  58.                         
  59.                         if(flag){                        //当有信息时,打印信息
  60.                                 System.out.println(name+"的性别是"+sex);
  61.                                 flag=false;                //打印完成后将标记置为false
  62.                                 notify();                //使另一线程进入唤醒状态
  63.                         }//else
  64.                                 try{wait();}catch(Exception e){}        //无信息打印时线程进入等待状态


  65.                 }
  66.         }

  67.         class Input implements Runnable                        //输入接口类
  68.         {
  69.                 private Res r;                        
  70.                
  71.                 Input(Res r){
  72.                         this.r=r;
  73.                 }

  74.                 public void run(){
  75.                         int x=0;               
  76.                         while(true){
  77.                                         if(x==0)                                //x为0时输入
  78.                                                 r.set("小明","男");        //调用输入方法
  79.                                         else                                        //否则输入
  80.                                                 r.set("meimei","woman");//调用输入方法
  81.                                         x=(x+1)%2;
  82.                         }
  83.                 }
  84.         }

  85.         class Output implements Runnable                //输出接口类
  86.         {
  87.                 private Res r;
  88.                 Output(Res r){
  89.                         this.r=r;
  90.                 }

  91.                 public void run(){
  92.                         while (true)
  93.                                 r.get();                                        //调用输出方法
  94.                         }
  95.         }


  96.         class InputOutputDemo
  97.         {
  98.                 public static void main(String args[]){
  99.                         Res r=new Res();                                
  100.                         Runnable r1=new Input(r);                //创建接口对象1
  101.                         Runnable r2=new Output(r);                //创建接口对象2

  102.                         Thread t1=new Thread(r1);                //将对象1作为参数传入创建线程1
  103.                         Thread t2=new Thread(r2);                //将对象2作为参数传入创建线程2

  104.                         t1.start();                                                //开启
  105.                         t2.start();                                                //开启
  106.                 }
  107.         }
复制代码



评分

参与人数 1技术分 +1 收起 理由
ily521125 + 1

查看全部评分

回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马