黑马程序员技术交流社区

标题: 多线程安全问题 [打印本页]

作者: 赵晓东    时间: 2012-11-24 15:07
标题: 多线程安全问题
本帖最后由 Object 于 2012-11-25 17:20 编辑
  1. /*多线程_等待唤醒机制*/

  2. /**
  3. *需求:创建两个线程,一个进行存储信息,一个进行打印信息。
  4. *目的:程序输入一个"mike man"打印一个"mike man"
  5. *           输入一个"莉莉 女女女女女"打印一个"莉莉 女女女女女"
  6. *步骤:创建一个共享资源类RescourceWaitNotifyDemo
  7. *                创建输入线程类InputWaitNotifyDemo
  8. *                创建打印线程类OutputWaitNotifyDemo
  9. *                由主函数创建线程,并执行。
  10. *问题:
  11. *                为什么会有线程安全问题?
  12. *                怎么解决?
  13. */

  14. /*线程共享资源类,信息类*/
  15. class ResourceWaitNotifyDemo //
  16. {
  17.         private String name;
  18.         private String sex;
  19.         private boolean flag=false;


  20.         public synchronized void setInfo(String name,String sex)//信息输入函数
  21.         {
  22.                 if(flag)
  23.                 /*如果flag值为false,则共享资源中没有信息,进行赋值
  24.                   如果为true,则共享资源中有信息没有打印,不进行赋值,进行wait操作
  25.                 */        
  26.                 {
  27.                         try
  28.                         {
  29.                                 this.wait();
  30.                         }
  31.                         catch (Exception e)
  32.                         {
  33.                         }
  34.                 }
  35.                 else
  36.                 {
  37.                         this.name = name;
  38.                         this.sex = sex;                        
  39.                 }        
  40.                 flag=true;         //改变开关,让输入程序不能再次进行赋值,同时可以让打印程序启动
  41.                 this.notify();//唤醒输出线程
  42.         }

  43.         public synchronized void OutInfo()//信息输出函数
  44.         {
  45.                 if (!flag)//如果flag值为ture,则共享资源中有信息,进行打印,否则等待
  46.                 {
  47.                         try
  48.                         {
  49.                                 this.wait();
  50.                         }
  51.                         catch (Exception e)
  52.                         {
  53.                         }
  54.                 }
  55.                 else
  56.                 {
  57.                         System.out.println(name+"......"+sex);                        
  58.                 }               
  59.                 flag=false;        //改变开关,让输入程序可以进行赋值,同时让自己不能在打印
  60.                 this.notify();//唤醒输入线程
  61.         }
  62. }

  63. /*输入线程*/
  64. class InputWaitNotifyDemo implements Runnable
  65. {
  66.         private ResourceWaitNotifyDemo r;        //创建共享类引用

  67.         InputWaitNotifyDemo(ResourceWaitNotifyDemo r)
  68.         {
  69.                 this.r = r;        //接收共享类对象
  70.         }

  71.         public void run()
  72.         {
  73.                 int x=0;
  74.                 while(true)
  75.                 {        
  76.                         if (x==0)
  77.                         {
  78.                                 r.setInfo("mike","man");
  79.                         }
  80.                         else
  81.                         {
  82.                                 r.setInfo("莉莉","女女女女女");
  83.                         }
  84.                         x=(x+1)%2;                                                
  85.                 }
  86.         }

  87. }

  88. /*输出线程*/
  89. class OutputWaitNotifyDemo implements Runnable
  90. {
  91.         private ResourceWaitNotifyDemo r;

  92.         OutputWaitNotifyDemo(ResourceWaitNotifyDemo r)
  93.         {
  94.                 this.r = r;        //和输入线程操作同一个共享类对象
  95.         }

  96.         public void run()
  97.         {
  98.                 while (true)
  99.                 {
  100.                         r.OutInfo();        
  101.                 }
  102.         }
  103. }

  104. /*主函数*/
  105. class ThreadWaitNotifyTest
  106. {
  107.         public static void main(String[] args)
  108.         {
  109.                 ResourceWaitNotifyDemo res = new ResourceWaitNotifyDemo();
  110. /*
  111.                 InputWaitNotifyDemo i = new InputWaitNotifyDemo(res);
  112.                 OutputWaitNotifyDemo o = new OutputWaitNotifyDemo(res);

  113.                 Thread t1 = new Thread(i);
  114.                 Thread t2 = new Thread(o);

  115.                 t1.start();
  116.                 t2.start();
  117. */
  118.                 new Thread(new InputWaitNotifyDemo(res)).start();        //创建输入线程
  119.                 new Thread(new OutputWaitNotifyDemo(res)).start();        //创建打印线程
  120.         }
  121. }
复制代码

PrintPhoto.jpg (227.81 KB, 下载次数: 18)

PrintPhoto.jpg

作者: 潘天功    时间: 2012-11-24 21:11
1、为什么会有线程安全问题?
   原因:(1)多线程访问出现延迟(由于共享数据导致);
         (2)线程的随机性(共享数据被多个线程操作)
2、怎么解决?
   (1)同步代码块
        具体格式:synchronized(对象){  需要同步的代码 }
     (2)使用 wait:让线程等待
           notify:唤醒单个线程
           notifyAll:唤醒所有线程

作者: 王阳    时间: 2012-11-24 21:57
楼主的代码没啥问题啊,应该可以正常运行吧。
作者: 潘天功    时间: 2012-11-24 22:07
王阳 发表于 2012-11-24 21:57
楼主的代码没啥问题啊,应该可以正常运行吧。

对啊、他问的问题你没看见啊?
作者: 雷剑腾    时间: 2012-11-24 22:10
代码中可使用while循环。让唤醒的线程再次判断条件。然后使用全唤醒notifyAll。问题即可解决。
作者: 赵晓东    时间: 2012-11-25 16:50
本帖最后由 Object 于 2012-11-25 17:15 编辑

问题解决掉了。

转自CSDN... 当程序从wait()返回时是什么状态? 是输出线程将信息取走了,运行了notify(),使输入线程继续运行,这时输入线程应该进行赋值操作。而楼主的代码,却有else语句,直接跳过了赋值语句。那它就是保持原来的值,所以会出现连续的相同的值。
把else 去掉即可。
作者: 赵晓东    时间: 2012-11-25 16:53
王阳 发表于 2012-11-24 21:57
楼主的代码没啥问题啊,应该可以正常运行吧。

有问题,看图片,输入一片输出一片,我预想的是输入一个,输出一个
作者: 赵晓东    时间: 2012-11-25 16:55
潘天功 发表于 2012-11-24 21:11
1、为什么会有线程安全问题?
   原因:(1)多线程访问出现延迟(由于共享数据导致);
         (2)线 ...

这代码有安全问题。我是让你们帮我解决这代码的问题,不是让你们帮我背定理啊,亲




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2