Java 线程 案例:生产者与消费者

简介: Java 线程 案例:生产者与消费者

一  案例目地

掌握控制线程的执行次序,实现按照要求的线程执行

二  案例要求:

生产者:

  1. 判断 “桌子上” 是否有 “食品” ,如果有就等待,如果没有才生产
  2. 把 “食品”  放在 “桌子上”。
  3. 叫醒等待的消费者
  4. 生产者存在生产数量的限制  

消费者:

  1. 判断 “桌子上” 是否有 “食品” ,如果没有就等待,如果有就 “吃” 掉 “食品”
  2. 吃完后,叫醒等待的生产者,继续生产 “食品”

三  方法提供

  1.  
1  void wait(); 导致当前线程等待,直到另一个线程调用该对象的 notify()方法或者 notifyAll()方法
2  void notify(); 唤醒正在等待对象监视器的单个线程
3  void notifyAll(); 唤醒正在等待对象监视器的所有线程
  1. 注:使用什么对象作为锁,那么就必须用这个对象去调用等待和唤醒方法,notify()随机唤醒这把锁上等待的一个线程,notifyAll()唤醒这把锁上的所有线程

四  代码演示

  1. 测试类:
public class Test {
    public static void main(String[] args) {
        Producer p = new Producer();
        Consumer c = new Consumer();
        p.start();
        c.start();
    }
}
  1. 生产者类:
