handler解析(1)——生产者消费者编程模式

简介:

某个模块负责产生数据,这些数据由另一个模块来负责处理(此处的模块是广义的,可以是类、函数、线程、进程等)。产生数据的模块,就形象地称为生产者;而处理数据的模块,就称为消费者。在生产者与消费者之间在加个缓冲区,我们形象的称之为仓库,生产者负责往仓库了进商品,而消费者负责从仓库里拿商品,这就构成了生产者消费者模式

图示:

实现方式

  1. 采用 wait—notify 的方式
  2. 采用 阻塞队列 方式

wait—notify 方式 

/**
 * 生产者类
 * 实现runnable接口
 * @author DH
 *
 */
public class Producer implements Runnable{

	private BufferArea ba;
	
	//通过传入参数的方式是使得对象相同,具有互斥锁的效果。
	public Producer(BufferArea ba){
		this.ba = ba;
	}
	
	@Override
	public void run() {
		while(true){
			setIntervalTime();
			ba.set();//生产产品
		}
	}
	
	//设置时间间隔
	public void setIntervalTime(){
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

}
/**
 * 消费者类
 * 实现runnable接口
 * @author DH
 *
 */
public class Consumer implements Runnable{
	private BufferArea ba;

	public Consumer(BufferArea ba){
		this.ba = ba;
	}
	
	@Override
	public void run() {
		while(true){
			setIntervalTime();
			ba.get();//消费产品
		}
	}
	
