用Java解决生产者-消费者问题

当我们尝试多线程编程时,生产者-消费者问题是最常见的问题之一。 尽管不像多线程编程中的其他一些问题那样具有挑战性,但是错误地实现此问题可能会造成应用程序混乱。 生产的物品将不使用,开始的物品将被跳过,消耗量取决于生产是在消耗尝试之前还是之后开始的,等等。此外,您可能会在异常发生后很长时间注意到异常,最重要的是,几乎所有异常线程程序,这一程序也很难调试和复制。
因此,在这篇文章中,我认为我将尝试借助Java出色的java.util.concurrent包及其类来解决Java中的此问题。
首先,让我们看一下生产者-消费者问题的特征:
  • 生产者生产物品。
  • 消费者消费生产者生产的物品。
  • 生产者完成生产,并让消费者知道他们已经完成了。
请注意,在此生产者-消费者问题中,生产者运行在与消费者不同的线程上。 此设置在两种情况下有意义:
  • 消耗该项目的步骤独立产生,而不依赖于其他项目。
  • 处理项目的时间大于生产项目的时间。
第二点中的“较大”一词有些宽松。 考虑以下情况:生产者从文件中读取一行,而“消耗和处理”只是将行以特殊格式记录回文件中,那么使用生产者消费者问题解决方案可以被认为是过度设计的情况一个解法。 但是,如果对于每行,“消耗和处理”步骤是向Web服务器发出HTTP GET / POST请求,然后将结果转储到某个地方,则我们应该选择生产者-消费者解决方案。 在这种情况下,我假设行(item)本身具有执行GET / POST的所有数据,而我们不依赖于上一行/下一行。
因此,让我们首先看一下我在下面发布的生产者-消费者问题解决方案的特征:
  • 可以有多个生产者。
  • 将有多个消费者。
  • 一旦完成新物品的生产,生产者将告知消费者,以便消费者在消费并加工完最后一件物品后退出。
有趣的是,要在通用级别解决此问题,我们只能解决消费者方,而不能解决生产方。 这是因为项目的生产可以随时进行,而我们以通用方式进行项目生产的控制几乎没有。 但是,我们可以在接受生产者提供的商品时控制消费者的行为。 制定了规则之后,让我们看一下消费者合同:
package com.maximus.producerconsumer;public interface Consumer
{public boolean consume(Item j);public void finishConsumption();
}

在这里,可以由多个类似商品的生产者共享消费者。 类似的项目,我的意思是生产者,其生产“项目”类型的对象。 Item的定义如下:

package com.maximus.consumer;public interface Item
{public void process();
}

现在我们来看一下Consumer接口的实现:

package com.maximus.consumer;import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;public class ConsumerImpl implements Consumer
{private BlockingQueue< Item > itemQueue = new LinkedBlockingQueue<Item>();private ExecutorService executorService = Executors.newCachedThreadPool();private List<ItemProcessor> jobList = new LinkedList<ItemProcessor>();private volatile boolean shutdownCalled = false;public ConsumerImpl(int poolSize){for(int i = 0; i < poolSize; i++){ItemProcessor jobThread = new ItemProcessor(itemQueue);jobList.add(jobThread);executorService.submit(jobThread);}}public boolean consume(Item j){if(!shutdownCalled){try{itemQueue.put(j);}catch(InterruptedException ie){Thread.currentThread().interrupt();return false;}return true;}else{return false;}}public void finishConsumption(){for(ItemProcessor j : jobList){j.cancelExecution();}executorService.shutdown();}
}

现在,唯一感兴趣的点是消费者内部用于处理传入商品的ItemProcessor。 ItemProcessor的编码如下:

package com.maximus.consumer;import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;public class ItemProcessor implements Runnable
{private BlockingQueue<Item> jobQueue;private volatile boolean keepProcessing;public ItemProcessor(BlockingQueue<Item> queue){jobQueue = queue;keepProcessing = true;}public void run(){while(keepProcessing || !jobQueue.isEmpty()){try{Item j = jobQueue.poll(10, TimeUnit.SECONDS);if(j != null){j.process();}}catch(InterruptedException ie){Thread.currentThread().interrupt();return;}}}public void cancelExecution(){this.keepProcessing = false;}
}
上面唯一的挑战是while循环中的条件。 这样编写while循环,即使在生产者完成生产并通知消费者生产完成之后,也可以支持项目消耗的继续。 上面的while循环可确保在线程退出之前完成所有项目的消耗。
上面的使用者是线程安全的,可以共享多个生产者,以便每个生产者可以并发调用consumer.consume(),而不必担心同步和其他多线程警告。 生产者只需要提交Item接口的实现,其process()方法将包含如何完成消耗的逻辑。
作为阅读本文的奖励,我提出了一个测试程序,演示了如何使用上述类:
package com.maximus.consumer;import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;public class Test
{public static void main(String[] args) throws Exception{Consumer consumer = new ConsumerImpl(10);BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(new File(args[0]))));String line = "";while((line = br.readLine()) != null){System.out.println("Producer producing: " + line);consumer.consume(new PrintJob(line));}consumer.finishConsumption();}
}class PrintJob implements Item
{private String line;public PrintJob(String s){line = s;}public void process(){System.out.println(Thread.currentThread().getName() + " consuming :" + line);}
}
可以通过多种不同的方式来调整上述消费者,使其更加灵活。 我们可以定义生产完成后消费者将做什么。 可能对其进行了调整,以允许批处理,但我将其留给用户使用。 随意使用它,并以任何想要的方式扭曲它。
编码愉快!

