线程中的生产者和消费者的模拟

package org.demo.thread;

public class ProduceConSumer {

 /**
  *生产者和消费者的关系
  */
 public static void main(String[] args) {
  // TODO Auto-generated method stub

  // 构建一个篮子
  SyncStack ss = new SyncStack();
  // 构建一个生产者
  producer producer = new producer(ss);
  // 构建一个消费额在
  Consumer consumer = new Consumer(ss);
  // :两个线程访问的是同一个篮子
  new Thread(producer).start();// 生产者的线程启动
  new Thread(consumer).start();// 消费者的线程启动

  // 注:这里可以多个生产者一个消费者,但是完美的效果是一个生产者,对应一生产者,不然就在消费者那里消费的数目等于生产者生产的数目
  // new Thread(producer).start();
  // new Thread(producer).start();
  // new Thread(producer).start();
  // new Thread(producer).start();
 }

}

// 馒头
class WoTou {
 int id;

 public WoTou(int id) {
  this.id = id;
 }

 // 重写 toString 是为了看到消费者
 @Override
 public String toString() {
  // TODO Auto-generated method stub
  return "WoTou:" + id;
 }
}

// 装馒头的篮子,先进后出
class SyncStack {
 int index = 0;
 /**
  * 用于装馒头的容量
  */
 WoTou[] arrWT = new WoTou[6];

 /**
  * 用于装馒头的容量 装馒头 注意仔细想想为什么加synchronized 考虑当篮子装满了的时候,index会超出索引报错,解决办法 wait
  *
  * @throws InterruptedException
  */
 public synchronized void push(WoTou wt) {
  // 当index=篮子的长度的时候,篮子满了
  while (index == arrWT.length) {// 注意这里永远是while

   /**
    * 注意这里抛异常,wait不是线程的, wait是Object的里面的方法 对wait的解释:当前的正在访问我这个对象的线程wait
    * wait和sleep的区别:
    * (wait过后synchronized不在拥有,sleep后,睡着了还是拥有synchronized)
    */
   try {
    this.wait();
   } catch (InterruptedException e) {
    e.printStackTrace();
   }

  }
  // 当wait完过后是需要叫醒wait的,notify和wait一般都是一一对应
  // notify的作用叫醒一个正在wait的线程的对象,让线程继续执行
  this.notify();
  // this.notifyAll();//顾名思义,有多个的时候调用这个
  arrWT[index] = wt;
  index++;
 }

 // 拿出一个馒头
 public synchronized WoTou pop() {
  // 消费完了,篮子没货了,这里wait和上面一样
  while (index == 0) {// 注意这里永远只能是while
   try {
    this.wait();
   } catch (InterruptedException e) {
    e.printStackTrace();
   }
  }
  this.notify();// 注意:当注释掉这里的时候,没叫醒正在wait的线程,观察一下数据的结果
  // this.notifyAll();//顾名思义,有多个的时候调用这个
  index--;
  return arrWT[index];
 }
}

// 生产者
class producer implements Runnable {

 SyncStack ss = null;// 因为生产者,要往篮子仍东西,所有拥有篮子

 public producer(SyncStack ss) {
  this.ss = ss;
 }

 @Override
 public void run() {

  // 模拟每个人生产20个馒头
  for (int i = 0; i < 20; i++) {
   WoTou wt = new WoTou(i);
   ss.push(wt);// 把馒头扔进篮子,生产方法
   System.out.println("生产了:" + wt);
   try {
    // Thread.sleep(1000);// 为了观察数据,让它每生产一个睡眠一秒
    // 随机随眠,这里把生产的时间速度快点,有助于观察数据,
    // 当消费玩完了的时候,消费者没有告诉它,没有叫醒wait,这是在注释掉this.notify()的时候,就一直等待,也算线程的死锁
    // 这里还同理消费这的this.notify(),所以在生产者和消费者中的this.notify()这两个都是不能缺少的
    Thread.sleep((int) (Math.random() * 200));

   } catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
  }

 }

}

// 消费者
class Consumer implements Runnable {

 SyncStack ss = null;// 消费者从篮子拿馒头

 public Consumer(SyncStack ss) {
  this.ss = ss;
 }

 @Override
 public void run() {

  // 模拟每个人吃20个馒头
  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) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
  }

 }

}

/**
 * 注:wait()和sleep()的区别:
 * wait方法是Object的方法,都能让线程停止一会,wait停止是相当于把锁放开了,别人可以访问
 * sleep是线程的方法,都能让线程停止一会,sleep停止的时候,仍然抱着锁,别人无法访问,
 *
 */

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值