java 并发编程实战 第四天

来源:互联网 发布:网络变压器 代工 编辑:程序博客网 时间:2024/06/05 02:40

第七章 取消与关闭

参考 http://blog.csdn.net/ICTCamera/article/details/12946459
看多了文章就开始感觉自己写的博客就像shi 一样...可能写的太少了,这个确实的.不知道以后回头看会是怎么一个感觉?

一条线程动起来很简单,start就ok了.但是如果要安全的,快速的停止,可能就不是简单的事情了.
这里会简单的介绍了一下线程的取消还有关闭等策略.

1.任务取消.

主要包括以下几大类:

  • l  用户请求取消
  • l  有时间限制的操作,超时的时候取消
  • l  应用程序事件,例如一组任务中一个任务完成,其他任务取消
  • l  错误,任务执行中发生错误(IO异常等)
  • l  关闭,关闭一个程序或服务

Java中取消可以通过程序设置取消标识(变量),然后根据执行任务前判断变量来达到取消,但是这种设计在实际应用基本上不使用,因为阻塞的任务处理可能是取消严重滞后或者永远查不到取消标识而永远不会结束。实际中一般通过Java的中断机制来实现任务的关闭和取消。中断是实现取消和关闭的最合理方式


在java 中没有一种安全的抢占式方法来停止线程,只有一些协作机制来取消任务.
下面是使用volatile状态变量  来取消正在运行的线程.
private final List<BigInteger> primes = new ArrayList<BigInteger>();
private volatile boolean cancelled ;
public void run() {
BigInteger p = BigInteger.ONE;
while(!cancelled){
p = p.nextProbablePrime();
synchronized (this) {
primes.add(p);
}
}catch{
            ...
        }
}
public void cancel(){cancelled = true;}
但是上面会出现一个问题. 上面会存在延迟取消,还有可能不能正常得被调用cancel() 方法导致线程无法正常退出.
这是一种不可靠的取消方式.如果使用上面的方法 任务调用了一个阻塞方法, 例如: BlockingQueue.put,那么任务就永远不会去检查取消的标致,就永远不会退出.

private final BlockingQueue<BigInteger> queue;
private volatile boolean cancelled = false;
 
public void run (){
try{
BigInteger p = BigInteger.ONE;
//当任务被阻塞在put 中的时候但是却不会去检查这个标志,因为这个时候take 方法已经挂了!,put 方法会一直保持着.
while(!cancelled){
queuq.put(p = ....);
}
}
}


2. 中断

Java没有提供一种安全、直接的方法来停止某个线程,但是Java提供了中断(interrupt)机制。如果我们对Java中断没有一个全面的了解,可能会误以为被中断的线程将立马退出运行,但事实并非如此。

下面是Thread 提供的中断方法
调用interrupt 并不意味着立即停止目标线程正在进行的工作,而只是传递了请求中断信息. 有点像我老妈叫我吃饭,但是立刻吃还是等会吃还是要 根据你本身
public class Thread{
//中断线程.由中断调用者调用,调用该方法会将被中断线程的中断状态设置为true
public void interrupt(){.....}
//测试线程是否已经中断.线程的中断状态 不受该方法的影响.
public boolean isInterrupted(){...}
//测试当前线程是否已经中.线程的中断状态 (中断标识)由该方法清除.如果连续两次调用该方法,则第二次调用将返回 false
public static boolean interrupt(){...}
}

上面的代码使用了Thread 类中自带的中断就能解决不能正常关闭线程的问题.
private final BlockingQueue<BigInteger> queue;
public void run (){
try{
BigInteger p = BigInteger.ONE;
//这样就能后顺利的将其中断
while(!Thread.currentThread().isInterrupted()){
queuq.put(p = ....);
}
}catch(...){
.... 
}
}

3响应中断.

当一些阻塞函数被中断的时候例如: Thread.sleep() 或者 BlockingQueue.put 等 会抛出 InterruptedException 
处理方式:
  1. 传递异常,直接往上throws   
        ps>>>>throws是用来声明一个方法可能抛出的所有异常信息 throw则是指抛出的一个具体的异常类型
  2. 恢复中断状态..
中断策略.中断或者取消操作应该都有自己的处理策略,不能直接catch 到Exception还是什么都不管.不能够屏蔽掉中断的请求.
对于一些不支持取消中断阻塞方法的操作.应该在退出前恢复中断.而不是等到catch 到Exception之后才中断.
public void method....{
boolean interrupted = false;
try{
while(true){
try{
return queue.take();
}catch(InterruptedException e){
interrupted = true;
}
}
} finally{
if(interrupted) Thread.currentThread().interrupt();
}
}


4.通过Future 来实现取消.

Future 拥有一个cancel 方法.能够取消任务, 
//如果为true ,并且任务正在运行,那么久直接中断.
//如果是false若任务没有启动就不中断它. ps:这个用于不处理中断的任务中.
public boolean cancel(boolean mayInterruptIfRunning) {
  • // TODO Auto-generated method stub
  • return false;
    }

  • 5.处理不可中断的阻塞.

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

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


    6.停止基于线程的服务.

    ExecutorService 中提供了shutdown 和shutdownNow 方法.
    shutdownNow 方法首先关闭当前正在执行的任务,然后返回所有尚未启动的任务清单.
    这两种关闭方式差别在于一个注重安全性,会等待所有任务完成才关闭, 相反另外一个就是速度快,能够快速关闭,但是安全性低.



    0 0
    原创粉丝点击