`
dyllove98
  • 浏览: 1380750 次
  • 性别: Icon_minigender_1
  • 来自: 济南
博客专栏
73a48ce3-d397-3b94-9f5d-49eb2ab017ab
Eclipse Rcp/R...
浏览量:38265
4322ac12-0ba9-3ac3-a3cf-b2f587fdfd3f
项目管理checkList...
浏览量:78567
4fb6ad91-52a6-307a-9e4f-816b4a7ce416
哲理故事与管理之道
浏览量:131695
社区版块
存档分类
最新评论

处理不可中断阻塞

 
阅读更多

在java库中,许多可阻塞的方法都是通过提前返回或者抛出InterruptedException来响应中断请求的,从而使开发人员更容易构建出能响应取消请求的任务。然而并非所有的可阻塞方法或者阻塞机制都能响应中断;如果一个线程由于执行同步的Socket I/O或者等待获得内置锁而阻塞,那么中断请求只能设置线程的中断状态,除此之外没有其他任何作用。

以下是不可中断阻塞的情况:

  1. java.io包中的同步Socket I/O
  2. java.io包中的同步I/O
  3. Selector的异步I/O
  4. 获取某个锁

下面是停止不可中断阻塞的方法,这篇文章很好地解释了我上一篇文章(使用Future停止超时任务)中提到的问题。

--------------------------------------------------------------------------------------------------------------------

关键步骤就是重写原来中断线程或者取消任务的方法,在方法里面加入自己的取消操作,比如关闭数据流,关闭套接字等,然后再调用父类的中断方法,这样就可以既关闭了阻塞的任务,又中断了线程。

--------------------------------------------------------------------------------------------------------------------

 下面那是具体的代码:
(CancellableTask.java)

 1 /**
 2  * 处理不可中断阻塞任务的接口
 3  * @author hongjie
 4  */
 5 public interface CancellableTask<V> extends Callable<V> {
 6     /**取消不可中断的阻塞任务*/
 7     public void cancel();
 8     /**创建自定义的FutureTask*/
 9     public RunnableFuture<V> newTask();
10 }

 (CancellableLoadTask.java)

 1 /**
 2  * 可中断的下载任务
 3  * @author hongjie
 4  */
 5 public class CancellableLoadTask<V> implements CancellableTask<V> {
 6     private InputStream input;
 7     private OutputStream output;
 8     private String filename;
 9 
10     public CancellableLoadTask(String filename) {
11         this.filename = filename;
12     }
13 
14     /**转存文件方法*/
15     public synchronized void download() throws FileNotFoundException,
16             IOException {
17         File file = new File(filename);
18         File saveFile = null;
19         String[] names = filename.split("/");
20         String saveName = names[names.length - 1];
21         saveFile = new File("tmp/" + saveName);
22 //        System.out.println(saveFile.getAbsolutePath());
23         input = new FileInputStream(file);
24         output = new FileOutputStream(saveFile);
25 
26         // 进行转存
27         int len = 0;
28         byte[] buffer = new byte[1024];
29         while (-1 != (len = input.read(buffer, 0, buffer.length))) {
30             output.write(buffer, 0, len);
31         }
32 
33         input.close();
34         output.close();
35     }
36 
37     /**重写的方法,关闭阻塞的输入输出流*/
38     @Override
39     public void cancel() {
40         try {
41             if (null != input)
42                 input.close();
43             if (null != output)
44                 output.close();
45         } catch (IOException e) {
46             e.printStackTrace();
47         }
48     }
49 
50     @Override
51     public RunnableFuture<V> newTask() {
52         //重写FutureTask的cancel()方法,首先调用自定义的 cancel方法,停掉阻塞的任务
53         return new FutureTask<V>(this) {
54             @Override
55             public boolean cancel(boolean mayInterruptIfRunning) {
56                 CancellableLoadTask.this.cancel();
57                 return super.cancel(mayInterruptIfRunning);
58             }
59         };
60     }
61 
62     @Override
63     public V call() throws Exception {
64         download();
65         return null;
66     }
67 }

(DownloadExecutor.java)

 1 /**
 2  * 下载任务的线程池
 3  * @author hongjie
 4  *
 5  */
 6 public class DownloadExecutor extends ThreadPoolExecutor {
 7     
 8     public DownloadExecutor(int corePoolSize, int maximumPoolSize,
 9             long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {
10         super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
11     }
12 
13     /**重写newTaskFor()方法,返回自定义的Future*/
14     @Override
15     protected <V> RunnableFuture<V> newTaskFor(Callable<V> callable) {
16         if(callable instanceof CancellableLoadTask)
17             return ((CancellableLoadTask<V>)callable).newTask();
18         return super.newTaskFor(callable);
19     }
20 }

DownloadExecutor继承了ThreadPoolExecutor方法,并重写了newTaskFor()方法,因为当调用submit()方法的时候会先调用newTaskFor()方法,然后再执行execute();下面是父类的submit()方法

 1     /**
 2      * @throws RejectedExecutionException {@inheritDoc}
 3      * @throws NullPointerException       {@inheritDoc}
 4      */
 5     public <T> Future<T> submit(Callable<T> task) {
 6         if (task == null) throw new NullPointerException();
 7         RunnableFuture<T> ftask = newTaskFor(task);
 8         execute(ftask);
 9         return ftask;
10     }

因此当调用submit方法的时候会先调用我们重写的newTaskFor()方法,看到DownloadExecutor.java中的16~18行,返回的是CancellableLoadTask.java中自定义的FutureTask,因此会调用我们重写的cancel方法,先停掉阻塞的下载任务,然后中断线程。

(StopLoadTest.java: 测试)

 1 public class StopLoadTest {
 2     public static void main(String[] args) {
 3         CancellableLoadTask<?> loadTask = new CancellableLoadTask("G:/Games/5211install.exe");
 4         //设定线程池中的容量为1,活动时间为2秒
 5         DownloadExecutor executor = new DownloadExecutor(1, 1, 2, TimeUnit.SECONDS, new ArrayBlockingQueue(10));
 6         Future<?> future = executor.submit(loadTask);
 7         try {
 8             //设置下载超时为200毫秒
 9             future.get(200, TimeUnit.MILLISECONDS);
10         } catch (InterruptedException e) {
11             System.out.println("下载任务已经取消");
12         } catch (ExecutionException e) {
13             System.out.println("下载中发生错误,请重新下载");
14         } catch (TimeoutException e) {
15             System.out.println("下载超时,请更换下载点");
16         }
17         finally{
18             future.cancel(true);
19         }
20     }
21 }

 

程序运行结果:
源文件:

下载超时:

目标文件:

 

 

分享到:
评论

相关推荐

    AVR单片机UART中断发送

    AVR单片机UART中断发送 AVR单片机UART以查询、中断方式发送数据 用于高效收发数据,收发均不阻塞CPU运行。 函数口中包含了两种中断发送方式,可选择 缓冲空中断 || 发送结束中断

    51非阻塞式串口通信

    本程序适用于学习交流,对读入一个字节(不带回车)读入一个字符串带回车,发送字符串函数测试成功。 本程序可以连续收发字符...所以本程序使用中断,非堵塞方式发送接受,缺点是占用一些内存,缓冲区大小可自由配置。

    51单片机外部中断的两种触发方式资料下载

    51单片机的外部中断有两种触发方式可选:电平触发和边沿触发。选择电平触发时,单片机在每个机器周期检查中断源口线...同样,当CPU在执行不可被中断的指令(如RETI)时,产生的电平触发中断如果时间太短,也得不到执行。

    51单片机外部中断触发方式

    51单片机的外部中断有两种触发方式可选:电平触发和边沿触发。选择电平触发时,单片机在每个机器周期检查中断源口线,检测到低电平,即置位中断请求标志,向CPU请求中断。选择边沿触发方式时,单片机在上一个机器...

    代码复现:基于主从博弈的主动配电网阻塞管理 采用双层模型进行求解 上层决策边际报价,下层求解出清电价和运行方案反馈到上层,反复迭

    场景1考虑可中断负荷和可调节负荷以及电压约束 场景2考虑电动汽车和储能以及电压约束 场景3综合场景12并增加线路传输容量约束 场景4也就是无阻塞管理模式,在场景3基础上不考虑电压和传输容量约束 在IEEE 33节点算例...

    linux驱动相关面试题目

    1、字符型驱动设备你是怎么创建设备文件的,...第二:中断服务程序中不能有阻塞操作。为什么?大家可以讨论。 第三:中断服务程序注意返回值,要用操作系统定义的宏做为返回值,而不是自 己定义的 OK,FAIL 之类的。

    最新操作系统试题及答案.doc

    由中断处理程序唤醒阻塞进程。(3)新数据尚未到 达。相互合作的进程中,消费者进程阻塞等待数据到达;生产者进程在数据到达后唤醒 阻塞进程。(4)无新工作可做。系统进程没有新工作可做时阻塞等待;当有进程发出请...

    WS2812Serial:WS2812无阻塞LED库

    WS2812Serial-非阻塞WS2812B / NeoPixel LED库与相似,该库允许您使用WS2811,WS2812,WS2812B / NeoPixel LED... 也用于传输数据,从而使该端口不可用于其他用途。支持的引脚和串行端口港口Teensy LC 少女3.2 少女3.5

    进程PV操作详细讲解

     P操作和V操作是不可中断的程序段,称为原语。PV原语及信号量的概念都是由荷兰科学家E.W.Dijkstra提出的。信号量sem是一整数,sem大于等于零时代表可供并发进程使用的资源实体数,但sem小于零时则表示正在等待使用...

    2操作系统简答题.doc

    由中断处理程序 唤醒阻塞进程。 (3)新数据尚未到达。相互合作的进程中,消费者进程阻塞等待数据到达;生产者进程 在数据到达后唤醒阻塞进程。 (4)无新工作可做。系统进程没有新工作可做时阻塞等待;当有进程发出...

    Java并发编程实战

    7.1.6 处理不可中断的阻塞121 7.1.7 采用newTaskFor来封装非标准的取消122 7.2 停止基于线程的服务124 7.2.1 示例:日志服务124 7.2.2 关闭ExecutorService127 7.2.3 “毒丸”对象128 7.2.4 示例:只执行一次...

    Java 并发编程实战

    3.4.2 示例:使用Volatile类型来发布不可变对象 3.5 安全发布 3.5.1 不正确的发布:正确的对象被破坏 3.5.2 不可变对象与初始化安全性 3.5.3 安全发布的常用模式 3.5.4 事实不可变对象 3.5.5 可变对象 3.5.6 ...

    Java 7并发编程实战手册

    1.9 线程中不可控异常的处理 24 1.10 线程局部变量的使用 26 1.11 线程的分组 30 1.12 线程组中不可控异常的处理 34 1.13 使用工厂类创建线程 37 第2章 线程同步基础 41 2.1 简介 41 2.2 使用...

    JAVA并发编程实践_中文版(1-16章全)_1/4

    3.4 不可变性 3.5 安全发布 . 第4章 组合对象 4.1 设计线程安全的类 4.2 实例限制 4.3 委托线程安全 4.4 向已有的线程安全类添加功能 4.5 同步策略的文档化 第5章 构建块 5.1 同步容器 5.2 发容器 5.3 阻塞队列和...

    Java并发编程part2

    3.4 不可变性 3.5 安全发布 . 第4章 组合对象 4.1 设计线程安全的类 4.2 实例限制 4.3 委托线程安全 4.4 向已有的线程安全类添加功能 4.5 同步策略的文档化 第5章 构建块 5.1 同步容器 5.2 发容器 5.3 阻塞队列和...

    Java并发编程实践part1

    3.4 不可变性 3.5 安全发布 . 第4章 组合对象 4.1 设计线程安全的类 4.2 实例限制 4.3 委托线程安全 4.4 向已有的线程安全类添加功能 4.5 同步策略的文档化 第5章 构建块 5.1 同步容器 5.2 发容器 5.3 阻塞队列和...

    春季操作系统原理(含参考答案) A卷.doc

    3.在一单处理机中,若有3个用户进程,在非管态的某一时刻,处于阻塞状态的用户进程最多有( B )个。 A.1 B.2 C.3 D.0 4. 就一个进程的生命周期来说,该不可能发生的状态变迁是( D ) A. 就绪变执行 B. 执行变阻塞...

    Java并发编程(学习笔记).xmind

    一组不可分割的操作 竞态条件 基于一种可能失效的观察结果来做出判断或执行某个计算 复合操作:执行复合操作期间,要持有锁 锁的作用 加锁机制、用锁保护状态、实现共享访问 锁的不恰当...

    操作系统重点

    死锁的4个必要条件:互斥条件、不可抢占条件、占有且申请条件、循环等待条件。  【了解】  1.Linux进程结构,见教材41页图。  2.进程间的3种高级通信:共享内存、管道文件和消息传递。 第3章 处理机调度  考核...

Global site tag (gtag.js) - Google Analytics