在Java中无法抢占式地停止一个任务的执行,而是通过中断机制实现了一种协作式的方式来取消任务的执行。
设置取消标志
public class MyTask implements Runnable {
private final ArrayList<BigInteger> primes = new ArrayList<BigInteger>();
private volatile boolean cancelled;
@Override
public void run() {
while (!cancelled) {
...
}
}
public void cancel() {
cancelled = true;
}
}
中断线程的执行
public static boolean interrupted() {
return currentThread().isInterrupted(true);
}
public boolean isInterrupted() {
return isInterrupted(false);
}
private native boolean isInterrupted(boolean ClearInterrupted);
interrupt方法试图中断线程并设置中断状态标志变量为true;
isInterrupted方法测试线程是否已经中断,返回中断状态变量的值;
interrupted方法用于清除线程的中断状态,并返回之前的值,即如果当前线程是中断状态,则重新设置为false,并且返回true;
调用interrupt并不意味着必然停止目标线程工作,它紧紧传递了请求中断信息。
阻塞方法与线程的中断
大部分的阻塞方法都是响应中断的,即这些方法在线程中执行时如果发现线程被中断,会清除线程的中断状态,并抛出InterruptedException表示该方法的执行过程被从外部中断。响应中断的阻塞方法通常会在入口处先检查线程的中断状态,线程不是中断状态时,才会继续执行。
class PrimeProducer extends Thread{
private final BlockingQueue<BigInteger> queue;
private volatile boolean cancelled;
PrimeProducer(BlockingQueue<BigInteger> queue){
this.queue = queue;
}
public void run(){
BigInteger p = BigInteger.ONE;
while(!Thread.currentThread().isInterrupted(){
queue.put(p = p.nextProbablePrime());
}catch(InterruptedException consumed){
/*允许线程退出*/
}
}
public void cancel(){
interrupt();
}
}
中断响应
当调用可中断的阻塞方法时,有两种策略可用于处理InterruptedException
1、传递异常,从而使你的方法也成为可中断的阻塞方法。
2、恢复中断状态,从而使调用栈上中的上层代码能够对其进行处理。
只有实现了线程中断策略的代码才可以屏蔽中断请求,常规任务中不应该屏蔽中断请求。
通过Future实现取消
public class TimedRun {
private static final ExecutorService taskExec = Executors.newCachedThreadPool();
public static void timedRun(Runnable r,
long timeout, TimeUnit unit)
throws InterruptedException {
Future<?> task = taskExec.submit(r);
try {
task.get(timeout, unit);
} catch (TimeoutException e) {
// task will be cancelled below
} catch (ExecutionException e) {
// exception thrown in task; rethrow
throw launderThrowable(e.getCause());
} finally {
// Harmless if task already completed
task.cancel(true); // interrupt if running
}
}
}
Future接口有一个cancel方法,可以通过该方法取消任务的执行,cancel方法有一个boolean型的参数mayInterruptIfRunning。
如果设置为false,对于正在执行的任务只能等到任务执行完毕,无法中断;
如果设置为true,对于正在执行的任务可以试图中断任务的运行,这种情况通常只在与Executor框架配合时使用,因为执行任务的线程是由Executor创建的,Executor知道该如何中断执行任务的线程;