温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

Java多线程中消费者与生产者的关系是什么

发布时间:2021-11-20 14:21:33 来源:亿速云 阅读:145 作者:小新 栏目:编程语言

这篇文章将为大家详细讲解有关Java多线程中消费者与生产者的关系是什么,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。

  多线程:CPU中各种任务在交替执行过程中,被称为多线程处理。其中,每个任务的一次动态执行过程被称为进程。进程执行过程中的暂停被称为中断。进程通过中断被分解成若干段,每一段被称为一个线程。

  在消费者与生产者中,我们设定单个生产者的每次活动是馒头 +1;单个消费者每次进行的是馒头 -1;然后消费者和生产者的活动时间不确定,同时生产者和消费者的数量不确定,该经典问题我们使用多线程实现:

  我们首先确定实物,即生产者的每次生成的物品,在这里我们使用馒头代替。在WoTou的类中,我们可以看到有着自己独特的属性,即馒头的 id,我们可以在控制台清晰的看到馒头的生产和消费过程,具体实现代码如下:

  class WoTou{ //馒头,生产者生产的馒头

  int id;

  WoTou(int id){

  this.id = id;

  }

  public String toString(){

  return "WoTou:"+ id;

  }

  }

  我们需要确定馒头的存储容器,即在消费和生产发生的时候,我们需要在什么地方进行判断,馒头是否耗尽,或者馒头是否满溢。每次活动都是相当于在栈中取东西和放东西,所以我们根据栈的特性为:先进后出 原则。

  class SyncStack {//篮子容器,放馒头用的

  int index = 0;

  WoTou[] arrWT = new WoTou[6];

  }

  在篮子容器中我们简单定义栈的最大容量为6,我们之后设定生产者的类,定义为producer类。我们知道producer有着一些自己的独特属性,即往篮子SyncStack中放WoTou,每次进行馒头+1操作,还有生产者的操作Time间隔,是隔10毫秒还是5毫秒,我们使得producer类实现其Runnerable接口,调用线程的run()方法,具体代码如下:

  class Producer implements Runnable{ //生产者

  SyncStack ss= null;

  Producer(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((int)(Math.random()*1000));

  } catch (InterruptedException e) {

  // TODO: handle exception

  e.printStackTrace();

  }

  }

  }

  }

  生产者在往栈中添加数据的时候,我们使用push方法进行插入。同时定义插入的馒头数量,这里的数量并不是篮子的馒头数量。篮子里边虽然只能一次性装6个馒头,但是消费者是同时间进行操作的,所以篮子的馒头数量在消费之后,生产者继续进行生产,一直到生产20个馒头为止。

  消费者我们这里定义为Consumer类,消费者和生产者有一定的相似性,但是我们需要消费在篮子中拿的过程,我们使用pop操作,同时定义消费数量,以及操作间隔,这里都是使用线程的sleep(时间)方法, 代码如下:

  class Consumer implements Runnable{ //消费者

  SyncStack ss= null;

  Consumer(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((int)(Math.random()*1000));

  } catch (InterruptedException e) {

  // TODO: handle exception

  e.printStackTrace();

  }

  }

  }

  }

  最后我们考虑在篮子中,假如容量已满,即生产者生产过多,消费的太慢,那么生产者需要休息;同样的消费过快,容器数量为0,消费者开始休息。我们在两种情况发生的时候,需要设置两种方法,在极限情况发生的时候,进行判断。简单实现代码如下:

  public synchronized void push(WoTou wt){ //往篮子中放馒头

  while(index == arrWT.length){

  try {

  this.wait();

  } catch (InterruptedException e) {

  // TODO: handle exception

  e.printStackTrace();

  }

  }

  this.notify();

  arrWT[index] = wt;

  index++;

  }郑州人流多少钱 http://mobile.sgyy029.com/

  我们需要确定是我们在生产者进行活动的时候,不能受到其他线程的影响,即我们需要保持在某一时刻只有一个线程进行操作,这种情况我们需要使用线程的一个synchronized方法。这个方法称为死锁,锁定当前方法体执行的过程中,保持其独立性。即在方法体的前面使用synchronized关键字修饰。

  从篮子中取出馒头的操作类似于生产者,实现代码如下:

  public synchronized WoTou pop(){ //从篮子中取馒头

  while(index == 0){

  try {

  this.wait();

  } catch (InterruptedException e) {

  // TODO: handle exception

  e.printStackTrace();

  }

  }

  this.notify();

  index--;

  return arrWT[index];

  }

  我们会发现在上面两种动作中,考虑到一个问题,即数量到极限之后,我们的动作停止了。生产者在篮子容量到达6时,动作停止;消费者在篮子数量到0后,停止行为。我们这时候开始使用线程的notify方法,唤醒休眠的线程,因为线程使用了wait方法,我们可以唤醒之后,在进行各自的行为。因此篮子SynStack类中详细代码为:

  class SyncStack {//篮子容器,放馒头用的

  int index = 0;

  WoTou[] arrWT = new WoTou[6];

  public synchronized void push(WoTou wt){ //往篮子中放馒头

  while(index == arrWT.length){

  try {

  this.wait(); //线程等待

  } catch (InterruptedException e) {

  // TODO: handle exception

  e.printStackTrace();

  }

  }

  this.notify(); //唤醒wait的线程

  arrWT[index] = wt;

  index++;

  }

  public synchronized WoTou pop(){ //从篮子中取馒头

  while(index == 0){

  try {

  this.wait();

  } catch (InterruptedException e) {

  // TODO: handle exception

  e.printStackTrace();

  }

  }

  this.notify();

  index--;

  return arrWT[index];

  }

  }

  我们可以修改生产者和消费者的数量和操作间隔,不一定生产+1同时消费-1。我们可以根据修改进行更改代码,上面的运行在控制台数据

关于“Java多线程中消费者与生产者的关系是什么”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,使各位可以学到更多知识,如果觉得文章不错,请把它分享出去让更多的人看到。

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI