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

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 韩秀山 中级黑马   /  2013-5-15 16:53  /  1286 人查看  /  8 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

学到了线程了,但是老师说有一个,生产者和消费者的例子不怎么好理解。希望谁能帮我写一下。。一定要有详细的注释。我好没学到那里,没注释看不懂!!!

8 个回复

倒序浏览
本帖最后由 兴朗ok 于 2013-5-15 18:08 编辑

多生产多消费图解(老毕)

1.JPG (64.12 KB, 下载次数: 1)

多生产多消费图解

多生产多消费图解

评分

参与人数 1技术分 +1 收起 理由
曹睿翔 + 1 自己画的图,不错

查看全部评分

回复 使用道具 举报
兴朗ok 发表于 2013-5-15 18:05
多生产多消费图解(老毕)

:'( 只是图解吗?看不懂啊!有源码吗?
回复 使用道具 举报
这是老师的源码。标注么,其实老师的视频就是最好的标注了。



  1. class ProducerConsumerDemo
  2. {
  3.         public static void main(String[] args)
  4.         {
  5.                 Resource r = new Resource();

  6.                 Producer pro = new Producer(r);
  7.                 Consumer con = new Consumer(r);

  8.                 Thread t1 = new Thread(pro);
  9.                 Thread t2 = new Thread(pro);
  10.                 Thread t3 = new Thread(con);
  11.                 Thread t4 = new Thread(con);

  12.                 t1.start();
  13.                 t2.start();
  14.                 t3.start();
  15.                 t4.start();

  16.         }
  17. }

  18. /*
  19. 对于多个生产者和消费者。
  20. 为什么要定义while判断标记。
  21. 原因:让被唤醒的线程再一次判断标记。


  22. 为什么定义notifyAll,
  23. 因为需要唤醒对方线程。
  24. 因为只用notify,容易出现只唤醒本方线程的情况。导致程序中的所有线程都等待。

  25. */


  26. class Resource
  27. {
  28.         private String name;
  29.         private int count = 1;
  30.         private boolean flag = false;
  31.                         //  t1    t2
  32.         public synchronized void set(String name)
  33.         {
  34.                 while(flag)
  35.                         try{this.wait();}catch(Exception e){}//t1(放弃资格)  t2(获取资格)
  36.                 this.name = name+"--"+count++;

  37.                 System.out.println(Thread.currentThread().getName()+"...生产者.."+this.name);
  38.                 flag = true;
  39.                 this.notifyAll();
  40.         }


  41.         //  t3   t4  
  42.         public synchronized void out()
  43.         {
  44.                 while(!flag)
  45.                         try{wait();}catch(Exception e){}//t3(放弃资格) t4(放弃资格)
  46.                 System.out.println(Thread.currentThread().getName()+"...消费者........."+this.name);
  47.                 flag = false;
  48.                 this.notifyAll();
  49.         }
  50. }

  51. class Producer implements Runnable
  52. {
  53.         private Resource res;

  54.         Producer(Resource res)
  55.         {
  56.                 this.res = res;
  57.         }
  58.         public void run()
  59.         {
  60.                 while(true)
  61.                 {
  62.                         res.set("+商品+");
  63.                 }
  64.         }
  65. }

  66. class Consumer implements Runnable
  67. {
  68.         private Resource res;

  69.         Consumer(Resource res)
  70.         {
  71.                 this.res = res;
  72.         }
  73.         public void run()
  74.         {
  75.                 while(true)
  76.                 {
  77.                         res.out();
  78.                 }
  79.         }
  80. }
复制代码
回复 使用道具 举报
chouwayメ 发表于 2013-5-15 18:15
这是老师的源码。标注么,其实老师的视频就是最好的标注了。

谢谢!!!
回复 使用道具 举报
先说两点基本的概念:
1,关于进程与线程。
        所谓进程,就是指电脑中一个正在运行中的程序,也指这个运行的程序在内存中开辟的一块内存空间。比如当我们用QQ上网聊天时,QQ这个程序(或者说为QQ程序开辟的那块内存空间)就是一个进程。
        所谓线程,是指负责程序执行的一个控制单元,也称之为执行路径。
        一个进程中至少有一条执行路径,也可以有多条执行路径。
        当进程中有多条执行路径时,我们就称之为多线程。
        在一个 java 程序的运行中,多线程就是指,除了运行 main 函数的那个线程(主线程) 之外,还有其他的线程和主线程并发执行。

2,开启一个新线程的两种方式。
        第一种方式:新建一个子类,继承Tread类,复写Tread类的 run() 方法,实例化这个子类,调用start() 方法。
        第二种方式:新建一个子类,实现Runnable接口,复写run() 方法,实例化这个类,把这个子类对象作为参数传递给new Thread(“子类对象”)。调用start()方法。
        由于在java中,子类只有一个父类,这样子类如果继承了Tread类,就不能再继承其他的类了;这就导致创建线程的第一种方式有固有的局限性;一般情况下,创建一个线程用第二种方式即可。

