任务的取消与关闭(java并发编程实践读书笔记六)

  • 可取消的任务:外部代码能够在任务自然完成之前,把他更改为完成状态。
  • 取消策略 :一个可取消的任务必须拥有取消策略 
    • 策略主要说明
      • 其他代码如何取消该任务。例:在任务中提供public的cancel方法
      • 任务本身在什么时候检查取消的请求是否到达
      • 任务响应取消请求要执行哪些动作
    • 一种取消策略
      • 在任务(线程)中定义一个取消标志 volatile boolean cancelled ,使用volatile域保证其可见性
      • 在任务(线程)中定义一个方法 public void cancel()用来设置变量cancelled的值
      • 在run方法的某个方便取消任务的位置检查该变量 如果变量被其他线程修改 则在方便的时候取消任务
      • 缺点:当检查取消标志之前存在阻塞的方法时,可能永远都不会检查到这个标志,cancel方法也就变得没有意义了
      • 代码:
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
public class PrimeGenerator implements Runnable {
    private final List primes = new ArrayList();
    private volatile boolean cancelled = false;
    @Override
    public void run() {
        BigInteger p = BigInteger.ONE;
        while(!cancelled){
            p=p.nextProbablePrime();
            synchronized(this){
                primes.add(p);
            }
        }
    }
    public void cancel(){
        cancelled=true;
    }
    public synchronized List get(){
        return new ArrayList(primes);
    }
}
这个线程用来产生素数,并不断的放到一个List中,其他线程可以随时从线程中得到已经产生的素数列表,也可以随时调用cancel方法来结束线程。
使用中断来取消任务:
  • 每一个线程都有一个boolean类型的中断状态,在中断的时候为true
  • Thread还包含了中断状态相关的方法
public class Thread{
    public void interrupt(){...}
    public boolean isInterrupted(){...}
    public static boolean interrupted(){...}
 
}
interrupt方法中断目标线程
isInterrupted方法返回目标线程当前的中断状态
静态的interrupted方法清除当前线程的中断状态,并返回它之前的值
 
1.阻塞的库函数(Thread.sleep,Object.wait等)会监视线程的中断状态,并提前返回。它们对中断的响应为:清除中断状态,抛出InterruptedException
try{
    Thread.sleep(3000);
}catch(InterruptedException e){
    /*允许线程退出*/
}
2.当线程没有处在阻塞状态时发生中断,会设置线程的中断状态,然后等待被中断的线程内部自己检查是否发生了中断。如果没有检查,也没有触发InterruptedException,中断状态就一直这么保持着。
while(!Thread.currentThread().isInterrupted()){ //检查中断状态
...
}
 
通过以上两点,我们可以认识到:中断并不会真正的中断一个线程,他仅仅是发出了一个 中断请求,线程收到请求后可以选择处理,也可以选择不处理。系统的有些库函数(阻塞的方法)会关注这个状态,并在接到中断之后抛出异常
注意:中断请求最好不要隐藏。静态的interrupted方法会清除中断状态,因此,如果interrupted方法返回true,可以抛出异常或者是再次调用interrupt方法设置中断状态
中断策略
     决定如何应对中断请求:尽可能迅速退出,如果需要的话进行清理,可能的话通知其他的实体本线程退出。
在任务代码中应该小心的保存中断状态,因为线程不是隶属于该任务的,对于线程池来讲,一个线程上可能会运行多个任务,任务中小心的保存中断状态,线程的所有者才能最终有所作用。
 
对于大多数可阻塞的库函数而言,他们之所以仅仅抛出了InterruptedException,是因为他们知道自己没有权限结束一个本来就不属于他们的线程,所以抛出异常,传给上层代码进一步的决定要采取的策略。在捕获了InterruptedException之后,要恢复中断的状态
Thread.currentThread().interrupt();
 
响应中断
     在调用可中断的阻塞函数时 的策略
    1.传递异常,这时你的方法也成为可中断的阻塞方法了
        public void sleep(int i) throws  InterruptedException{
            Thread.sleep(i);
        }
    2.保存中断状态,上层调用者对其处理
        在catch语句中回复中断状态 --Thread.currentThread().interrupt()
    3.实现含有阻塞方法的不可取消任务
        一般来说,含有阻塞方法的任务均可响应中断,可以通过特殊的处理,使任务在退出前保存中断
        定义一个自有的中断状态,当阻塞的方法响应中断抛出异常时,catch中把自有的中断状态设置为ture,然后在finally块中检查这个自有的中断状态,然后设置Thread 的中断状态。这样只有在任务结束退出的时候才设置的Thread的中断。实现了不可取消的任务。
 
 这里可能是最后一篇,我自己买了本书,以后笔记就直接写在书上了,不再整理发布了
 

你可能感兴趣的:(多线程,任务,读书,编程,java,thread,import)