//创建生产者类
public class Producer extends Thread{
    public void run() {
        //因为操作不止一次,使用while循环
        while (true){
            //共享数据,使用同步代码块
            synchronized (Desk.lock){
                //判断是否达到,生产者上线
                if (Desk.count == 0){
                    break;
                }else {
                    //判断桌上是否有“食品”
                    if(Desk.flag){
                        //如果有,就等待
                        try {
                            Desk.lock.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }else {
                        //如果没有,进行生产
                        System.out.println("生产者正在生产");
                        //表示有食品了
                        Desk.flag = true;
                        //叫醒消费者
                        Desk.lock.notifyAll();
                        //生产者上线数减一
                        Desk.count--;
                    }
                }
            }
        }
    }
}
  1. 消费者类:
//创建消费者类
public class Consumer extends Thread{
    public void run() {
        //因为操作不止一次,使用while循环
        while (true){
            //共享数据,使用同步代码块
            synchronized (Desk.lock){
                //判断是否达到,生产者上线
                if (Desk.count == 0){
                    break;
                }else {
                    //判断桌上是否有“食品”
                    if(Desk.flag){
                        //如果有
                        System.out.println("消费者正在吃掉食品");
                        //表示没有食品了
                        Desk.flag = false;
                        //叫醒生产者
                        Desk.lock.notifyAll();
                    }else {
                        //如果没有,进行等待
                        //使用什么对象作为锁,那么就必须用这个对象去调用等待与唤醒方法
                        try {
                            Desk.lock.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    }
}
  1. “桌子类”:
//创建桌子类
public class Desk {
    //定义标记,如果为true,表示桌子上有“食品”,如果false表示无
    public static boolean flag = false;
    //定义,生产的生产上线
    public static int count = 10;
    //锁对象,在此次定义,使用final,目地:保证消费者与生产者锁对象唯一
    public static final Object lock = new Object();
}
  1. 效果演示:实现了,对生产者与消费者的执行次序控制image.png

五  线程写法小结

  1. while(true)死循环
  2. synchronized  锁,锁对象要唯一
  3. 判断,共享数据是否结束,如果结束就跳出循环
  4. 如果没有结束,执行题目逻辑要求

六  代码优化

  为了体现面向对象编程的特性,对代码进行优化

  1. 桌子类进行封装:
//创建桌子类
public class Desk {
    //定义标记,如果为true,表示桌子上有“食品”,如果false表示无
    //public static boolean flag = false;
    private boolean flag = false;
    //定义,生产的生产上线
    //public static int count = 10;
    private int count = 10;
    //锁对象,在此次定义,使用final,目地:保证消费者与生产者锁对象唯一
    //public static final Object lock = new Object();
    private final Object lock = new Object();
    //空参构造
    public Desk() {
    }
    //全参构造
    public Desk(boolean flag, int count) {
        this.flag = flag;
        this.count = count;
    }
    //提供get,set方法
    //boolean的get方法叫做is...
    public boolean isFlag() {
        return flag;
    }
    public void setFlag(boolean flag) {
        this.flag = flag;
    }
    public int getCount() {
        return count;
    }
    public void setCount(int count) {
        this.count = count;
    }
    //lock因为由final修饰,所以没有set方法
    public Object getLock() {
        return lock;
    }
    //toString()方法重写
    public String toString() {
        return "Desk{" +
                "flag=" + flag +
                ", count=" + count +
                ", lock=" + lock +
                '}';
    }
}
  1. 测试类:
public class Test {
    public static void main(String[] args) {
        //在测试类中,创建esk对象D,防止Producer与Consumer的共享数据不同
        Desk desk = new Desk();
        //提供分别的Desk对象构造方法
        Producer p = new Producer(desk);
        Consumer c = new Consumer(desk);
        p.start();
        c.start();
    }
}
  1. 生产者类:
//创建生产者类
public class Producer extends Thread{
    private Desk desk;
    public Producer(Desk desk) {
        this.desk = desk;
    }
    public void run() {
        //因为操作不止一次,使用while循环
        while (true){
            //共享数据,使用同步代码块
            synchronized (desk.getLock()){
                //判断是否达到,生产者上线
                if (desk.getCount() == 0){
                    break;
                }else {
                    //判断桌上是否有“食品”
                    if(desk.isFlag()){
                        //如果有,就等待
                        try {
                            desk.getLock().wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }else {
                        //如果没有,进行生产
                        System.out.println("生产者正在生产");
                        //表示有食品了
                        desk.setFlag(true);
                        //叫醒消费者
                        desk.getLock().notifyAll();
                        //生产者上线数减一
                        desk.setCount(desk.getCount() - 1);
                    }
                }
            }
        }
    }
}
  1. 消费者类:
//创建消费者类
public class Consumer extends Thread{
    private Desk desk;
    public Consumer(Desk desk) {
        this.desk = desk;
    }
    public void run() {
        //因为操作不止一次,使用while循环
        while (true){
            //共享数据,使用同步代码块
            synchronized (desk.getLock()){
                //判断是否达到,生产者上线
                if (desk.getCount() == 0){
                    break;
                }else {
                    //判断桌上是否有“食品”
                    if(desk.isFlag()){
                        //如果有
                        System.out.println("消费者正在吃掉食品");
                        //表示没有食品了
                        desk.setFlag(false);
                        //叫醒生产者
                        desk.getLock().notifyAll();
                    }else {
                        //如果没有,进行等待
                        //使用什么对象作为锁,那么就必须用这个对象去调用等待与唤醒方法
                        try {
                            desk.getLock().wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    }
}


目录
相关文章
|
28天前
|
自然语言处理 前端开发 Java
JBoltAI 框架完整实操案例 在 Java 生态中快速构建大模型应用全流程实战指南
本案例基于JBoltAI框架,展示如何快速构建Java生态中的大模型应用——智能客服系统。系统面向电商平台,具备自动回答常见问题、意图识别、多轮对话理解及复杂问题转接人工等功能。采用Spring Boot+JBoltAI架构,集成向量数据库与大模型(如文心一言或通义千问)。内容涵盖需求分析、环境搭建、代码实现(知识库管理、核心服务、REST API)、前端界面开发及部署测试全流程,助你高效掌握大模型应用开发。
160 5
|
9天前
|
安全 算法 Java
Java 多线程:线程安全与同步控制的深度解析
本文介绍了 Java 多线程开发的关键技术,涵盖线程的创建与启动、线程安全问题及其解决方案,包括 synchronized 关键字、原子类和线程间通信机制。通过示例代码讲解了多线程编程中的常见问题与优化方法,帮助开发者提升程序性能与稳定性。
46 0
|
1月前
|
前端开发 JavaScript Java
Java 学习路线规划及项目案例中的技术栈应用解析
内容包括:**Java 17核心特性**(如sealed class、record)与模块化开发;Spring Boot 3 + Spring Cloud微服务架构,涉及响应式编程(WebFlux)、多数据库持久化(JPA、R2DBC、MongoDB);云原生技术**如Docker、Kubernetes及CI/CD流程;性能优化(GraalVM Native Image、JVM调优);以及前后端分离开发(Vue 3、Spring Boot集成)。通过全栈电商平台项目实战,掌握从后端服务(用户、商品、订单)到前端应用(Vue 3、React Native)的全流程开发。
77 9
|
7天前
|
Java API 调度
从阻塞到畅通:Java虚拟线程开启并发新纪元
从阻塞到畅通:Java虚拟线程开启并发新纪元
148 83
|
1月前
|
存储 SQL 安全
Java 无锁方式实现高性能线程实战操作指南
本文深入探讨了现代高并发Java应用中单例模式的实现方式,分析了传统单例(如DCL)的局限性,并提出了多种无锁实现方案。包括基于ThreadLocal的延迟初始化、VarHandle原子操作、Record不可变对象、响应式编程(Reactor)以及CDI依赖注入等实现方式。每种方案均附有代码示例及适用场景,同时通过JMH性能测试对比各实现的优劣。最后,结合实际案例设计了一个高性能配置中心,展示了无锁单例在实际开发中的应用。总结中提出根据场景选择合适的实现方式,并遵循现代单例设计原则以优化性能和安全性。文中还提供了代码获取链接,便于读者实践与学习。
47 0
|
13天前
|
存储 Java 调度
Java虚拟线程:轻量级并发的革命性突破
Java虚拟线程:轻量级并发的革命性突破
155 83
|
1月前
|
存储 Java
说一说 JAVA 内存模型与线程
我是小假 期待与你的下一次相遇 ~
|
28天前
|
人工智能 Java API
Java 生态大模型应用开发全流程实战案例与技术路径终极对决
在Java生态中开发大模型应用,Spring AI、LangChain4j和JBoltAI是三大主流框架。本文从架构设计、核心功能、开发体验、性能扩展性、生态社区等维度对比三者特点,并结合实例分析选型建议。Spring AI适合已有Spring技术栈团队,LangChain4j灵活性强适用于学术研究,JBoltAI提供开箱即用的企业级解决方案,助力传统系统快速AI化改造。开发者可根据业务场景和技术背景选择最适合的框架。
149 2
|
1月前
|
移动开发 Java
说一说 Java 是如何实现线程间通信
我是小假 期待与你的下一次相遇 ~
登录插画

登录以查看您的控制台资源

管理云资源
状态一览
快捷访问