下面是代码演示:
  1. //共享的资源类
  2. class Resource {
  3.         private String name;
  4.         private int count = 1;
  5.         // 当flag标记为真(有货)时,执行负责消费的同步代码块,当flag标记为假(无货)时,执行负责生产的同步代码块
  6.         private boolean flag = false;

  7.         //负责生产的同步代码块
  8.         public synchronized void set(String name) {
  9.                 while (flag)
  10.                         try {
  11.                                 this.wait();  // 先判断flag,如果不满足,此线程要进入等待状态;若满足继续向下执行
  12.                         } catch (InterruptedException e) {
  13.                         }
  14.                 this.name = name + count;
  15.                 count++;
  16.                 System.out.println(Thread.currentThread().getName() + "....生产者..."
  17.                                 + this.name);
  18.                 flag = true;  // 生产完之后,就有存货了,flag修改为真
  19.                 notify(); // 唤醒其它的线程
  20.         }

  21.         //负责消费的同步代码块
  22.         public synchronized void out() {
  23.                 while (!flag)
  24.                         try {
  25.                                 this.wait(); // 先判断flag,如果不满足,此线程要进入等待状态;若满足继续向下执行
  26.                         } catch (InterruptedException e) {
  27.                         }
  28.                 System.out.println(Thread.currentThread().getName()
  29.                                 + "....消费者............." + this.name);
  30.                 flag = false;  // 消费完之后,就没有存货了,flag修改为假
  31.                 notify();  // 唤醒其它的线程
  32.         }
  33. }

  34. //生产者类,实现Runnable接口,覆盖run()方法
  35. class Producer implements Runnable {
  36.         private Resource r;

  37.         Producer(Resource r) {
  38.                 this.r = r;
  39.         }

  40.         public void run() {
  41.                 while (true) {
  42.                         r.set("烤羊肉串");
  43.                 }
  44.         }

  45. }

  46. //消费者类,实现Runnable接口,覆盖run()方法
  47. class Consumer implements Runnable {
  48.         private Resource r;

  49.         Consumer(Resource r) {
  50.                 this.r = r;
  51.         }

  52.         public void run() {
  53.                 while (true) {
  54.                         r.out();
  55.                 }
  56.         }
  57. }

  58. //演示类
  59. class MyProducerConsumer {
  60.         public static void main(String[] args) {
  61.                 Resource r = new Resource();
  62.                 Producer pro = new Producer(r);
  63.                 Consumer con = new Consumer(r);

  64.                 // 我们自己一共新建两个线程,一个负责生产,一个负责消费
  65.                 Thread t1 = new Thread(pro);
  66.                 Thread t2 = new Thread(con);

  67.                 t1.start();
  68.                 t2.start();
  69.         }
  70. }
复制代码
先注释这么多,有问题可以讨论,或者自己看一下视频。。

评分

参与人数 1技术分 +1 收起 理由
曹睿翔 + 1 鼓励下,虽然楼主想要的是线程阻塞与释放的.

查看全部评分

回复 使用道具 举报
哎哟喂,道友真是有源啦,我也刚学到这里,我觉得要理解这个程序的话可以分为两步,
第一步是先要把代码的基本功能看懂,把基本的功能看懂了就成功了一大把办
第二步才是要看多线程同步的,代码我分开来说,先是程序的基本功能
  1.         this.notifyAll();
复制代码
这个是第一步的,下面是才是关于多线程同步的
回复 使用道具 举报

  1. /*
  2.         需求:写出一个多线程生产者消费程序
  3.         思路,生产者和消费者共同处理一堆资源
  4.                   生产者和消费者由多个线程处理
  5. */
  6. class Res
  7. {
  8.         private String name;
  9.         private boolean kai=false;
  10.         private int count=1;
  11.         public synchronized void setName(String name)
  12.         {
  13.                 while (kai)
  14.                         try{this.wait();}catch(Exception e){}
  15.                
  16.                         this.name = name+count++;//先进行初始化,把商品的名字和编号进行初始化
  17.                         System.out.println(Thread.currentThread().getName()+"-----商品已经生产------"+this.name);//为了直观,把初始化的结果打印到控制台
  18.                         kai = true;
  19.                         this.notifyAll();
  20.                                
  21.         }
  22.         public synchronized void out()
  23.         {
  24.                 while(!kai)
  25.                         try{this.wait();}catch(Exception e){}
  26.                        
  27.                 System.out.println(Thread.currentThread().getName()+"----商品已售出---"+this.name);//把销售的结果打印出控制台
  28.                         kai = false;
  29.                 this.notifyAll();
  30.         }
  31. }
  32. class Producer        implements Runnable
  33. {
  34.         private Res r;
  35.         Producer(Res r)//将资源传递给生产者,并进行赋值打印处理
  36.         {
  37.                 this.r = r;
  38.         }
  39.         public void run()
  40.         {
  41.                
  42.                 while (true)//因为要打印多次,并且不知道打印次数,所以用while
  43.                 {
  44.                                 r.setName("商品");
  45.                 }
  46.         }
  47. }
  48. class Consumer implements Runnable
  49. {
  50.         private Res r;
  51.         Consumer(Res r)//把资源传递给消费者,并进行输出处理
  52.         {
  53.                 this.r = r;
  54.         }
  55.         public void run()
  56.         {
  57.        
  58.                 while (true)
  59.                 {
  60.                         r.out();
  61.                 }
  62.         }
  63. }
  64. class  h
  65. {
  66.         public static void main(String[] args)
  67.         {
  68.                 Res r = new Res();
  69.                 Producer pro = new Producer(r);
  70.                 Consumer con = new Consumer(r);
  71.                 Thread t1 = new Thread(pro);
  72.                 Thread t2 = new Thread(pro);
  73.                 Thread t3 = new Thread(con);
  74.                 Thread t4 = new Thread(con);
  75.                 t1.start();
  76.                 t2.start();
  77.                 t3.start();
  78.                 t4.start();

  79.                
  80.         }
  81. }
复制代码
无语,那个没复制到,这是第一步的
回复 使用道具 举报
  1. /*
  2.         需求:写出一个多线程生产者消费程序
  3.         思路,生产者和消费者共同处理一堆资源
  4.                   生产者和消费者由多个线程处理
  5. */
  6. class Res
  7. {
  8.         private String name;
  9.         private boolean kai=false;
  10.         private int count=1;
  11.         public synchronized void setName(String name)
  12.         {
  13.                 while (kai)//判断生产者里有没有内容,就是有没有生产商品,有生产的话就是true,true的话就要将线程冻结。所以wait,wait也要告诉是哪一个锁wait,同步函数的锁是this。
  14.                 try{this.wait();}catch(Exception e){}
  15.                 //当kai是false的时候,就代表里面没有值,就是没有商品,这时需要进行生产,所以执行以下语句
  16.                         this.name = name+count++;//先进行初始化,把商品的名字和编号进行初始化
  17.                         System.out.println(Thread.currentThread().getName()+"-----商品已经生产------"+this.name);//为了直观,把初始化的结果打印到控制台
  18.                         kai = true;//生产完之后吧开关kai变为true,告诉别人,我有值啦,有值啦,所以就不能生产啦,下一步就是要wait,所以就要在冻结前把别人唤醒,因为有可能只唤醒本方,所以要把所有线程唤醒,notifyAll
  19.                         this.notifyAll();
  20.                                
  21.         }
  22.         public synchronized void out()
  23.         {
  24.                 while(!kai)//判断开关kai是否有值,假如是false的话就要冻结啦,因为我已经消费过啦,没有商品啦,额,对了,因为wait是有异常的,但是Runnable中没有,所以就要进行try处理
  25.                         try{this.wait();}catch(Exception e){}
  26.                         //kai是ture的话就是说我还有值,我还没有被销售,我要被销售,就进行下面的操作
  27.                 System.out.println(Thread.currentThread().getName()+"----商品已售出---"+this.name);//把销售的结果打印出控制台
  28.                         kai = false;//告诉别人我别销售完毕啦,把kai置为false,下一步就是要冻结啦,就要把所有线程唤醒,
  29.                 this.notifyAll();
  30.         }
  31. }
  32. class Producer        implements Runnable
  33. {
  34.         private Res r;
  35.         Producer(Res r)//将资源传递给生产者,并进行赋值打印处理
  36.         {
  37.                 this.r = r;
  38.         }
  39.         public void run()
  40.         {
  41.                
  42.                 while (true)//因为要打印多次,并且不知道打印次数,所以用while
  43.                 {
  44.                                 r.setName("商品");
  45.                 }
  46.         }
  47. }
  48. class Consumer implements Runnable
  49. {
  50.         private Res r;
  51.         Consumer(Res r)//把资源传递给消费者,并进行输出处理
  52.         {
  53.                 this.r = r;
  54.         }
  55.         public void run()
  56.         {
  57.        
  58.                 while (true)
  59.                 {
  60.                         r.out();
  61.                 }
  62.         }
  63. }
  64. class  h
  65. {
  66.         public static void main(String[] args)
  67.         {
  68.                 Res r = new Res();
  69.                 Producer pro = new Producer(r);
  70.                 Consumer con = new Consumer(r);
  71.                 Thread t1 = new Thread(pro);
  72.                 Thread t2 = new Thread(pro);
  73.                 Thread t3 = new Thread(con);
  74.                 Thread t4 = new Thread(con);
  75.                 t1.start();
  76.                 t2.start();
  77.                 t3.start();
  78.                 t4.start();

  79.                
  80.         }
  81. }
复制代码
这个是第二步的

评分

参与人数 1技术分 +1 收起 理由
曹睿翔 + 1 云3都看见你,多来回答问题啊

查看全部评分

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