	//设置时间间隔
	public void setIntervalTime(){
		try {
			Thread.sleep(200);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
}
/**
 * 仓库
 * 缓冲区
 * wait()/notify()
 * @author DH
 *
 */
public class BufferArea {
	private int currNum = 0;//当前仓库的产品数量
	private int maxNum = 10;//仓库最大产品容量
	
	public synchronized void set(){
		if(currNum<maxNum){
			currNum++;
			System.out.println(Thread.currentThread().getName()+" 生产了一件产品!当前产品数为:"+currNum);
			notifyAll();
		}else{//当前产品数大于仓库的最大容量
			try {
				System.out.println(Thread.currentThread().getName()+" 开始等待!当前仓库已满,产品数为:"+currNum);
				wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
	
	public synchronized void get(){
		if(currNum>0){//仓库中有产品
			currNum--;
			System.out.println(Thread.currentThread().getName()+" 获得了一件产品!当前产品数为:"+currNum);
			notifyAll();
		}else{
			try {
				System.out.println(Thread.currentThread().getName()+" 开始等待!当前仓库为空,产品数为:"+currNum);
				wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}
/**
 * 测试类
 * @author DH
 *
 */
public class MainCode {
	public static void main(String[] args) {
		//同一个仓库
		BufferArea ba = new BufferArea();
		
		//三个生产者
		Producer p1 = new Producer(ba);
		Producer p2 = new Producer(ba);
		Producer p3 = new Producer(ba);
		//三个消费者
		Consumer c1 = new Consumer(ba);
		Consumer c2 = new Consumer(ba);
		Consumer c3 = new Consumer(ba);
		//创建线程,并给线程命名
		Thread t1 = new Thread(p1,"生产者1");
		Thread t2 = new Thread(p2,"生产者2");
		Thread t3 = new Thread(p3,"生产者3");
		Thread t4 = new Thread(c1,"消费者1");
		Thread t5 = new Thread(c2,"消费者2");
		Thread t6 = new Thread(c3,"消费者3");
		//使线程进入就绪状态
		t1.start();
		t2.start();
		t3.start();
		t4.start();
		t5.start();
		t6.start();
	}
}

通过设置生产者消费者的时间间隔,可以测试仓库满和空时的情况,当生产者时间间隔小,表示生产的快,会出现仓库满了的情况。测试结果如下。

生产者2 生产了一件产品!当前产品数为:1
生产者1 生产了一件产品!当前产品数为:2
生产者3 生产了一件产品!当前产品数为:3
生产者3 生产了一件产品!当前产品数为:4
生产者1 生产了一件产品!当前产品数为:5
生产者2 生产了一件产品!当前产品数为:6
生产者1 生产了一件产品!当前产品数为:7
生产者3 生产了一件产品!当前产品数为:8
生产者2 生产了一件产品!当前产品数为:9
生产者3 生产了一件产品!当前产品数为:10
生产者2 开始等待!当前仓库已满,产品数为:10
生产者1 开始等待!当前仓库已满,产品数为:10
消费者1 获得了一件产品!当前产品数为:9
消费者2 获得了一件产品!当前产品数为:8

当消费者时间间隔小,表示消费的快,会出现仓库为空的情况。测试结果如下。

消费者2 开始等待!当前仓库为空,产品数为:0
生产者3 生产了一件产品!当前产品数为:1
生产者2 生产了一件产品!当前产品数为:2
生产者1 生产了一件产品!当前产品数为:3
消费者2 获得了一件产品!当前产品数为:2
消费者1 获得了一件产品!当前产品数为:1
消费者3 获得了一件产品!当前产品数为:0
消费者3 开始等待!当前仓库为空,产品数为:0

举例2 

产品类(仓库)


package test.exception.producer_consumer_model;
 
/*
假设为产品为笔
 */
 
public class Production {
  private String type = "";
  private String color = "";
  private long code = 0; // 产品编号
  private boolean isProduced = false; // 是否生产完成 初始状态为未生产状态
  private boolean isContinueProduce = true; // 是否停产该产品
 
  public void setContinueProduce(boolean continueProduce) {
    isContinueProduce = continueProduce;
  }
 
  public void setCode(long code) {
    this.code = code;
  }
 
  public Production(){
  }
 
  public boolean isContinueProduce() {
    return isContinueProduce;
  }
 
  public void setType(String type) {
    this.type = type;
  }
 
  public void setColor(String color) {
    this.color = color;
  }
 
  public void setProduced(boolean produced) {
    isProduced = produced;
  }
 
  public boolean isProduced() {
    return isProduced;
  }
 
  @Override
  public String toString() {
    return color + type + "-" + code;
  }
}

生产者


package test.exception.producer_consumer_model;
 
public class Producer implements Runnable {
  private final Production pen; // 产品
 
  public Producer(Production pen) {
    this.pen = pen;
  }
 
  // 生产
  public void produce() {
    long code = 0;
    while (this.pen.isContinueProduce()) {
      synchronized (this.pen) {
        if (this.pen.isProduced()) {
          try {
            this.pen.wait(); // 等待消费者消费,将当前线程跟锁进行绑定
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
        }
        // 开始生产
        this.pen.setType("铅笔");
        this.pen.setColor("蓝色");
        this.pen.setCode(code++);
        this.pen.setProduced(true);
        System.out.println(this.pen + " is produced");
        this.pen.notify();
      }
    }
    System.out.println("finish producing");
  }
  @Override
  public void run() {
    produce();
  }
}

其中要注意的是this.pen.wait();这块是将当前线程跟锁进行绑定,这样在notifyAll的时候就没必要唤醒多余的线程了

消费者


package test.exception.producer_consumer_model;
 
public class Consumer implements Runnable {
  private final Production pen;
 
  public Consumer(Production pen) {
    this.pen = pen;
  }
 
  // 持续消费
  public void consumer() {
    while (this.pen.isContinueProduce()) {
      synchronized (this.pen) {
        if (!this.pen.isProduced()) {
          try {
            this.pen.wait(); // 等待生产者生产
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
        }
 
        System.out.println(this.pen + " is consumed"); // 使用
        this.pen.setProduced(false); // 使用完后更新状态
        this.pen.notify();
      }
    }
    // 确保停止生产后,能够使用最后生产的一支笔
    if (this.pen.isProduced()) {
      System.out.println(this.pen + " is consumed");
    }
 
    System.out.println("finish using");
  }
 
  @Override
  public void run() {
    consumer();
  }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值