对于持有线程的服务,只要服务的存在时间大于创建线程的方法的存在时间,那么就应该提供生命周期方法。 |
在下面的程序中给出了一个简单的日志服务示例,其中日志操作在单独的日志线程中执行。产生日志消息的线程并不会将消息直接写入输出流,而是由LogWriter通过BlockingQueue将消息提交给日志线程,并由日志线程写入。这是一种多生产者单消费者(Multiple-Producer,Single-Consumer)的设计方式:每个调用log的操作都相当于一个生产者,而后台的日志线程则相当于消费者。如果消费者的处理速度低于生产者的生成速度,那么BlockingQueue将阻塞生产者,直到日志线程有能力处理新的日志消息。
不支持关闭的生产者-消费者日志服务
public class LogWriter { private static final int CAPACITY = 5; private final BlockingQueue<String> queue; private final LoggerThread logger; public LogWriter(Writer writer){ this.queue = new LinkedBlockingDeque<String>(CAPACITY); this.logger = new LoggerThread(writer); } public void start(){ logger.start(); } public void log(String msg) throws InterruptedException{ queue.put(msg); } private class LoggerThread extends Thread{ private final PrintWriter writer; public LoggerThread(Writer writer){ this.writer = (PrintWriter) writer; } public void run(){ try{ while(true){ writer.println(queue.take()); } }catch(InterruptedException innored){ }finally{ writer.close(); } } } }
一般地,像Logwriter这样的服务在软件产品中能发挥实际的作用,还需要实现一种终止日志线程的方法,从而避免使JVM无法正常关闭。
一种关闭LogWriter的方法是:设置某个“已请求关闭”标志,以避免进一步提交日志消息。但存在竞态问题,提供可靠关闭操作能够解决该问题,因而要使日志消息的提交操作成为原子操作。具体代码如下:
public class LogService { private static final int CAPACITY = 5; private final BlockingQueue<String> queue; private final LoggerThread loggerThread; private final PrintWriter writer; @GuardedBy("this") private boolean isShutdown; @GuardedBy("this") private int reservations; //预约 public LogService(PrintWriter writer){ this.queue = new LinkedBlockingQueue<String>(CAPACITY); this.writer = writer; loggerThread = new LoggerThread(); } public void start(){ loggerThread.start(); } public void stop(){ synchronized(this){ isShutdown = true; } loggerThread.interrupt(); } public void log(String msg) throws InterruptedException{ synchronized(this){ if(isShutdown){ throw new IllegalStateException("..."); } ++reservations; } queue.put(msg); } private class LoggerThread extends Thread{ public void run(){ try{ while(true){ try{ synchronized(LogService.this){ if(isShutdown && reservations == 0){ break; } } String msg = queue.take(); synchronized(LogService.this){ --reservations; } writer.println(msg); }catch(InterruptedException e){ /* retry */ } } }finally{ writer.close(); } } } }
另外一种关闭生产者-消费者服务的方式就是使用“毒丸(Poison Pill)”对象:“毒丸”是指一个放在队列上的对象,其含义是:“当得到这个对象时,立即停止”。 示例代码如下:
public class IndexingService { private static final File POISON = new File(""); private final IndexerThread consumer = new IndexerThread(); private final CrawlerThread producer = new CrawlerThread(); private final BlockingQueue<File> queue = new LinkedBlockingDeque<File>(); private final File root = new File("root"); public void start(){ producer.start(); consumer.start(); } public void stop(){ producer.interrupt(); } public void awaitTermination() throws InterruptedException{ consumer.join(); } public class CrawlerThread extends Thread{ public void run(){ try{ crawl(root); }catch(InterruptedException e){ /* 发生异常 */ }finally{ while(true){ try{ queue.put(POISON); break; }catch(InterruptedException e1){ /* 重新尝试 */ } } } } private void crawl(File root) throws InterruptedException{ /*....*/ } } public class IndexerThread extends Thread{ public void run(){ try{ while(true){ File file = queue.take(); if(file == POISON){ break; }else{ indexFile(file); } } }catch(InterruptedException consumed){ } } private void indexFile(File file) { /* ... */ } } }
相关推荐
《java jdk 7学习笔记》适合java的初中级读者,以及广大java应用开发人员。 作译者 林信良(网名:良葛格) 学历:台湾大学电机工程学系 经历:台湾升阳教育训练技术顾问、专业讲师,oracle授权训练中心讲师 ...
在过去单核CPU时代,单任务在一个时间点只能执行单一程序,随着多核CPU的发展,并行程序开发就显得尤为重要。 《实战Java高并发程序设计》主要介绍基于Java的并行程序设计基础、思路、方法和实战。第一,立足于...
Java并发编程学习笔记,研究JAVA并发多线程编程的一本教程,使用并发技术可以开发出并行算法,充分利用多处理器的计算能力,避免硬件资源浪费。目前,在JAVA并发编程方面的论述系统且内容详实的技术资料不太多,Java...
Java SE 8 通过减少样板代码,改进了集合和注释,简单的并行编程模型和更有效地利用现代多核处理器,提高了开发人员的工作效率和显着的增强了应用程序的性能。 Java SE 8u172 版本更新:2018年4月17日
Java SE 8 通过减少样板代码,改进了集合和注释,简单的并行编程模型和更有效地利用现代多核处理器,提高了开发人员的工作效率和显着的增强了应用程序的性能。 Java SE 8u172 版本更新:2018年4月17日
本书不是教你怎样使用Java语言开发应用程序,而是教你怎样才能开发出更高效、更优秀的Java应用程序。书中每一个例子都经过了作者严格的验证。 本书适合于所有想编写更高效、完美Java应用程序的开发人员阅读。 本书...
Java 6 同步工具类 闭锁 *应用场景 (1)确保某个计算在其需要的所有资源都被初始化后才能继续执行 (2)确保某个服务在其所依赖的所有其他服务都已经启动之后才启动 (3)等待...
snmp源码软件开发笔记 请分叉并贡献。 编排、配置管理和 DevOps 工具: - Packer 是一种用于从单一源配置为多个平台创建相同机器映像的工具。 - 服务器自动化框架和应用 - Vagrant 是用于创建和配置虚拟开发环境的...
适用于各种开发语言和开发工具的很棒的库。 给出了一些推荐的选项。 您还可以看到更多选项。 本网站来源: 常见的 石英 提琴手 戈格斯 影袜 kcptun 代理链 海文件 邮差 代理 平++ 图形语言 免费的 SSL 证书 ...
java程序员刷题软件文件夹 这个存储库包含我参与过的著名程序和项目的集合。 README 为每个程序提供了简要说明,以及...我开发的轻量级笔记应用程序,灵感来自 Google Keep。 从美国境内的监测站收集预测和历史潮汐信
流动站java笔试题我写的笔记到处都是,我的写作也是如此。 所以我将尝试将它集中在这里。 专注于语言:C++、Javascript 和 Go。 我将在我生命的接下来几年中使用这些语言 - 最好用几种语言完善自己,而不是把所有...
其中内容均为前段时间研究开源搜索引擎时搜集参考的资料,非常齐全包含的内容有: Computing PageRank Using Hadoop.ppt Google的秘密PageRank彻底解说中文版.doc ...用_Hadoop_进行分布式并行编程.doc
沙里亚尔的笔记 原则 比特科技 算法 CI / CD 开发运维 地理信息系统 集成开发环境 3D 资源 概念 统一 虚拟现实 云 云 蔚蓝 Kubernetes 语言能力 Java s VueJS 打字稿 React p Cpp C# F# 去 斯威夫特/ ...
开发笔记 在我的 Windows 8 笔记本电脑上,当您尝试一次扫描两个或三个以上的主机时,我注意到 NMAP 存在问题。 我正在并行运行请求,所以我不确定这是否是由 java 承诺或 NMAP 本身无法同时运行引起的错误。 这个...
这种架构使得前后端可以并行开发,大大提高了开发效率。 系统功能丰富,包括用户管理、课程管理、在线学习、考试评估等多个模块。用户管理模块可以实现用户的注册、登录、信息修改等功能;课程管理模块可以对课程...
在专业课程中开发的材料和脚本 Minas Gerais天主教大学(PUC-MG)使用Python 3以及关系和非关系数据库(Oracle,MongoDB,Redis,Neo4J)的脚本和笔记本存储库,用于数据科学和大数据的毕业后研究) 技术涵盖 的...
执行mvn clean install或者对于并行构建,执行mvn -T 2.0C clean install 。 在使用了几年的适度开发笔记本电脑上,后者的构建花费了不到两分钟的时间。 经过大量输出之后,您最终应该会看到一条成功消息。
layer)是一个用于编写并行应用程序的软件开发框架。DOL允许指定基于计算Kahn进程网络模型的应用程序和具有一个基于SystemC的模拟引擎的特点。而且,DOL提供了一个基于XML规范的格式来描述在一个多处理器系统上的并行...
matlab 梁代码 目录 C++ C++ STL Java 数据结构与算法 Internet ...《CUDA并行程序设计-GPU编程指南》读书笔记 《设计模式之禅》读书笔记 微信公众平台开发 WordPress git IDE UML Matlab DSP 其他
CloudSimEx项目的目标是为 CloudSim 模拟器开发一组扩展。 证明值得的扩展稍后将与 CloudSim 合并。 笔记! 这些扩展在与 CloudSim 集成之前不受 CloudSim 团队的正式支持。 目前CloudSimEx 的特点: 网络会话建模...