Java——多线程编程小实例:生产者-消费者问题(应用举例)

简介: Java——多线程编程小实例:生产者-消费者问题(应用举例)

1.Problem Descrption:


知识背景1:需要对操作系统中的消费者-生产者问题有一定的理解,在这里不再进行讲解了,大家可以百度或者查阅相应的书籍。

知识背景2:Java多线程的相关知识。

下面就直接上代码了!!!


2.Code:


2.1 BreadContainer类

package producer.and.consumer;
//面包容器类
public class BreadContainer {
  //面包厂的最大生产量
  public static final int maxNum=300;
  //当前面包的数量
  private int num;
  //无参构造方法
  public BreadContainer() {
  }
  //有参构造方法
  public BreadContainer(int num) {
    this.num=num;//初始化面包数量
  }
  //同步方法
  public synchronized void produceBread(int produceNum,String producerName) {
    //判断是否可以继续生产面包
    //如果当前面包数量 + 生产的面包数量 > 面包厂的最大生产量
    while(num + produceNum > maxNum) {
      //打印相关信息
      System.out.println(producerName + "要生产" + produceNum + "个,当前有"
          + num + "个,资源充足,不需要生产," + producerName + "去等待!");
      try {
        //此时无需生产  所以生产者等待
        wait();
      }catch(Exception e) {
        e.printStackTrace();
      }
    }
    //满足条件后,生产者可以生产面包,数量 = 当前面包数量 + 生产者生产的面包数量
    num = num + produceNum;
    //打印相关信息
    System.out.println(producerName + "生产了" + produceNum
          + "个,现在有" + num + "个!");
    //此时唤醒资源等待池中的所有线程
    notifyAll();
  }
  //同步方法
  public synchronized void consumeBread(int consumeNum,String consumerName) {
    //判断面包数量是否满足消费
    //如果所需消费的面包数量 > 当前面包数量
    while(consumeNum > num) {
      //打印相关信息
      System.out.println(consumerName + "要消费" + consumeNum + "个,由于现在只有"
          + num + "个," + consumerName + "于是去等待!");
      try {
        //数量不够,不能满足消费,所以消费者等待
        wait();
      }catch(Exception e) {
        e.printStackTrace();
      }
    }
    //满足条件后,数量充足,消费面包,数量 = 当前面包数量 - 所需消费的面包数量
    num = num - consumeNum;
    //打印相关信息
    System.out.println(consumerName + "消费了" + consumeNum
          + "个,现在还剩下" + num + "个!");
    //此时唤醒资源等待池中的所有线程
    this.notifyAll();
  }
}


2.2 Producer类

package producer.and.consumer;
//生产者类继承了Thread类
public class Producer extends Thread{
  //生产者一次生产的面包数量
  private int produceNum;
  //生产者需要访问的面包容器数量
  private BreadContainer bc;
  //无参构造方法
  public Producer() {
  }
  //有参构造方法
  public Producer(int produceNum,BreadContainer bc,String producerName) {
    //对生产者线程中的某些资源进行初始化
    this.produceNum=produceNum;
    this.bc=bc;
    this.setName(producerName);
  }
  //生产者的生产方法
  @Override
  public void run() {
    bc.produceBread(produceNum,this.getName());
  }
}


2.3 Consumer类

package producer.and.consumer;
//消费者类继承了Thread类
public class Consumer extends Thread{
  //记录消费者一次消费的数量
  private int consumeNum;
  //消费者需要访问的面包容器数量
  private BreadContainer bc;
  //无参构造方法
  public Consumer() {
  }
  //有参构造方法
  public Consumer(int consumeNum,BreadContainer bc,String consumerName) {
    //对消费者线程中的某些资源进行初始化
    this.consumeNum=consumeNum;
    this.bc=bc;
    this.setName(consumerName);
  }
  //消费者的消费方法
  @Override
  public void run() {
    bc.consumeBread(consumeNum,this.getName());
  }
}


2.4 Main主类

package producer.and.consumer;
//Main主类
public class Main {
  public static void main(String[] args) {
    //实例化一个面包容器类的对象,即初始面包数量为50
    BreadContainer bc=new BreadContainer(50);
    //创建相应的生产者和消费者线程对象
    Producer p1=new Producer(20,bc,"p1");
    Producer p2=new Producer(290,bc,"p2");
    Consumer c1=new Consumer(80,bc,"c1");
    Consumer c2=new Consumer(60,bc,"c2");
    //调用start()方法启动生产者-消费者线程
    c1.start();
    c2.start();
    p1.start();
    p2.start();
  }
}


2.5 Program running results

 

