前言
还记得今年参加自学操作系统考试,最难分析的就是PV这部分,然而伟大的米老师却用一个放东西吃东西的小例子,把PV讲的栩栩如生,言简意赅。学J2SE时学到了线程部分,里面提到了线程同步,死锁问题等等一系列问题,现在(结合马士兵老师分析例子,通过java语言实现当时的PV效果。
内容
- 需求:
生产者生产窝头给消费者吃,生产者将生产的窝头放到篮子里,消费者拿着吃。为了防止生产者生产的窝头放满了篮子,再生产放不了或者消费者一直吃窝头,最后篮子的窝头没了消费者饿死了,这种情况。需要引入多线程,在生产者和消费者同时进行。其中生产者如果把篮子填满了,这时需要停下来,通知消费者赶紧吃,反之,消费者吃了窝头,吃完了后也已应该停下来,赶紧通知生产者生产窝头。
- 根据马士兵老师的面向对象分析方法来分析:
对象:生产者、消费者、篮子、窝头
- 技术点:
线程创建启动;类实现接口进而实现接口方法;异常的处理;notify()方法应用;数组和其他一些循环结构等的应用;
- UML图
- Demo
/* 作者:周丽同 说明:生产者生产窝头给消费者吃,引用多线程保证这个流程正常运行; */ public class ProducerConsumer{ public static void main(String[] args){ SyncStack ss = new SyncStack(); new Thread(new Producer(ss)).start();//创建线程,并启动线程; new Thread(new Consumer(ss)).start();//创建线程,并启动线程; } } //窝头类 class WoTou{ int id; WoTou(int id){ this.id=id; } public String toString(){ return "窝头" + id; } } //生产池 class SyncStack{ int index = 0;//标记现在有几个窝头; WoTou[] arrayWoTou = new WoTou[6]; //生产者向生产池中放入窝头; public synchronized void push(WoTou wt){ //"synchronized"用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码 //要用while不要用if,如果用if出现例外的话,会继续向下进行,导致索引溢出; while(index >= 6){ try{ this.wait(); }catch(InterruptedException e){ e.printStackTrace();//用来跟踪异常事件的发生时执行堆栈的内容; } } notify();//随机通知一个正在等待的线程; arrayWoTou[index] = wt; index++; } //消费者从生产池中消费窝头; public synchronized WoTou pop(){ while(index <= 0){ try{ this.wait(); }catch(InterruptedException e){ e.printStackTrace();//用来跟踪异常事件的发生时执行堆栈的内容; } } notify();//随机通知一个正在等待的线程; //先要index--因为index记录的是当前的窝头个数; index--; return arrayWoTou[index]; } } //生产者 class Producer implements Runnable{ SyncStack ss = new SyncStack(); Producer(SyncStack ss){ this.ss=ss; } public void run(){ for(int i=1;i<=10;i++){ WoTou wt = new WoTou(i); ss.push(wt); System.out.printIn("生产了:" + wt); } } } //消费者 class Consumer implements Runnable{ SyncStack ss = new SyncStack(); Consumer(SyncStack ss){ this.ss=ss; } public void run(){ for(int i=1;i<=10;i++){ WoTou wt = null; wt = ss.pop(); System.out.printIn("消费了" + wt); } } }
小结
根据需求,自己尝试画了UML,不知道用图中的关系合适不合适,如若有不恰当的地方,还请大神指点一二。
感谢您的宝贵时间······