关于java:并发王者课青铜10千锤百炼如何解决生产者与消费者经典问题

24次阅读

共计 2752 个字符,预计需要花费 7 分钟才能阅读完成。

欢送来到《并发王者课》,本文是该系列文章中的 第 10 篇

在本篇文章中,我将为你介绍并发中的经典问题 - 生产者与消费者问题,并基于后面系列文章的知识点,通过 wait、notify 实现这一问题的简版计划

一、生产者与消费者问题

生产者消费者问题(Producer-consumer problem),也称无限缓冲问题(Bounded-buffer problem),是一个多过程、线程同步问题的经典案例。

这个问题形容了共享固定大小缓冲区的两个过程——即所谓的“生产者 ”和“ 消费者 ”——在理论运行时会产生的问题。 生产者的次要作用是生成一定量的数据放到缓冲区中,而后反复此过程。与此同时,消费者也在缓冲区耗费这些数据。

生产者与消费者问题的关键在于 要保障生产者不会在缓冲区满时退出数据,消费者也不会在缓冲区中空时耗费数据

要解决该问题,就必须让生产者在缓冲区满时休眠(要么罗唆就放弃数据),等到下次消费者耗费缓冲区中的数据的时候,生产者能力被唤醒,开始往缓冲区增加数据

同样,也能够让消费者在缓冲区空时进入休眠,等到生产者往缓冲区增加数据之后,再唤醒消费者。通常采纳线程间通信的办法解决该问题,罕用的办法有信号量等。如果解决办法不够欠缺,则容易呈现死锁的状况。呈现死锁时,两个线程都会陷入休眠,期待对方唤醒本人。

当然,生产者与消费者问题并不是局限于单个生产者与消费者,在理论工作中,遇到更多的是多个生产者和消费者的情景

生产者与消费者模式在软件开发与设计中有着十分宽泛的利用。在这一模式中,生产者与消费者互相独立,它们仅通过缓冲区传递数据,因而能够用于程序间的 解耦 异步削峰 等。

生产者与消费者问题的要点:

  • 生产者与消费者解耦,两者通过缓冲区传递数据
  • 缓冲区数据装满了之后,生产者进行数据生产或抛弃数据
  • 缓冲区数据为空后,消费者进行生产并进入期待状态,期待生产者告诉

二、实现生产者与消费者计划

本节中,咱们通过王者中的一个场景来模仿生产者与消费者问题。

在王者中,英雄兰陵王须要通过打野来发育,然而野区的野怪在被打完之后,须要隔一段时间再投放。

所以,咱们创立两个线程,一个作为 生产者 向野区投放野怪,一个作为 消费者 打怪。

生产者 :每秒查看一次野区,如果野区没有野怪,则进行投放。 野怪投放后,告诉打野英雄

// 野怪投放【生产者】public static class WildMonsterProducer implements Runnable {public void run() {
    try {createWildMonster();
    } catch (InterruptedException e) {System.out.println("野怪投放被中断");
    }
  }

  // 投放野怪,每 1 秒查看一次
  public void createWildMonster() throws InterruptedException {for (int i = 0;; i++) {synchronized(wildMonsterArea) {if (wildMonsterArea.size() == 0) {wildMonsterArea.add("野怪" + i);
          System.out.println(wildMonsterArea.getLast());
          wildMonsterArea.notify();}
      }
      Thread.sleep(1000);
    }
  }
}

消费者 :打野英雄兰陵王作为消费者,在朝区打怪发育。如果野区有野怪,则打掉野怪。如果没有,会进行 期待野区新的野怪产生

// 兰陵王,打野英雄
public static class LanLingWang implements Runnable {public void run() {
    try {attackWildMonster();
    } catch (InterruptedException e) {System.out.println("兰陵王打野被中断");
    }
  }

  // 打野,如果没有则进行期待
  public void attackWildMonster() throws InterruptedException {while (true) {synchronized(wildMonsterArea) {if (wildMonsterArea.size() == 0) {wildMonsterArea.wait();
        }
        String wildMonster = wildMonsterArea.getLast();
        wildMonsterArea.remove(wildMonster);
        System.out.println("播种野怪:" + wildMonster);
      }
    }
  }
}

创立野区,并启动生产者与消费者线程。

public class ProducerConsumerProblemDemo {

    // 野怪流动的野区
    private static final LinkedList<String> wildMonsterArea = new LinkedList<String>();

    public static void main(String[] args) {Thread wildMonsterProducerThread = new Thread(new WildMonsterProducer());
        Thread lanLingWangThread = new Thread(new LanLingWang());

        wildMonsterProducerThread.start();
        lanLingWangThread.start();}
}

在下面几段代码中,你须要重点留神的是 synchronizedwaitnotify用法,它们是本次计划的要害。运行后果如下:

野怪 0
播种野怪:野怪 0
野怪 1
播种野怪:野怪 1
野怪 2
播种野怪:野怪 2
野怪 3
播种野怪:野怪 3
野怪 4
播种野怪:野怪 4
野怪 5
播种野怪:野怪 5
野怪 6
播种野怪:野怪 6 

从后果能够看到,生产者在创立野怪后,打野英雄兰陵王会进行打野,实现了生产者与消费者的问题。

小结

以上就是对于线程异样解决的全部内容,在本文中咱们基于 waitnotify 来解决生产者与消费者问题。对于本文内容,你须要了解生产者与消费者问题的外围是什么。另外,本文所提供的计划仅仅是这一问题多种解决方案中的一种,在前面的文章中,咱们会依据新的知识点提供其余的解法。

注释到此结束,祝贺你又上了一颗星✨

夫子的试炼

  • 编写代码实现生产者与消费者问题。

延长浏览

  • Producer–consumer problem
  • 《并发王者课》纲要与更新进度总览

对于作者

关注公众号【庸人技术笑谈】,获取及时文章更新。记录平凡人的技术故事,分享有品质(尽量)的技术文章,偶然也聊聊生存和现实。不贩卖焦虑,不做题目党。

如果本文对你有帮忙,欢送 点赞 关注 监督 ,咱们一起 从青铜到王者

正文完
 0