Java没有提供任何机制来安全地终止线程。提供了中断(一种协作机制),能够使一个线程终止另一个线程的当前工作。 行为良好的软件:能很完善地处理失败、关闭和取消等过程。 一个可取消的任务必须拥有取消策略,在这个策略中将详细地定义取消操作的“How”、“When”以及“What”,即其他代码如何(How)请求取消该任务,任务在何时(When)检查是否已经请求了取消,以及在响应取消请求时应该执行哪些(What)操作。
如果外部代码能在某个操作正常完成之前将其置入“完成”状态,那么这个操作就可以称为可取消的(Cancellable)。
取消操作原因:
用户请求取消有时间限制的操作应用程序事件错误关闭在Java中没有一种安全的抢占式方法来停止线程,因此也就没有安全的抢占式方法来停止任务。
测试代码:
import java.math.BigInteger; import java.util.List; import static java.util.concurrent.TimeUnit.SECONDS; public class PrimeGeneratorTest implements Runnable { public List<BigInteger> aSecondOfPrimes() throws InterruptedException { PrimeGenerator generator = new PrimeGenerator(); new Thread(generator).start(); try { SECONDS.sleep(1); } finally { generator.cancel(); } return generator.get(); } @Override public void run() { try { System.out.println(aSecondOfPrimes()); } catch (InterruptedException e) { e.printStackTrace(); } } public static void main(String[] args) { new Thread(new PrimeGeneratorTest()).start(); } }线程中断是一种协作机制,线程可以通过这种机制来通知另一个线程,告诉它在合适的或者可能的情况下停止当前工作,并转而执行其他的工作。 在Java中如果在取消之外的其他操作中使用中断,那么是不合适的,并且很难支撑起更大的应用。 每个线程都有一个boolean类型的中断状态。当中断线程时,这个线程的中断状态将被设置为true。
public class Thread{ public void interrupt(){...} public boolean isInterrupted(){...} public static boolean interrupted(){...} }如上代码: interrupt( )能中断目标线程; isInterrupted( )能返回目标线程的中断状态; interrupted( )将清除当前的中断状态(中断标记重置为false),并返回它之前的值,这是清除中断状态的唯一方法。
调用interrupt( )并不意味着立即停止目标线程正在进行的工作,而只是传递了请求中断的消息。它并不会真正地中断一个正在运行的线程,而只是发出中断请求,然后由线程在下一个合适的时刻中断自己。
如果线程处于被阻塞状态(例如处于sleep, wait, join 等状态),那么线程将立即退出被阻塞状态,并抛出一个InterruptedException异常。可见,给目标线程发送中断还能够产生唤醒目标线程的效果。
使用interrupted( )时,它会清除当前线程的中断状态。如果在调用interrupted( )时返回了true,那么除非你想屏蔽这个中断,否则必须对它进行处理——可以抛出InterruptedException,或者通过再次调用interrupt( )来恢复中断状态。依照惯例,凡是抛出InterruptedException异常方法,通常会在其抛出该异常之前将当前线程的中断标记重置为false。
抛出InterruptedException异常的同时它会将线程中断标志置为false。
public class InterrupTest implements Runnable { @Override public void run() { try { while (true) { Boolean a = Thread.currentThread().isInterrupted(); System.out.println("in run() - about to sleep for 20 seconds-------" + a); Thread.sleep(20000); System.out.println("in run() - wake up"); } } catch (InterruptedException e) { //如果不加上这一句,那么c,d将会都是false,因为在捕捉到InterruptedException异常的时候就会自动的中断标志置为了false Thread.currentThread().interrupt(); Boolean c = Thread.interrupted(); Boolean d = Thread.interrupted(); System.out.println("c = " + c); System.out.println("d = " + d); } } public static void main(String[] args) { InterrupTest si = new InterrupTest(); Thread t = new Thread(si); t.start(); //主线程休眠2秒,从而确保刚才启动的线程有机会执行一段时间 try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("in main() - interrupting other thread"); //中断线程t t.interrupt(); System.out.println("in main() - leaving"); } }output:
in run() - about to sleep for 20 seconds-------false in main() - interrupting other thread in main() - leaving c = true d = false上述代码来源。
import java.util.concurrent.BlockingQueue; public class TaskRunnable implements Runnable { BlockingQueue<Task> queue; @Override public void run() { try{ processTask(queue.take()); }catch(InterruptedException e){ // 恢复被中断的状态 Thread.currentThread().interrupt(); } } }通常,中断是实现取消的最合理方式。
如果一个线程由于执行同步的Socket I/O或者等待获得内置锁而阻塞,那么中断请求只能设置线程的中断状态,除此之外没有其他的任何作用。对于由于执行不可中断操作而被阻塞的线程,可以使用类似于中断的手段来停止这些线程,但这要求我们必须知道线程阻塞的原因。
只有通过execute提交的任务,才能将它抛出的异常交给未捕获异常处理器,而通过submit提交的任务,无论是抛出的未检查异常还是已检查异常,都将被认为是任务返回状态的一部分。