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();
                        }
                    }
                }
            }
        }
    }
}


目录
相关文章
|
7月前
|
JSON 网络协议 安全
【Java】(10)进程与线程的关系、Tread类;讲解基本线程安全、网络编程内容;JSON序列化与反序列化
几乎所有的操作系统都支持进程的概念,进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位一般而言,进程包含如下三个特征。独立性动态性并发性。
396 1
|
7月前
|
JSON 网络协议 安全
【Java基础】(1)进程与线程的关系、Tread类;讲解基本线程安全、网络编程内容;JSON序列化与反序列化
几乎所有的操作系统都支持进程的概念,进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位一般而言,进程包含如下三个特征。独立性动态性并发性。
372 1
|
8月前
|
数据采集 存储 弹性计算
高并发Java爬虫的瓶颈分析与动态线程优化方案
高并发Java爬虫的瓶颈分析与动态线程优化方案
Java 数据库 Spring
357 0
|
8月前
|
算法 Java
Java多线程编程:实现线程间数据共享机制
以上就是Java中几种主要处理多线程序列化资源以及协调各自独立运行但需相互配合以完成任务threads 的技术手段与策略。正确应用上述技术将大大增强你程序稳定性与效率同时也降低bug出现率因此深刻理解每项技术背后理论至关重要.
539 16
|
9月前
|
缓存 并行计算 安全
关于Java多线程详解
本文深入讲解Java多线程编程,涵盖基础概念、线程创建与管理、同步机制、并发工具类、线程池、线程安全集合、实战案例及常见问题解决方案,助你掌握高性能并发编程技巧,应对多线程开发中的挑战。
|
9月前
|
数据采集 存储 前端开发
Java爬虫性能优化:多线程抓取JSP动态数据实践
Java爬虫性能优化:多线程抓取JSP动态数据实践
|
10月前
|
安全 Java API
Java 集合高级应用与实战技巧之高效运用方法及实战案例解析
本课程深入讲解Java集合的高级应用与实战技巧,涵盖Stream API、并行处理、Optional类、现代化Map操作、不可变集合、异步处理及高级排序等核心内容,结合丰富示例,助你掌握Java集合的高效运用,提升代码质量与开发效率。
402 0
|
10月前
|
安全 JavaScript Java
java Web 项目完整案例实操指南包含从搭建到部署的详细步骤及热门长尾关键词解析的实操指南
本项目为一个完整的JavaWeb应用案例,采用Spring Boot 3、Vue 3、MySQL、Redis等最新技术栈,涵盖前后端分离架构设计、RESTful API开发、JWT安全认证、Docker容器化部署等内容,适合掌握企业级Web项目全流程开发与部署。
894 0
|
10月前
|
Java API 调度
从阻塞到畅通:Java虚拟线程开启并发新纪元
从阻塞到畅通:Java虚拟线程开启并发新纪元
495 83

热门文章

最新文章