马士兵视频中的生产者与消费者的经典问题

来源:互联网 发布:工程量预算软件 编辑:程序博客网 时间:2024/06/04 22:43
package org.xn.chapter16.demo;/** * 这是一个经典的生产者与消费者的问题,其中涉及到4个类 * 一个产品类(WoTou),一个存放产品的容器类(SyncStack) * 一个生产者类(Producer),一个消费者类(Consumer) * 生产者不停的生产出WoTou,而消费者不停的消费WoTou * 当容器盛满WoTou时生产者就停止生产,当容器WoTou被拿空时消费者就停止消费 * 每生产一个,就消费一个,一共生产20个WoTou,容器中最多允许存放6个WoTou *  * 现在有以下三个注意的地方: * 1、使用了wait()之后,必须使用notify()来唤醒其他线程,如果我们不采用notify * 并且两睡眠时间设为随机,那么就会出现生产完了不消费,或者消费完了不生产 * 2、在判断容器是否为空或者满的时候,只能使用while ,而不是 if, * 因为如果在wait()的过程中发生了异常,如果使用了if,那么打断后会直接执行后行的内容 * 而如果使用while的话,即使发生了打断,程序也会回头来检查,如果满足条件,继续睡眠 *  *  * */class WoTou {int id ;WoTou(int id) {this.id = id;}public String toString() {return "WoTou" + id;}}class SyncStack {WoTou[] wtArr = null;int index = 0;SyncStack(int capacity) { wtArr = new WoTou[capacity];}//定义生产方法public synchronized void push(WoTou wt) {while (index == wtArr.length) {//当容器满时try {this.wait();//阻塞当前的生产线程} catch (InterruptedException e) {e.printStackTrace();}}this.notifyAll();//并唤醒所有的消费线程wtArr[index] = wt;index++;//每生产一个wotou计数器加1}//定义消费方法public synchronized WoTou pop() {//注意这里的判断条件要使用while而不是if,避免wait()发生打断异常while (index == 0) {//当容器为空try {this.wait();//阻塞当前的消费线程} catch (InterruptedException e) {e.printStackTrace();}}index--;//每消费一个wotou计数器减1this.notifyAll();//并唤醒所有的生产线程return wtArr[index];}}class Producer0 implements Runnable{SyncStack ss = null;Producer0(SyncStack ss) {this.ss = ss;}public void run() {for (int i = 0; i < 20; i++){WoTou wt = new WoTou(i);ss.push(wt);System.out.println("生产了:" + wt);try {Thread.sleep(1000);//Thread.sleep((int)(Math.random() * 1000));} catch (InterruptedException e) {e.printStackTrace();}}}}class Consumer0 implements Runnable{SyncStack ss = null;Consumer0(SyncStack ss) {this.ss = ss;}public void run() {for (int i = 0; i < 20; i++){WoTou wt = ss.pop();System.out.println("消费了:" + wt);try {Thread.sleep(1000);    //Thread.sleep((int)(Math.random() * 1000));} catch (InterruptedException e) {e.printStackTrace();}}}}public class MsbProducerConsumer {public static void main(String[] args) {//定义容器的容量SyncStack ss = new SyncStack(6);//新建生产者和消费者,并且引用的是同一个容器Producer0 p = new Producer0(ss);Consumer0 c = new Consumer0(ss);new Thread(p).start();new Thread(c).start();}}

这是一个比较经典的习题,不过里面有一些小的细节,还是值得我们去关注下,特别是对于初学者来说。

0 0
原创粉丝点击