参考: The Java HotSpot博客上的JCG合作伙伴 Sarma Swaranga 解决了Java中的生产者-消费者问题 。


翻译自: https://www.javacodegeeks.com/2012/05/solving-producer-consumer-problem-in.html

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

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

相关文章

哪位科学家奠定了计算机结构理论,计算机等级考试一级理论知识选择题题库(1-50)...

领域中的问题为主的数值计算称为科学计算B)计算机应用可分为数值应用和非数值应用两类C)计算机各部件之间有两股信息流&#xff0c;即数据流和控制流D)对信息(即各种形式的数据)进行收集、储存、加工与传输等一系列活动的总称为实时控制答案&#xff1a;D32. 金卡工程是我国正在…

axios 参数为payload的解决方法

1. 添加头部headers headers: {Content-Type: application/x-www-form-urlencoded,}, axios.post(url, {a: 1, b:2}, {headers: {Content-Type: application/x-www-form-urlencoded,}, }).then(response > response.data).then(err > {console.log(err);}); 2. 在Browser…

超出了GC开销限制– Java堆分析

这篇文章是我们原来的GC超出限制的问题模式帖子的延续。 正确的Java堆分析对于消除O​​utOfMemoryError&#xff1a;GC开销问题至关重要。 如果您不熟悉此Java HotSpot 1.6错误&#xff0c;建议您首先阅读有关此主题的第一篇文章 。 本文将为您提供一个示例程序和一个教程&…

开灯问题

开灯问题 时间限制&#xff1a;3000 ms | 内存限制&#xff1a;65535 KB难度&#xff1a;1描述有n盏灯&#xff0c;编号为1~n&#xff0c;第1个人把所有灯打开&#xff0c;第2个人按下所有编号为2 的倍数的开关&#xff08;这些灯将被关掉&#xff09;&#xff0c;第3 个人按…

计算机科学基本理论,计算机科学的基础知识.ppt

计算机科学的基础知识第二章 计算机科学的基础知识 本章学习目标&#xff1a; 数据的理解、分类与表示 计算机的基本结构与工作原理 程序设计基础 算法基础 2.1 数据类型 2.2 计算机内部的数据 2.3 表示数据 2.4 十进制表示法 2.5 二进制表示法 2.6 十六进制表示法 2.7 八进制表…

损坏注册表的原因

软件: &#xff08;1&#xff09;应用程序错误 &#xff08;2&#xff09;驱动程序不兼容或使用了错误的应用程序 &#xff08;3&#xff09;应用程序在注册表中添加了错误的内容 &#xff08;4&#xff09;应用程序添加了错误的数据文件和应用程序之间的联系 硬件: &#xff0…

cdockpane限制调整大小_影视后期制作小伙伴必看:使用AU对声音质量进行调整的三大技巧...

一、增幅一般人进入AU的音频调整界面&#xff0c;会使用图中的旋钮进行音量调整&#xff0c;这种操作是错误的&#xff0c;因为通过拖拽并不能确定调整音量的大小幅度&#xff0c;精准度极低&#xff0c;反复操作才能试出最佳音量&#xff0c;效率极低。最优方案是使用左侧效果…

html5css3js文件作业,HTML5 CSS3 JavaScriptWeb前端开发自测试卷2.docx

自测试卷2一、选择题1&#xff0e;使用标签在网页中成功地添加一张图片&#xff0c;必不可少的属性是( )。A&#xff0e;alt B&#xff0e;title C&#xff0e;src D&#xff0e;width2&#xff0e;使用CSS设置鼠标放置在链接上时的样式应使用以下哪个选择器( )。A&#xff0e;…

线程故事:Web应用程序中的ThreadLocal

