Java 并发编程之任务取消(五)

news/2024/11/29 7:50:12/

停止基于线程的服务

正确的封装原则是:除非拥有某个线程,否则不能对该线程进行操控。例如中断线程或修改线程的优先级等 。那么什么 是拥有某个线程呢,就是创建该线程的类,一般来说线程池是其工作线程的所有者,所以要修改线程的话,需要使用线程池来执行

线程的所有权是不能传递的。在ExecutorService中提供了shutdown和shutdownnow等 方法,同样,在其他拥有线程的服务中也应该提供类似的关闭机制。


对于持有线程 的服务,只要服务的存在时间 大于创建线程的方法 的存在时间,那么就应该提供生命周期方法


栗子:日志服务

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.Writer;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingDeque;public class LogWriter {private final BlockingQueue<String> queue;private final LoggerThread logger;private final int CAPACITY = 100;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) {super();this.writer = (PrintWriter) writer;}@Overridepublic void run() {// TODO Auto-generated method stubwhile (true) {try {writer.println(queue.take());} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();} finally {writer.close();}}}}public static void main(String[] args) {Writer writer = null;try {writer = new PrintWriter(new File("C://log.txt"));} catch (FileNotFoundException e) {// TODO Auto-generated catch blocke.printStackTrace();}LogWriter log = new LogWriter(writer);log.start();try {log.log("sdfds");log.log("sdfds");} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}
}
这是一个典型的多生产者一个消费者的设计方式,如果 消费者的速度小于生产者的速度,那么BlockingQueue会阻塞生产者,直到日志线程有能力处理新的日志消息

但是它不支持关闭,我们下面想办法把它关闭。第一种方法是将日志线程修改为当捕获到InterrupterException就退出 。也就是只关闭了消费者

这样有几个缺点,第一个就是会丢失将要处理的日志信息。第二,当其他线程调用log时被阻塞,因为日志消息队列是满的。因为这些线程将无法解除阻塞状态。但在这个示例中,生产者并不是一个专门的线程。因此要取消他们非常困难


第二种关闭logwriter的方法是:设置某个“已请求关闭”的标志,一收到关闭的时候就停止接收日志消息

	private boolean shutdownRequested = false;public void log(String msg) throws InterruptedException {if (!shutdownRequested) {queue.put(msg);} elsethrow new IllegalStateException("logger is shut down ");}public void shutdownlog() {shutdownRequested = true;}

这同样存在着阻塞问题,log是一种先判断再运行的程序,当他判断的时候是关闭之前,然后开始阻塞put。在这个过程中如果服务被关闭了,那么同样也是会发生问题的。


下面是一个终极解决办法

import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.io.Writer;
import java.rmi.server.LogStream;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingDeque;public class LogWriter {private final BlockingQueue<String> queue;private final LoggerThread logger;private final int CAPACITY = 100;private boolean isShutdown = false;private int reservations;public LogWriter(Writer writer) {this.queue = new LinkedBlockingDeque<String>(CAPACITY);this.logger = new LoggerThread(writer);}public void start() {logger.start();}public void stop() {synchronized (this) {isShutdown = true;}logger.interrupt();}public void log(String msg) throws InterruptedException {synchronized (this) {if (isShutdown) {throw new IllegalStateException("logger is shut down ");}++reservations;}queue.put(msg);}private class LoggerThread extends Thread {private final PrintWriter writer;public LoggerThread(Writer writer) {super();this.writer = (PrintWriter) writer;}@Overridepublic void run() {// TODO Auto-generated method stubwhile (true) {try {synchronized (this) {if (isShutdown && reservations == 0) {break;}}String msg = queue.take();synchronized (LogWriter.this) {--reservations;}writer.println(msg);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();} finally {writer.close();}}}}public static void main(String[] args) {Writer writer = null;try {writer = new PrintWriter(new File("C://log.txt"));} catch (FileNotFoundException e) {// TODO Auto-generated catch blocke.printStackTrace();}final LogWriter log = new LogWriter(writer);log.start();try {log.log("sdfds");log.log("sdfds");} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}
}
这次把logwriter改写成为原子性的操作。消除了在判断后阻塞的问题。并且引入了一个计数器。确保它可以把已经put的日志消费完,同时不再接收任何日志。这样当消费完毕的时候才会关闭日志服务。


http://www.ppmy.cn/news/338373.html

相关文章

12eqfsdfds

public void aaa(){System.out.println("hello"); }

ces

#include<iostream> using namespace std; int main() { int s,f; cin>>s>>f; if (((s>8) && (s<16))||((s17) && (f00))) { cout<<"YES"; } else { cout<<"NO"; } }

Ubuntu下sqlite3的安装及使用

转载Ubuntu下sqlite3的安装及使用 Sqlite是一款轻型的数据库&#xff0c;实现了多数SQL-92标准&#xff0c;包括事务&#xff08;原子性&#xff0c;一致性&#xff0c;隔离性和持久性 ACID&#xff09;&#xff0c;触发器与多数复杂查询。对于一个移动手持设备的应用开发者&am…

【Android】通过CustomTarget释放Glide在ViewHolder 所占用的图片内存,避免内存泄漏

在上述代码中&#xff0c;Glide 加载图片所占用的内存是通过 CustomTarget 的 onResourceReady 方法返回的 Drawable 对象来表示的。因此&#xff0c;在 onViewRecycled 方法中&#xff0c;我们可以通过将 Drawable 对象的引用置为 null 来释放所占用的内存。 具体来说&#x…

共享电动车APP开发

当前用户的出行主要是为了日常的工作或者是节假日的一些休闲娱乐活动&#xff0c;所以说抓住 这一类用户的需求&#xff0c;能够有效发展平台的整体用户粘性;要知道用户的出行图的就是一个 便捷&#xff0c;虽然说日常生活中有公交地铁这样的公共交通设备&#xff0c;但是这样…

电动车防盗管理系统

第一章 引言. 第一章 引言 1.1 文档说明 此文档旨在解释说明电动车防盗管理系统的原理与构成、系统功能和相关案例。未经授权&#xff0c;不得以任何形式转载篡改&#xff0c;奔骝科技不对篡改后的文档负责。 1.2 读者对象集成商销售 依据本解决方案&#xff0c;集成商销售可…

远程控制和原理和实践

按理来说&#xff0c;本人不该发表此类专业的文章&#xff0c;但是从鄙人的开发经历出发&#xff0c;让本人斗胆在此对远控软件做一些论述&#xff0c;谈论一点自己的认识。 程序工程代码地址&#xff1a;点击此处下载。 程序分为两个部分&#xff0c;控制端和被控端&#xf…

戴尔笔记本vostro 5402高通无线网卡出现wlan找不到WI-FI网络诊断说无线适配器或接入点问题

环景&#xff1a; 戴尔笔记本vostro 5402 windows 10家庭中文版20H 问题描述&#xff1a; 笔记本高通QCA61x4A 802.11AC无线网卡,出现wlan找不到WI-FI网络&#xff0c;不能上网&#xff0c;禁用启用网卡才行&#xff0c;隔一段时间重复出现。网卡诊断说无线适配器或接入点问…