生产者消费者问题(生产者和消费者分别阻塞于不同的锁)

简介: 生产者消费者问题(生产者和消费者分别阻塞于不同的锁)

公众号merlinsea


背景介绍:


   之前介绍了生产者消费者阻塞在同一把this锁的解决方案,但那个方案会导致生产者和消费者互斥,即生产者生产的时候消费者不能进行消费或者消费者消费的时候生产者不能进行生产,为了解决这个问题,故提出了如下解决方案。


生产者消费者问题介绍

奔跑的小梁,公众号:梁霖编程工具库生产者消费者问题(生产者和消费者都阻塞于同一把锁this锁)


利用condition优化之前的生产者和消费者问题

特点:

1、生产者生产的时候消费者不能消费,消费者消费的时候生产者不能生产

2、生产者和消费者分别阻塞于不同的锁

640.jpg


中间商Medium

/**
 * 中间商
 */
public class Medium {
    private int num = 0;
    private static final int TOTAL = 20;
    private Lock lock = new ReentrantLock();
    private Condition consumerCondition = lock.newCondition();
    private Condition producerCondition = lock.newCondition();
    /**
     * 接收生产数据
     */
    public void put() {
        lock.lock();
        try {
            //判断当前库存,是否已经是最大的库存容量,
            if (num < TOTAL) {
                num++;
                System.out.println(Thread.currentThread().getName()+" 生产者 新增库存:" +num);
                // 如果不是,生产完成之后,通知消费者进行消费
                try {
                    Thread.sleep(500L);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                consumerCondition.signalAll();
            } else {
                // 如果是,则通知生产者进行等待,
                try {
                    System.out.println(Thread.currentThread().getName()+" 生产者 库存已满:" + num);
                    producerCondition.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        } finally {
            lock.unlock();
        }
    }
    /**
     * 获取消费数据
     */
    public void take() {
        lock.lock();
        try {
            //判断当前库存是否不足
            if (num > 0) {
                //如果充足,在消费完成之后,通知生产者进行生产
                num--;
                System.out.println(Thread.currentThread().getName()+" 消费者 消费库存:" + num);
                try {
                    Thread.sleep(1000L);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                producerCondition.signalAll();
            } else {
                //如果不足,通知消费者暂停消费
                try {
                    System.out.println(Thread.currentThread().getName()+" 消费者 库存不足:" + num);
                    consumerCondition.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        } finally {
            lock.unlock();
        }
    }
}


消费者consumer

/**
 * 消费者
 */
public class Consumer implements Runnable{
    private Medium medium;
    public Consumer( Medium medium) {
        this.medium = medium;
    }
    @Override
    public void run() {
        while (true) {
            medium.take();
        }
    }
}


生产者producer

/**
 * 生产者
 */
public class Producer implements Runnable{
    private Medium medium;
    public Producer(Medium medium) {
        this.medium = medium;
    }
    @Override
    public void run() {
        while (true) {
            medium.put();
        }
    }
}


main函数

public class Main {
    public static void main(String[] args) {
        Medium medium = new Medium();
        new Thread(new Consumer(medium)).start();
        new Thread(new Consumer(medium)).start();
        new Thread(new Producer(medium)).start();
        new Thread(new Producer(medium)).start();
        new Thread(new Producer(medium)).start();
        new Thread(new Producer(medium)).start();
    }
}


vip算法班永久学习班: 800元/人

周一、周三、周五:8:30-9:30,周六、周日:10:30-11:30

报名方式:通过公众号导航栏的刷题群即可联系到我的微信号

vip算法班详情链接

奔跑的小梁,公众号:梁霖编程工具库算法训练营快来参加吧~
相关文章
|
人工智能 运维 监控
AI时代云基础设施的技术创新与展望丨ODCC2023
AI时代云基础设施的技术创新与展望丨ODCC2023
|
安全 Java 编译器
kotlin面试题
kotlin面试题
856 1
|
存储 自然语言处理
国际化和本地化(Internationalization and Localization):打开全球市场的关键
在全球互联网时代,国际化和本地化是确保您的产品或服务能够在全球范围内成功的关键因素之一。本博客将深入探讨国际化和本地化的概念、重要性以及如何有效实施它们,以满足不同文化和地区的用户需求。
394 1
|
7月前
|
缓存 开发工具 开发者
鸿蒙NEXT开发App相关工具类(ArkTs)
这段代码展示了一个名为鸿蒙NEXT开发 `AppUtil` 的工具类,主要用于管理鸿蒙应用的上下文、窗口、状态栏、导航栏等配置。它提供了多种功能,例如设置灰阶模式、颜色模式、字体类型、屏幕亮度、窗口属性等,并支持获取应用包信息(如版本号、包名等)。该工具类需在 UIAbility 的 `onWindowStageCreate` 方法中初始化,以便缓存全局变量。代码由鸿蒙布道师编写,适用于鸿蒙系统应用开发,帮助开发者更便捷地管理和配置应用界面及系统属性。
312 0
鸿蒙NEXT开发App相关工具类(ArkTs)
|
Java 编译器 Android开发
Kotlin教程笔记(28) -Kotlin 与 Java 混编
本系列教程笔记详细讲解了Kotlin语法,适合希望深入了解Kotlin的开发者。对于需要快速学习Kotlin的小伙伴,推荐查看“简洁”系列教程。本篇笔记重点介绍了Kotlin与Java混编的技巧,包括代码转换、类调用、ProGuard问题、Android库开发建议以及相互调用时的注意事项。
136 3
|
数据可视化 Python
流形学习(Manifold Learning)是一种非线性降维方法
流形学习(Manifold Learning)是一种非线性降维方法
386 24
|
存储 机器学习/深度学习 算法
【博士每天一篇文献-算法】Gradient Episodic Memory for Continual Learning
本文介绍了一种名为Gradient Episodic Memory(GEM)的算法,旨在解决神经网络在持续学习中的灾难性遗忘问题,通过构建经验记忆库传递知识,同时提出了评估模型在任务间转移知识和避免遗忘能力的度量指标。
383 0
【博士每天一篇文献-算法】Gradient Episodic Memory for Continual Learning
|
Java 调度 Android开发
Android面试题之Kotlin中async 和 await实现并发的原理和面试总结
本文首发于公众号“AntDream”,详细解析了Kotlin协程中`async`与`await`的原理及其非阻塞特性,并提供了相关面试题及答案。协程作为轻量级线程,由Kotlin运行时库管理,`async`用于启动协程并返回`Deferred`对象,`await`则用于等待该对象完成并获取结果。文章还探讨了协程与传统线程的区别,并展示了如何取消协程任务及正确释放资源。
347 0
|
Android开发 开发者
Android面试之Activity启动流程简述
每个Android开发者都熟悉的Activity,但你是否了解它的启动流程呢?本文将带你深入了解。启动流程涉及四个关键角色:Launcher进程、SystemServer的AMS、应用程序的ActivityThread及Zygote进程。核心在于AMS与ActivityThread间的通信。文章详细解析了从Launcher启动Activity的过程,包括通过AIDL获取AMS、Zygote进程启动以及ActivityThread与AMS的通信机制。接着介绍了如何创建Application及Activity的具体步骤。整体流程清晰明了,帮助你更深入理解Activity的工作原理。
318 0
|
IDE Java 开发工具
Lombok 详解:简化 Java 开发的神奇工具
Lombok 是一款 Java 工具,通过注解自动处理如 getter/setter、toString、equals 和 hashCode 等常见代码,减少样板代码。安装 Lombok 需要在 IDE(如 IntelliJ IDEA)中添加插件,并在 Maven 或 Gradle 项目中配置依赖。常用注解包括 @Getter/@Setter 生成访问器,@ToString 生成对象描述,@EqualsAndHashCode 生成比较方法,@NoArgsConstructor/@AllArgsConstructor 生成构造器,@Data 综合应用这些注解。
1396 9