java线程之并发协作:生产者消费者简单模型

代码作者链接:https://blog.csdn.net/yjsz2010/article/details/82729562
本文是对作者代码的分析

线程之并发协作:生产者消费者简单模型

对于多线程程序来说,生产者和消费者模型都是最经典的。

对于此模型,应该注意 :

  1. 生产者仅仅在仓储未满时候生产,仓满则停止生产。
  2. 消费者仅仅在仓储有产品时候才能消费,仓空则等待。
  3. 当消费者发现仓储没产品可消费时候会通知生产者生产。
  4. 生产者在生产出可消费产品时候,应该通知等待的消费者去消费。

​ 需要结合wait、notify、notifyAll来实现

代码分析

其实消费者和生产者离开了仓库也就不行了,这个模型把对应的控制都放到了仓库类中

主要思路,分别定义一个仓库对象(godown)、多个生产者(Producer )、多个消费者(Godown )。通过厂库对于其他线程的控制来实现对应的场景。

生产者的类:

class Producer extends Thread{  
    private int neednum;//生产产品的数量  
    private Godown godown;//仓库  
    Producer(int neednum, Godown godown) {  
       this.neednum = neednum;  
       this.godown = godown;  
    }  
    public void run(){  
       //生产指定数量的产品  
       godown.produce(neednum);  
    }
}  

消费者的类:

class Consumer extends Thread{  
    private int neednum;//消费产品的数量  
    private Godown godown;//仓库  
    Consumer(int neednum, Godown godown) {  
       this.neednum = neednum;  
       this.godown = godown;  
    }  
    public void run(){  
       //消费指定数量的产品  
       godown.consume(neednum);  
    }  
}  

​ 由以上代码可知,Producer和Consumer都继承了线程的Thread类,并复写了其中的run方法。在run方法中分别调用了Godown的 godown.produce(neednum); 和godown.consume(neednum);

​ 他们只负责对应的生产调用和消费。而核心的线程控制模块放到了Godown中。

本代码中俩个线程交互函数的介绍:

​ 这些方法必须从同步环境的内部来调用。线程不能调用对象上等待或通知的方法,除非它拥有那个对象的锁。

​ wait()、notify()、notifyAll()都是Object的实例方法。与每个对象具有锁一样,每个对象可以有一个线程列表,他们等待来自该信号(通知)。线程通过执行对象上的wait()方法获得这个等待列表。从那时候起,它不再执行任何其他指令,直到调用对象的notify()方法为止。**如果多个线程在同一个对象上等待,则将只选择一个线程(不保证以何种顺序)**继续执行。如果没有线程等待,则不采取任何特殊操作。

​ 如果一个线程在对象上获得一个锁,就没有任何其他线程可以进入(该对象的)类中的任何一个同步方法(睡眠不释放锁)

​ wait()的作用是让当前线程进入等待状态,同时,wait()也会让当前线程释放它所持有的锁。

​ 所以该代码是将对应的线程放入仓库对象的等待列表中,释放该对象的锁,直到notifyall()所有的等待线程。

  • wait():
  1. void wait(longtimeout)——导致当前的线程等待,直到其他线程调用此对象的 notify()方法或 notifyAll()方法,或者超过指定的时间量。
  2. void wait(longtimeout, int nanos)——导致当前的线程等待,直到其他线程调用此对象的 notify()方法或 notifyAll()方法,或者其他某个线程中断当前线程,或者已超过某个实际时间量。
  3. void wait()——导致当前的线程等待,直到其他线程调用此对象的 notify()方法或 notifyAll()方法。
  • notifyall()

    void notifyAll()——唤醒在此对象监视器上等待的所有线程

仓库类:

class Godown{  
    public static final int max_size=100;//最大库存量  
    public int curnum;//当前库存量  
    Godown() {  
    }  
    Godown(int curnum){  
       this.curnum=curnum;  
    }  
    /**  生产指定数量的产品  **/  
    public synchronized void produce(int neednum){  
       //测试是否需要生产  
       while(neednum+curnum>max_size){  
           System.out.println("要生产的产品数量" + neednum +"超过剩余库存量" + (max_size - curnum) +",暂时不能执行生产任务!");  
           try {  
              //当前的生产线程等待  
              wait();  
           } catch (InterruptedException e) {  
              e.printStackTrace();  
           }  
       }  
       //满足生产条件,则进行生产,这里简单的更改当前库存量  
       curnum+=neednum;  
       System.out.println("已经生产了"+neednum+"个产品,现仓储量为"+curnum);  
       //唤醒在此对象监视器上等待的所有线程  
       notifyAll();  
    }  
    /** 
     * 消费指定数量的产品 
     */  
    public synchronized void consume(int neednum){  
       //测试是否可以消费  
       while(curnum<neednum){  
           try {  
              //当前的生产线程等待  
              wait();  
           } catch (InterruptedException e) {  
              e.printStackTrace();  
           }  
       }  
       //满足消费条件,则进行消费,这里简单的更改当前库存  
       curnum-=neednum;  
       System.out.println("已经消费了" + neednum +"个产品,现仓储量为" + curnum);  
       //唤醒在此对象监视器上等待的所有线程  
       notifyAll();  
    }  
}  

仓库类中一共俩个同步方法

public synchronized void produce(int neednum)

public synchronized void consume(int neednum)

都通过while()条件判断,如果不符合条件,就让对应的线程进行等待,而又因为produce,consume方法始终会有一个在执行,这就使得该程序不会出现死锁。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值