对于线程来说,执行完特定任务后,自然的结束,当然是当好的选择。 但实际有很多情况,在任务没有执行完时,要求停止或者退出。 安全的停止一个正在运行的线程,也不是一件容易的事。
错误的关闭方法 已废弃的Thread.stop()
原因:
该方法天生是不安全的。使用thread.stop()停止一个线程,导致释放(解锁)所有该线程已经锁定的监视器(因沿堆栈向上传播的未检查异常ThreadDeath而解锁)。如果之前受这些监视器保护的任何对象处于不一致状态,则不一致状态的对象(受损对象)将对其他线程可见,这可能导致任意的行为。
无法直接停止的interrupt Thread.interrupt() 如代码示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public static void example() throws Exception { Thread th = new Thread(new Runnable() { @Override public void run() { System .out .println("enter running..."); int i=0 ; while (i++ <Integer .MAX_VALUE -1 ) { System .out .println(i); } System .out .println("end of run"); } }); th.start (); System .out .println("main thread sleep"); Thread.sleep(1000 ); System .out .println("main thread call interrupt"); th.interrupt(); System .out .println("over"); }public static void main(String[] args) throws Exception { example(); }
代码中会执行完循环再停止。
虽然调用interrupt方法,但线程中没有处理。
能正常工作的方法 普通循环业务 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public static void example2() throws Exception { Thread th = new Thread(new Runnable() { @Override public void run() { System .out .println("enter running..."); int i=0 ; while (i++ <Integer .MAX_VALUE -1 && !Thread.interrupted()) { System .out .println(i); } System .out .println("end of run"); } }); th.start (); System .out .println("main thread sleep"); Thread.sleep(1000 ); System .out .println("main thread call interrupt"); th.interrupt(); System .out .println("over"); }public static void main(String[] args) throws Exception { example2(); }
这里在业务逻辑中判断有没有打断。没有,就继续,有就停下来。
sleep和wait等情况 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 public static void example3 () throws Exception { Thread th = new Thread(new Runnable() { @Override public void run () { System.out .println("enter running..." ); try { Thread.sleep(5 *10 *1000 ); } catch (InterruptedException e) { e.printStackTrace(); } System.out .println("end of run" ); } }); th.start(); System.out .println("main thread sleep" ); Thread.sleep(1000 ); System.out .println("main thread call interrupt" ); th.interrupt(); System.out .println("over" ); }public static void main (String[] args ) throws Exception { example3(); }
原因:
如果该线程正阻塞于Object类的wait()、wait(long)、wait(long, int)方法,或者Thread类的join()、join(long)、join(long, int)、sleep(long)、sleep(long, int)方法,则该线程的中断状态将被清除,并收到一个java.lang.InterruptedException。
如果该线程正阻塞于interruptible channel上的I/O操作,则该通道将被关闭,同时该线程的中断状态被设置,并收到一个java.
等待IO时的情况 参考这里 如何中断ServerSocket accept()方法? 其于属于抛异常,进行处理。
比较好的方法-条件变量 1 2 3 4 5 6 7 8 9 10 11 12 public class BestPractice extends Thread { private volatile boolean finished = false ; public void doStop() { finished = true ; } @Override public void run() { while (!finished) { } } }
这是最开始写多线程中推荐的写法。
总结 Java没有提供任何机制来安全地终止线程。但它提供了中断(Interruption),这是一种协作机制,能够使一个线程终止另一个线程的的工作。 中断只是一种协作机制,需要被中断的线程自己处理中断。停止一个线程最佳实践是 中断 + 条件变量。
参考