本周&#xff0c;我花了一些合理的时间来消除Web应用程序中的所有ThreadLocal变量。 原因是他们造成了类加载器泄漏&#xff0c;我们不能再适当地取消部署我们的应用程序。 取消部署应用程序后&#xff0c;当GC根目录继续引用应用程序对象时&#xff0c;将发生类加载器泄漏。 如…

n-1位数

n-1位数 时间限制&#xff1a;3000 ms | 内存限制&#xff1a;65535 KB难度&#xff1a;1描述已知w是一个大于10但不大于1000000的无符号整数&#xff0c;若w是n(n≥2)位的整数&#xff0c;则求出w的后n-1位的数。 输入第一行为M&#xff0c;表示测试数据组数。接下来M行&…

Android之封装好的异步网络请求框架

1.简介 Android中网络请求一般使用Apache HTTP Client或者采用HttpURLConnection&#xff0c;但是直接使用这两个类库需要写大量的代码才能完成网络post和get请求&#xff0c;而使用这个MyHttpUtils库可以大大的简化操作&#xff0c;它是基于HttpURLConnection&#xff0c;所有…

华润置地php面试题_从一流到顶流|2020华润置地与沈阳一起美好

如果用一句话来形容华润置地进入沈阳13年的发展历程&#xff0c;你认为是什么&#xff1f;“从优秀到卓越”。用2020年的语言你给我翻译一下&#xff1f;“从一流到顶流”&#xff01;01/ 初识的美好犹记2007年1月&#xff0c;央企华润置地首进沈阳&#xff0c;在大馆原址呈现出…

金融工作用计算机吗,为什么计算机专业的人想转金融,而金融专业的想转计算机?...

1首先两个专业都很有前途。如果好好学IT&#xff0c;应该是走技术路线&#xff0c;30岁后逐渐开始搞些管理或者设计之类的。当然&#xff0c;继续搞技术也没问题。只是要不断学习&#xff0c;因为发展很快&#xff0c;IT业自身不断更新。很多人说IT枯燥&#xff0c;难学&#x…

Java GUI应用程序关闭陷阱

最近&#xff0c;我遇到了一个或两个Java GUI应用程序在关闭时无法关闭的问题。 它们似乎是一个过程&#xff0c;消耗着计算机资源。 今天&#xff0c;我深入探究了问题的根源&#xff0c;这是一个我以前从未意识到的棘手问题&#xff0c;所以我想我会分享一下。 理论上&#x…

shell启动程序脚本

#!/bin/bash#/usr/local/xxx/bin/xxxx.sh start#/usr/local/xxx/bin/startup.shfor i in find /server -name start.sh do fadirdirname $i //读取父目录 cd $fadir echo > nohup.out ./start.sh & sleep 2 echo "start succe…

Unity性能优化的N种武器

贴图&#xff1a; l 控制贴图大小&#xff0c;尽量不要超过 1024 x1024&#xff1b; l 尽量使用2的n次幂大小的贴图&#xff0c;否则GfxDriver里会有2份贴图&#xff1b; l 尽量使用压缩格式减小贴图大小&#xff1b; l 若干种贴图合并技术&#xff1b; l 去除多余的alpha…

cmd控制屏幕光标_电脑控制手机?上班时间愉快尽情地玩手机吧!它值得您拥有!...

在现今时代&#xff0c;手机已成为人们必不可少的工具&#xff0c;有的时候甚至可以说手机比电脑方便好用多了&#xff0c;例如某些实用的APP软件就只有手机端并没有电脑端&#xff0c;想使用的话就得整天捧着手机盯着不放。但别忘记&#xff0c;我们大多数都是打工族&#xff…

xp系统设置锁定计算机,系统锁定时不关机的诀窍 给XP系统关闭计算机再加一把锁...

很多用户抱怨在使用电脑的过程中&#xff0c;总是经常会被琐碎的事情打断&#xff0c;有时候难免暂时离开电脑&#xff0c;处于便利和资料安全&#xff0c;我们往往会按下“WindowsL”来锁定计算机。这样&#xff0c;操作方便同时又能阻止他人乱动我们的计算机。但是如果遇到好…

ACM题目————中位数

题目描述 长为L的升序序列S&#xff0c;S[L / 2]为其中位数。 给出两个等长升序序列S1和S2&#xff0c;求两序列合并并排序后的中位数。 输入 多组数据&#xff0c;每组第一行为n&#xff0c;表示两个等长升序序列的长度。 接下来n行为升序序列S1的元素&#xff0c;再接下来n行…

Regular Exprassion--正则表达式基础

正则表达式&#xff1a; 强大灵活的文本处理工具 语法&#xff1a; 普通字符 转义字符 \ , \t , \n , \\ 标准字符集合&#xff08;大写代表相反的意思&#xff09; \d 任意一个数字 \w 任意一个字母、数字、下划线 \s 空白符&#xff…