Java线程中断的三种方法
多线程编程中耗时线程是很常见的情况,有时候我们不得不在一个线程中去终止另一个耗时线程。JDK并不推荐直接停止比如this.stop(),这会导致一些异常,比如锁未释放程序一直死锁。JDK推荐使用一个线程去通知耗时线程该结束线程了,耗时线程做退出前的回收处理然后自己结束线程。
自定义标志位终止
使用volatile 修饰的变量isExit控制线程的退出,这种方法需要不断及时判断isExit的值
public class FinishThreadLearn { public static void main(String[] args) throws InterruptedException { InterruptStopThread threadA = new InterruptStopThread("A"); threadA.start(); Thread.sleep(100); System.out.println("终止线程"); threadA.isExit=true; } } class InterruptStopThread extends Thread { private String name; public volatile boolean isExit = false; public InterruptStopThread(String name) { this.name = name; } @Override public void run() { super.run(); while (!isExit) { System.out.println("Thead:" + this.name + "正在运行"); } System.out.println("线程结束运行"); } }
输出结果可以看到,线程并未立即终止,结束循环体后才最终结束线程。
interrupt() 方式终止
正常执行的代码
public class FinishThreadLearn { public static void main(String[] args) throws InterruptedException { InterruptStopThread threadA = new InterruptStopThread("A"); threadA.start(); Thread.sleep(100); System.out.println("终止线程"); threadA.interrupt(); } } class InterruptStopThread extends Thread { private String name; public volatile boolean isExit = false; public InterruptStopThread(String name) { this.name = name; } @Override public void run() { super.run(); while (!isInterrupted()) { System.out.println("Thead:" + this.name + "正在运行"); } System.out.println("线程结束运行"); } }
执行结果
处于阻塞休眠的代码
这里有点不一样,interrupt()方式中断阻塞会把标志位清除并报出InterruptedException异常,所以要在catch的时候退出。
public class FinishThreadLearn { public static void main(String[] args) throws InterruptedException { InterruptStopThread threadA = new InterruptStopThread("A"); threadA.start(); Thread.sleep(2000); System.out.println("终止线程"); threadA.interrupt(); } } class InterruptStopThread extends Thread { private String name; public volatile boolean isExit = false; public InterruptStopThread(String name) { this.name = name; } @Override public void run() { super.run(); while (true) { System.out.println("Thead:" + this.name + "正在运行"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); break; } } System.out.println("线程结束运行"); } }
执行结果
stop()强行停止
public class FinishThreadLearn { public static void main(String[] args) throws InterruptedException { InterruptStopThread threadA = new InterruptStopThread("A"); threadA.start(); Thread.sleep(100); System.out.println("终止线程"); threadA.stop(); } } class InterruptStopThread extends Thread { private String name; public volatile boolean isExit = false; public InterruptStopThread(String name) { this.name = name; } @Override public void run() { super.run(); while (!isInterrupted()) { System.out.println("Thead:" + this.name + "正在运行"); } System.out.println("线程结束运行"); } }
从执行结果可以看到,run方法并未完全执行完就结束了,所以这种方法不推荐使用
源码分析
Thread源码中使用了一个volatile修饰的标志位控制终止信号
public class Thread implements Runnable { ... /* Interrupt state of the thread - read/written directly by JVM */ private volatile boolean interrupted; ... }
interrupt方法会使标志位变为true
判断线程是否终止JDK提供了两种方式
Thread.interrupted():测试当前线程是否已经中断 this.isInterrupted():测试线程是否已经中断
this.isInterrupted()
调用isInterrupted会返回该标志位
Thread.interrupted()
调用interrupted会返回该标志位,如果为ture会将标志位清空,且这个方法为静态方法