任务和线程的启动很容易。在大多数时候,咱们都会让它们运行直到结束,或者让它们自行中止。然而,有时候咱们但愿提早结束任务或线程,或许是由于用户取消了操做,或者应用程序须要被快速关闭。 要使任务和线程能安仝、快速、可靠地中止下来,并非一件容易的事。Java的Thread类为咱们提供了stop(),suspend()等中止挂起线程的方法,可是因为安全问题目前都已被弃用。Java并无提供一种安全的抢占式方法来中止线程,但它提供了中断(Interruption),这是一种协做机制,采用协做式的方式使一个线程终止另外一个线程的当前工做。 这种协做式的方法是必要的,咱们不多但愿某个任务、线程或服务当即中止,由于这种当即中止会使共享的数据结构处于不一致的状态。相反,在编写任务和服务时可使用一种协做的方式:当须要中止时,它们首先会清除当前正在执行的工做,而后再结束。这提供了更好的灵活性,由于任务自己的代码比发出取消请求的代码更清楚如何执行清除工做。 生命周期结束(End-of-Lifecycle)的问题会使任务、服务以及程序的设计和实现等过程变得复杂,而这个在程序设计中很是重要的要素却常常被忽略。一个在行为良好的软件与勉强运行的软件之间的最主要区别就是,行为良好的软件能很完善地处理失败、关闭和取消等过程。java
如何设计一种协做机制,让线程能够安全的中断呢?咱们能够设置一个取消标志,在工做线程会被中断的地方去检查这个标志,当检查到这个中断标志被设置为已取消时,工做线程便开始作取消工做。编程
1 public class CancelableThread implements Runnable { 2 3 //线程取消标志,volatile修饰,保证内存可见性 4 private volatile boolean isCanceled = false; 5 6 @Override 7 public void run() { 8 while (!isCanceled) {//在工做线程中轮询检测这个取消标志 9 System.out.println("The current thread is doing something..."); 10 System.out.println(Thread.currentThread().getName() + " cancel flag is " + isCanceled); 11 } 12 //当取消标志被设置为true,执行如下代码,能够作一些取消工做 13 System.out.println(Thread.currentThread().getName() + "The current thread Has been cancelled"); 14 } 15 16 private void cancel() { 17 isCanceled = true; 18 } 19 }
1 public class Main { 2 public static void main(String[] args) throws Exception { 3 4 CancelableThread cancelableThread = new CancelableThread(); 5 new Thread(cancelableThread).start(); 6 try { 7 Thread.sleep(1); 8 } finally { 9 //设置标志位为true,中断线程 10 cancelableThread.cancel(); 11 } 12 } 13 }
打印结果:安全
Thread-0 cancel flag is false The current thread is doing something... Thread-0 cancel flag is false The current thread is doing something... Thread-0 cancel flag is false The current thread is doing something... Thread-0 cancel flag is false The current thread is doing something... Thread-0 cancel flag is true Thread-0The current thread Has been cancelled
其实Thread类为咱们提供了三个与线程中断相关的方法,来实现上述机制。这三个方法分别是:数据结构
public void interrupt() { //... 省略相关代码 interrupt0(); // Just to set the interrupt flag //... 省略相关代码 }
public static boolean interrupted() { return currentThread().isInterrupted(true); }
public boolean isInterrupted() { return isInterrupted(false); }
查看源码发现,静态的interrupted()和isInterrupted()方法都是调用的 private native boolean isInterrupted(boolean ClearInterrupted); 根据传入的ClearInterrupted的值,来判断是否要清除中断标志位。并发
1 public class InterruptTest { 2 3 4 static class InnerThread extends Thread{ 5 6 7 @Override 8 public void run() { 9 while(!isInterrupted()){ 10 System.out.println(Thread.currentThread().getName()+" cancle flag is "+isInterrupted()); 11 try { 12 13 Thread.sleep(100); 14 15 }catch (InterruptedException e){ 16 e.printStackTrace(); 17 //抛出InterruptedException,中断标志位被清除,再次调用 interrupt(); 18 interrupt(); 19 } 20 } 21 System.out.println(Thread.currentThread().getName()+" cancle flag is "+isInterrupted()); 22 23 } 24 } 25 26 27 public static void main(String[] args) { 28 InnerThread innerThread = new InnerThread(); 29 innerThread.start(); 30 try { 31 32 Thread.sleep(1000); 33 34 }catch (InterruptedException e){ 35 e.printStackTrace(); 36 } 37 innerThread.interrupt(); 38 // InnerThread innerThread2 = new InnerThread(); 39 // innerThread2.start(); 40 // innerThread2.interrupt(); 41 } 42 }
打印结果:ide
Thread-0 cancle flag is false Thread-0 cancle flag is false Thread-0 cancle flag is false Thread-0 cancle flag is false Thread-0 cancle flag is false Thread-0 cancle flag is false Thread-0 cancle flag is false Thread-0 cancle flag is false Thread-0 cancle flag is false Thread-0 cancle flag is false java.lang.InterruptedException: sleep interrupted at java.lang.Thread.sleep(Native Method) at InterruptTest$InnerThread.run(InterruptTest.java:13) Thread-0 cancle flag is true
参考资料:《Java并发编程实战》