黑马程序员技术交流社区

标题: 关于单生产者消费者的问题 [打印本页]

作者: haozi050    时间: 2014-1-31 13:14
标题: 关于单生产者消费者的问题
本帖最后由 haozi050 于 2014-2-9 08:34 编辑
  1. package day13;
  2. /*需求:写一个单生产单消费的例子
  3. * 思路:生产者生产馒头,消费者消费馒头。所以需要两个线程,一个生产,一个消费。生产消费的都是馒头,所以共享资源是
  4. * 馒头。
  5. * 步骤1,定义资源类,包含名称,编号
  6. * 2,定义生产任务类,复写run()方法,方法里面定义生产馒头代码
  7. * 3,定义消费者任务类,复写run()方法,方法俩面定义消费馒头代码
  8. * */
  9. class Resource
  10. {
  11. //        定义商品名称和编号
  12.         private String name;
  13.         private int count=1;
  14. //        为方便起见,将生产馒头方式和消费馒头方式定义在这里
  15.         public void set(String name)
  16.         {
  17.                 this.name=name+"--"+count;
  18.                 System.out.println(Thread.currentThread().getName()+"...生产者..."+name+count);
  19.                 count++;
  20.         }
  21.         public void get()
  22.         {
  23.                 System.out.println(Thread.currentThread().getName()+"...消费者..."+name+count);
  24.         }
  25. }
  26. class Producer implements Runnable
  27. {
  28. //        此处需要使用馒头对象调用生产馒头方法,如果new对象的话,消费者类中也是new对象,那么生产和消费的就不是同一个对象了
  29. //        ,简单说编号就错了。为了保证资源唯一,可以将馒头对象传递给生产者,消费者,这就唯一了。所以定义在构造函数中,一初始化就有资源对应。
  30.         Resource r;
  31.         Producer(Resource r)
  32.         {
  33.                 this.r=r;
  34.         }
  35.         public void run()
  36.         {
  37.                 while(true)
  38.                 {
  39.                         r.set("馒头");
  40.                 }
  41.         }
  42. }

  43. class Consumer implements Runnable
  44. {
  45.         Resource r;
  46.         Consumer(Resource r)
  47.         {
  48.                 this.r=r;
  49.         }
  50.         public void run()
  51.         {
  52.                 while(true)
  53.                 {
  54.                         r.get();
  55.                 }
  56.         }
  57. }
  58. public class ProductorConsumerDemo {

  59.         public static void main(String[] args) {
  60.                 Resource r=new Resource();
  61.                 Producer p=new Producer(r);//创建生产任务
  62.                 Consumer c=new Consumer(r);//创建消费任务
  63.                 Thread t1=new Thread(p);//创建线程明确生产任务
  64.                 Thread t2=new Thread(c);//创建线程明确消费任务
  65.                 t1.start();
  66.                 t2.start();
  67.         }

  68. }
复制代码



作者: haozi050    时间: 2014-1-31 13:15
问题是为什么每次运行,不管是生产者还是消费者编号都不是从1开始的,请问哪里出问题了?求指点!
作者: 透过生活    时间: 2014-1-31 14:15
你说的编号每次都是从0开始。这是线程名吧。Thread.currentThread().getName()这里从0开始。
作者: zhangchao    时间: 2014-1-31 21:22
首先你这程序线程不安全,但是无论如何生产者都会输出1,原因是消费者就不会改变count的值,你如果说消费者输出不了1是有可能的,因为线程不安全,假如,t1,t2 线程开启后只会有一个线程能获取执行权,假设t1具备执行权后,首先会打印1,然后count加1,然后t2获得执行权,打印肯定不是1了,而是2,;另外一种情况,t2先获得执行权,直接输出就是1. 加入同步方法,你再试试。
我是这么认为的,欢迎交流
作者: haozi050    时间: 2014-1-31 22:06
zhangchao 发表于 2014-1-31 21:22
首先你这程序线程不安全,但是无论如何生产者都会输出1,原因是消费者就不会改变count的值,你如果说消费者 ...

这个是我刚学线程写的一个例子,是单生产单消费的例子。没加同步会出现连续生产多次或者连续消费多次,这个我理解。但是在我电脑上运行时不管加不加同步每次生产或者消费馒头编号都不是从1开始的,为什么???加了sychronized修饰之后好像还是不行,求指点!Thread-0...生产者...馒头--18445
Thread-0...生产者...馒头--18446
Thread-0...生产者...馒头--18447
Thread-0...生产者...馒头--18448
Thread-0...生产者...馒头--18449
Thread-0...生产者...馒头--18450
Thread-0...生产者...馒头--18451
Thread-0...生产者...馒头--18452
Thread-0...生产者...馒头--18453
Thread-0...生产者...馒头--18454
Thread-0...生产者...馒头--18455
Thread-0...生产者...馒头--18456
Thread-0...生产者...馒头--18457
Thread-0...生产者...馒头--18458
Thread-0...生产者...馒头--18459
Thread-0...生产者...馒头--18460
Thread-0...生产者...馒头--18461
Thread-1...消费者...馒头--18188
Thread-1...消费者...馒头--18462
Thread-1...消费者...馒头--18462
Thread-1...消费者...馒头--18462
Thread-1...消费者...馒头--18462


作者: 陈文杰    时间: 2014-1-31 22:20
你要打印烤鸭数为啥输出语句name后面再加上count干嘛。
作者: haozi050    时间: 2014-2-1 00:32
陈文杰 发表于 2014-1-31 22:20
你要打印烤鸭数为啥输出语句name后面再加上count干嘛。

那是小失误,name后面确实不需要再加count,但是修正之后商品编号也不是从1开始的,麻烦哥们运行验证一下,给解释解释,谢谢了。
作者: 陈文杰    时间: 2014-2-1 01:43
线程不安全,随机性。你去同步吧
作者: zhangchao    时间: 2014-2-1 21:37
class Resource
{
//        定义商品名称和编号
        private String name;
        private int count=1;
//        为方便起见,将生产馒头方式和消费馒头方式定义在这里
        public void set(String name)
        {
                this.name=name+"--"+count;
                System.out.println(Thread.currentThread().getName()+"...生产者..."+name+count);
                                //加入这个循环你就知道了,这个就解决的你的疑惑,我用你的代码也能打印出1。
                                while(count==1)
                                {
                                        System.out.println("----------------count = 1-------------");
                                }
                count++;
        }
        public void get()
        {
                System.out.println(Thread.currentThread().getName()+"...消费者..."+name+count);
        }
}
作者: e.c    时间: 2014-2-4 15:54
生产者肯定能打出1,可能是运行太快,后面的记录覆盖了前面的导致看不到输入生产者1:Thread-0...生产者...馒头1






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