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

© 何仕映 中级黑马   /  2013-3-22 23:57  /  1625 人查看  /  4 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

本帖最后由 何仕映 于 2013-3-24 14:06 编辑

下面这个生产消费的例子,我是想暴露出wait()和notify()的在多个线程干一件事情时线程间通信的不足。我想看到的安全问题是生产两次消费一次或者生产两次消费一次。但是在执行过程中还出现了另一个问题就是一大片的销售没有生产,按代码上来执行应该是如果销售了没有生产,标志位是不会变的,是不会再销售的,为什么还会有那么多销售打出来呢?
下面是代码:请高手帮帮忙分析一下
  1. class Goods        //定义商品类
  2. {
  3.         private String name;//商品的属性
  4.         private int num = 0;//商品的编号
  5.         boolean flag = false;//定义标志位,如果为真代表已生产商品,等待销售

  6.         Goods(String name)        //构造函数
  7.         {
  8.                 this.name = name;
  9.         }
  10.         
  11.         public  void Product()        //商品的生产
  12.         {
  13.                 synchronized(this)
  14.                 {
  15.                         if(flag)
  16.                                 try{this.wait();}catch(Exception e){}//如果商品生产了则等待
  17.                         System.out.println(Thread.currentThread().getName()+"Product \t"+this.name+"\t编号是"+(++num));
  18.                         flag = true;
  19.                         this.notify();
  20.                 }
  21.         }

  22.         public  void Sell()        //商品的销售
  23.         {
  24.                 synchronized(this)
  25.                 {
  26.                         if(!flag)
  27.                                 try{this.wait();}catch(Exception e){}//如果商品卖出了,则等待
  28.                         System.out.println(Thread.currentThread().getName()+"Sell \t"+this.name+"\t编号是"+num);
  29.                         flag = false;
  30.                         this.notify();
  31.                 }
  32.         }
  33. }
  34. class Product implements Runnable        //商品生产的类
  35. {
  36.         Goods g;
  37.         Product(Goods g)
  38.         {
  39.                 this.g = g;
  40.         }
  41.         public void run()
  42.         {
  43.                 while(true)
  44.                 {
  45.                         g.Product();
  46.                 }
  47.         }
  48. }
  49. class Sell implements Runnable        //商品销售的类
  50. {
  51.         Goods g;
  52.         Sell(Goods g)
  53.         {
  54.                 this.g = g;
  55.         }

  56.         public void run()
  57.         {
  58.                 while(true)
  59.                 g.Sell();
  60.         }
  61. }
  62. class ProductSellDemo        //主函数
  63. {
  64.         public static void main(String[] args)
  65.         {
  66.                 Goods g = new Goods("IPhone");
  67.                
  68.                 new Thread(new Product(g)).start();//生产线程
  69.                 new Thread(new Product(g)).start();

  70.                 new Thread(new Sell(g)).start();//销售线程
  71.                 new Thread(new Sell(g)).start();
  72.         }
  73. }
复制代码
下面是执行过程中的问题截图


消费.png (10.38 KB, 下载次数: 16)

消费.png

评分

参与人数 1技术分 +1 收起 理由
黄玉昆 + 1

查看全部评分

4 个回复

正序浏览
葛伟 发表于 2013-3-23 09:05
因为线程不同步.

能给我仔细分析一下吗?万分感谢。
回复 使用道具 举报
strawberry2013 发表于 2013-3-23 10:57
public  void Product()        
{
  synchronized(this)

我知道啊,如果换成你修改后的代码就不会出现生产一次销售两次或者是生产两次销售一次的情况。我写这个代码就是为了让他暴露出安全问题。只是暴露的第二个问题,我不知道是怎么来的。按代码上来执行应该是如果销售了没有生产,标志位是不会变的,是不会再销售的,顶多是销售两次或者生产两次,为什么还会有那么多销售打出来呢?
看我上面的截图,我是不知道为什么会暴露第二个安全问题。
回复 使用道具 举报
public  void Product()        
{
  synchronized(this)
  {
          while(flag)      //此处为while不应该为if,以便对唤醒的等待做出判断
                  try{this.wait();}catch(Exception e){}
          System.out.println(Thread.currentThread().getName()+"Product \t"+this.name+"\t编号是"+(++num));
          flag = true;
          this.notifyAll(); // 此处为notifyAll()唤醒该锁下的所有的线程,如为notify()则有可能唤醒仍为该区域
  }
}

public  void Sell()   
{
  synchronized(this)
  {
          while(!flag)     // 解释如上
                  try{this.wait();}catch(Exception e){}
          System.out.println(Thread.currentThread().getName()+"Sell \t"+this.name+"\t编号是"+num);
          flag = false;
          this.notifyAll();        // 解释如上
  }
}


建议仔细观看毕老师第12天课程!

评分

参与人数 1技术分 +1 收起 理由
黄玉昆 + 1

查看全部评分

回复 使用道具 举报
因为线程不同步.
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马