【生产者消费者模型的 Java 实现】

文章目录

  • 前言
  • 传统派
  • 维新派


前言

题目:一个初始值为零的变量,多个线程对其交替操作,分别加1减1

实现步骤:

  1. 线程操作资源类
  2. 判断,干活,通知
  3. 防止虚假唤醒机制,即:多线程的判断需要用 while,不能使用 if(jdk 要求的,保证线程不会出错)

传统派

加锁实现,通过加锁保证线程的安全

class ShareData {// 资源类private int number = 0;// 锁private final Lock lock = new ReentrantLock();private final Condition condition = lock.newCondition();public void increment() throws InterruptedException {lock.lock();try {// 1. 判断,不能使用 if
//            if (number != 0) {while (number != 0) {// 有值,等待消费,不能生产condition.await();}// 2. 干活number++;System.out.println(Thread.currentThread().getName() + "\t" + number);// 3. 通知,唤醒condition.signalAll();} catch (InterruptedException e) {e.printStackTrace();} finally {// 手动解锁lock.unlock();}}public void decrement() {lock.lock();try {// 1. 判断
//            if (number == 0) {while (number == 0) {// 有值,等待消费,不能生产condition.await();}// 2. 干活number--;System.out.println(Thread.currentThread().getName() + "\t" + number);// 3. 通知,唤醒condition.signalAll();} catch (InterruptedException e) {e.printStackTrace();} finally {lock.unlock();}}
}public class Test {public static void main(String[] args) throws Exception {// 传统ShareData shareData = new ShareData();new Thread(() -> {for (int i = 1; i <= 5; i++) {try {shareData.increment();} catch (InterruptedException e) {e.printStackTrace();}}}, "Produce0").start();new Thread(() -> {for (int i = 1; i <= 5; i++) {shareData.decrement();}}, "Consume0").start();// 多个线程验证性质 3// 发现不是生产一个就消费一个了new Thread(() -> {for (int i = 1; i <= 5; i++) {try {shareData.increment();} catch (InterruptedException e) {e.printStackTrace();}}}, "Produce1").start();new Thread(() -> {for (int i = 1; i <= 5; i++) {shareData.decrement();}}, "Consume2").start();}
}

输出结果:

在这里插入图片描述


维新派

使用阻塞队列和原子类实现


class MyResource {// 默认开启private volatile boolean FLAG = true;// 原子类作为共享变量private final AtomicInteger atomicInteger = new AtomicInteger();// 阻塞队列实现锁的功能BlockingQueue<String> blockingQueue = null;public MyResource(BlockingQueue<String> blockingQueue) {this.blockingQueue = blockingQueue;}public void myProd() throws InterruptedException {String date = null;boolean retValue;while (FLAG) {date = atomicInteger.incrementAndGet() + "";retValue =  blockingQueue.offer(date, 2L, TimeUnit.SECONDS);if (retValue) {System.out.println(Thread.currentThread().getName() + "\t插入队列" + date + "成功");} else {System.out.println(Thread.currentThread().getName() + "\t插入队列" + date + "失败");}// 一秒生产一个TimeUnit.SECONDS.sleep(1);}System.out.println(Thread.currentThread().getName() + "\t停止生产");}public void myConsumer() throws InterruptedException {String result = null;while (FLAG) {result = blockingQueue.poll(2L, TimeUnit.SECONDS);if (result == null || result.equalsIgnoreCase("")) {FLAG = false;System.out.println(Thread.currentThread().getName() + "\t超过两秒没有取到,退出");System.out.println();System.out.println();return;}System.out.println(Thread.currentThread().getName() + "\t消费队列" + result + "成功");}}public void stop() {this.FLAG = false;}
}public class Test {public static void main(String[] args) throws Exception {MyResource myResource = new MyResource(new ArrayBlockingQueue<>(10));new Thread(() -> {System.out.println(Thread.currentThread().getName() + "\t生产线程启动");try {myResource.myProd();} catch (InterruptedException e) {e.printStackTrace();}}, "Prod").start();new Thread(() -> {System.out.println(Thread.currentThread().getName() + "\t消费线程启动");try {myResource.myConsumer();System.out.println();System.out.println();} catch (InterruptedException e) {e.printStackTrace();}}, "Consumer").start();Thread.sleep(5000);System.out.println();System.out.println("时间到,main 线程叫停");myResource.stop();}
}

输出结果:

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/344012.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

PostMan、LoadRunner进行并发压测流程

需求 两个记账接口在同一时间大量处理同一账户账务时&#xff0c;锁表顺序不同导致死锁&#xff0c;在修改完代码后模拟生产记账流程进行测试&#xff0c;需要对两个接口进行并发测试。 在进行压测的时候&#xff0c;需要对流水号进行递增。 PostMan处理流程 1. 新建Collection…

Qt QComboBox组合框控件

文章目录 1 属性和方法1.1 文本1.2 图标1.3 插入和删除1.4 信号和槽 2 实例2.1 布局2.2 代码实现 Qt中的组合框是集按钮和下拉列表体的控件&#xff0c;&#xff0c;它占用的屏幕空间很小&#xff0c;对应的类是QComboBox 1 属性和方法 QComboBox有很多属性&#xff0c;完整的…

html代码

1、Echart各种图表示例 <!DOCTYPE html> <html> <head> <meta charset"UTF-8"> <title>ECharts 箱线图示例</title> <!-- 引入 ECharts 文件 --> <script src"https://cdn.jsdelivr.net/npm/ech…

CRLF漏洞靶场记录

搭建 利用 docker 搭建 vulhub 靶场 git clone https://github.com/vulhub/vulhub.git 进入 /vulhub/nginx/insecure-configuration 目录 启动前关闭现有的 8080、8081、8082 端口服务&#xff0c;避免端口占用 docker-compose up -d 进入容器 docker exec -it insecure-…

Invalid bound statement(只有调用IService接口这一层会报错的)

问题描述:controller直接调用实现类可以,但是一旦调用IService这个接口这一层就报错. 找遍了大家都说是xml没对应好,但是我确实都可以一路往下跳,真的对应好了.结果发现是 MapperScan写错了,如下才是对的. MapperScan的作用是不需要在mapper上一直写注解了,只要启动类上写好就放…

统一格式,无限创意:高效管理不同格式图片批量转换

在数字时代&#xff0c;图片格式的多样性带来了管理上的不便。为了满足不同的需求&#xff0c;我们经常需要将大量图片转换为统一的格式。那么&#xff0c;有没有一种简单、高效的方法来解决这个问题呢&#xff1f;答案是肯定的&#xff01;今天&#xff0c;我们将为您介绍一款…

档案数字化怎样快速整理资料

对于机构和组织来说&#xff0c;档案数字化是一个重要的信息管理和保护措施。要快速整理资料进行档案数字化&#xff0c;可以遵循以下步骤&#xff1a; 1. 准备工具和设备&#xff1a;确保有一台计算机、扫描仪和相关软件。 2. 分类和组织资料&#xff1a;先将资料分类&#xf…

在CentOS中,对静态HTTP服务的性能监控

在CentOS中&#xff0c;对静态HTTP服务的性能监控和日志管理是确保系统稳定运行和及时发现潜在问题的关键。以下是对这一主题的详细探讨。 性能监控 使用工具监控&#xff1a;top、htop、vmstat、iostat等工具可以用来监控CPU、内存、磁盘I/O等关键性能指标。这些工具可以实时…

8.4V升压14V4A芯片

随着手持设备如智能手机、平板电脑等电子设备的普及&#xff0c;对电池充电技术的要求也越来越高。为了满足这一需求&#xff0c;本文将介绍一款8.4V升压14V4A芯片&#xff0c;采用SOP-8 132*476I-OOO1封装&#xff0c;适用于5V-36V输入&#xff0c;外挂MOS&#xff0c;可为主流…

服务器管理平台开发(2)- 设计数据库表

数据库表设计 本篇文章主要对数据管理平台数据库表设计进行介绍&#xff0c;包括单库多表设计、SQL语句、视图构造等 1、整体设计 设备品牌、序列号、型号等使用业务主表进行记录&#xff0c;逻辑磁盘、PCI设备可能出现1对N的情况&#xff0c;分别使用PCI设备表、Mac地址表、逻…

MySQL数据管理(二)

DML语言 DML &#xff08;数据操作语&#xff09;&#xff1a;用于操作数据库对象中所包含的数据 DML包括&#xff1a; INSERT&#xff08;添加数据语句&#xff09;UPDATE&#xff08;更新数据语句&#xff09;DELETE&#xff08;删除数据语句&#xff09; 一、添加数据 …

密码输入检测 - 华为OD统一考试

OD统一考试(C卷) 分值: 100分 题解: Java / Python / C++ 题目描述 给定用户密码输入流input,输入流中字符 ‘<’ 表示退格,可以清除前一个输入的字符,请你编写程序,输出最终得到的密码字符,并判断密码是否满足如下的密码安全要求。 密码安全要求如下: 密码长度&…