相关文章
|
5小时前
|
安全 Java 调度
深入理解Java并发编程:线程安全与性能优化
【5月更文挑战第12天】 在现代软件开发中,多线程编程是提升应用程序性能和响应能力的关键手段之一。特别是在Java语言中,由于其内置的跨平台线程支持,开发者可以轻松地创建和管理线程。然而,随之而来的并发问题也不容小觑。本文将探讨Java并发编程的核心概念,包括线程安全策略、锁机制以及性能优化技巧。通过实例分析与性能比较,我们旨在为读者提供一套既确保线程安全又兼顾性能的编程指导。
|
5小时前
|
Java
Java中的多线程编程:基础知识与实践
【5月更文挑战第13天】在计算机科学中,多线程是一种使得程序可以同时执行多个任务的技术。在Java语言中,多线程的实现主要依赖于java.lang.Thread类和java.lang.Runnable接口。本文将深入探讨Java中的多线程编程,包括其基本概念、实现方法以及一些常见的问题和解决方案。
|
5小时前
|
安全 算法 Java
深入理解Java并发编程:线程安全与性能优化
【5月更文挑战第13天】 在Java开发中,并发编程是一个复杂且重要的领域。它不仅关系到程序的线程安全性,也直接影响到系统的性能表现。本文将探讨Java并发编程的核心概念,包括线程同步机制、锁优化技术以及如何平衡线程安全和性能。通过分析具体案例,我们将提供实用的编程技巧和最佳实践,帮助开发者在确保线程安全的同时,提升应用性能。
10 1
|
5小时前
|
Java 编译器 开发者
Java一分钟之-Java注解的理解与应用
【5月更文挑战第12天】本文介绍了Java注解的基础知识和常见应用,包括定义、应用和解析注解。注解在编译检查、框架集成和代码生成等方面发挥重要作用。文章讨论了两个易错点:混淆保留策略和注解参数类型限制,并提供了避免策略。提醒开发者避免过度使用注解,以保持代码清晰。理解并恰当使用注解能提升代码质量。
13 3
|
5小时前
|
Java 调度
Java一分钟之线程池:ExecutorService与Future
【5月更文挑战第12天】Java并发编程中,`ExecutorService`和`Future`是关键组件,简化多线程并提供异步执行能力。`ExecutorService`是线程池接口,用于提交任务到线程池,如`ThreadPoolExecutor`和`ScheduledThreadPoolExecutor`。通过`submit()`提交任务并返回`Future`对象,可检查任务状态、获取结果或取消任务。注意处理`ExecutionException`和避免无限等待。实战示例展示了如何异步执行任务并获取结果。理解这些概念对提升并发性能至关重要。
17 5
|
5小时前
|
Java API 开发者
Java中Lambda表达式的深入理解与应用
【5月更文挑战第12天】在Java 8之后,Lambda表达式已经成为了Java开发者必备的技能之一。Lambda表达式以其简洁、灵活的特点,大大提高了编程的效率。本文将深入探讨Lambda表达式的基本概念,语法规则,以及在实际开发中的应用,帮助读者更好地理解和使用Lambda表达式。
|
5小时前
|
Java
Java一分钟:线程协作:wait(), notify(), notifyAll()
【5月更文挑战第11天】本文介绍了Java多线程编程中的`wait()`, `notify()`, `notifyAll()`方法,它们用于线程间通信和同步。这些方法在`synchronized`代码块中使用,控制线程执行和资源访问。文章讨论了常见问题,如死锁、未捕获异常、同步使用错误及通知错误,并提供了生产者-消费者模型的示例代码,强调理解并正确使用这些方法对实现线程协作的重要性。
14 3
|
5小时前
|
安全 算法 Java
Java一分钟:线程同步:synchronized关键字
【5月更文挑战第11天】Java中的`synchronized`关键字用于线程同步,防止竞态条件,确保数据一致性。本文介绍了其工作原理、常见问题及避免策略。同步方法和同步代码块是两种使用形式,需注意避免死锁、过度使用导致的性能影响以及理解锁的可重入性和升级降级机制。示例展示了同步方法和代码块的运用,以及如何避免死锁。正确使用`synchronized`是编写多线程安全代码的核心。
57 2
|
5小时前
|
安全 Java 调度
Java一分钟:多线程编程初步:Thread类与Runnable接口
【5月更文挑战第11天】本文介绍了Java中创建线程的两种方式:继承Thread类和实现Runnable接口,并讨论了多线程编程中的常见问题,如资源浪费、线程安全、死锁和优先级问题,提出了解决策略。示例展示了线程通信的生产者-消费者模型,强调理解和掌握线程操作对编写高效并发程序的重要性。
43 3
|
5小时前
|
安全 Java
深入理解Java并发编程:线程安全与性能优化
【5月更文挑战第11天】在Java并发编程中,线程安全和性能优化是两个重要的主题。本文将深入探讨这两个方面,包括线程安全的基本概念,如何实现线程安全,以及如何在保证线程安全的同时进行性能优化。我们将通过实例和代码片段来说明这些概念和技术。
4 0