声明:
本博客是本人在学习《Java 多线程编程核心技术》后整理的笔记,旨在方便复习和回顾,并非用作商业用途。
本博客已标明出处,如有侵权请告知,马上删除。
1.7 停止线程
停止一个线程意味着在线程处理完任务之前停掉正在做的操作,也就是放弃当前操作。
在 Java 中有以下三种方法可以终止正在运行的线程:
- 使用退出标志,使线程正常退出,也就是当 run() 方法完成后线程终止
- 使用 stop() 方法强行终止线程,已废弃,不推荐使用
- 使用 interrupt() 方法中断线程,经常使用
1.7.1 停止不了的线程
接下来会使用 interrupt() 方法,但这个方法不会真的停止线程,只是在当前线程中打了一个停止的标记
下面通过一个示例来说明:
-
创建一个自定义的线程类
public class MyThread14 extends Thread { @Override public void run() { super.run(); for (int i = 0; i < 500000; i++) { System.out.println(i); } } }
-
测试类
public class MyThread14Test { public static void main(String[] args) { try { MyThread14 myThread14 = new MyThread14(); myThread14.start(); Thread.sleep(1000); myThread14.interrupt(); } catch (InterruptedException e) { e.printStackTrace(); } } }
运行结果
... 499990 499991 499992 499993 499994 499995 499996 499997 499998 499999
分析:从运行结果来看,调用 interrupt() 方法并没有停止线程,那该如何停止线程呢?
1.7.2 判断线程是否是停止状态
在介绍如何如何停止线程前,先来看一下如何判断线程的状态是否是停止的。
Thread 类中提供了两种方法:
- this.interrupted():测试当前线程是否已经是中断状态,当前线程是指运行 this.interrupted() 方法的线程,执行后具有将状态标志清除为 false 的功能
- this.isInterrupted():测试线程 Thread 对象是否已经是中断状态,但不清除状态标志
下面通过一个示例来演示 interrupted() 方法的使用:
-
创建一个自定义的线程类
public class MyThread15 extends Thread { @Override public void run() { super.run(); for (int i = 0; i < 50000; i++) { System.out.println(i); } } }
-
测试类
public class MyThread15Test { public static void main(String[] args) { try { MyThread15 myThread15 = new MyThread15(); myThread15.start(); // 让 main 线程休眠 0.5 秒,这样线程规划器会先执行 myThread15 线程 Thread.sleep(500); myThread15.interrupt(); System.out.println("是否停止1 = " + myThread15.interrupted()); System.out.println("是否停止2 = " + myThread15.interrupted()); } catch (InterruptedException e) { e.printStackTrace(); } } }
运行结果
... 40292 40293 40294 40295 是否停止1 = false 40296 40297 ... 40803 40804 40805 是否停止2 = false 40806 40807 40808 40809 ...
分析:
我们在测试类中调用了以下代码,来停止 myThread15 线程:
myThread15.interrupt();
但在后面又使用了以下代码,来判断当前线程是否停止:
System.out.println("是否停止1 = " + myThread15.interrupted());
System.out.println("是否停止2 = " + myThread15.interrupted());
但打印结果说明当前线程并未停止,再看看 interrupted() 方法的解释:测试当前线程是否已经是中断状态,当前线程是指运行 this.interrupted() 方法的线程
这个当前线程是 main 线程,它从未中断过,所以打印结果是两个 false
接下来让 main 线程产生中断,再看看:
-
创建测试类
public class Test3 { public static void main(String[] args) { Thread.currentThread().interrupt(); System.out.println("是否停止1 = " + Thread.interrupted()); System.out.println("是否停止2 = " + Thread.interrupted()); } }
运行结果
是否停止1 = true 是否停止2 = false
分析:第一次调用 interrupted() 判断当前线程已经是中断状态了,然后清除了状态标志,所以第二次调用 interrupted() 方法的返回值是 false
介绍完 interrupted() 方法,下面通过一个示例来演示 isInterrupted() 方法的使用:
-
创建测试类
public class MyThread15Test_2 { public static void main(String[] args) { try { MyThread15 myThread15 = new MyThread15(); myThread15.start(); // 让 main 线程休眠 0.5 秒,这样线程规划器会先执行 myThread15 线程 Thread.sleep(500); myThread15.interrupt(); System.out.println("是否停止1 = " + myThread15.isInterrupted()); System.out.println("是否停止2 = " + myThread15.isInterrupted()); } catch (InterruptedException e) { e.printStackTrace(); } } }
运行结果
... 48254 48255 48256 48257 是否停止1 = true 是否停止2 = true 48258 48259 48260 ...
分析:从打印结果上来看,测试 myThread15 线程已经是中断状态了,而且 isInterrupted() 方法并不清除状态标志,所以打印了两个 true
1.7.3 能停止的线程——异常法
有了前面学习的知识,就可以在 for 语句中判断一下线程是否是中断状态了,如果是中断状态,则后面的代码不再运行即可。
下面通过一个示例来演示异常法停止线程:
-
创建一个自定义的线程类
public class MyThread16 extends Thread { @Override public void run() { super.run(); try { for (int i = 0; i < 50000; i++) { // 如果是中断状态就不再执行后面的代码了 if (this.interrupted()) { System.out.println("我要退出了..."); throw new InterruptedException(); } System.out.println(i); } } catch (InterruptedException e) { e.printStackTrace(); } } }
-
测试类
public class MyThread16Test { public static void main(String[] args) { try { MyThread16 myThread16 = new MyThread16(); myThread16.start(); Thread.sleep(500); myThread16.interrupt(); } catch (InterruptedException e) { e.printStackTrace(); } } }
运行结果
... 41332 41333 41334 41335 41336 41337 41338 我要退出了... java.lang.InterruptedException at MyThread16.run(MyThread16.java:9)
1.7.4 在沉睡中停止
如果线程在 sleep() 状态下停止线程,会是什么效果呢?
下面通过一个示例来演示:
-
创建一个自定义的线程类
public class MyThread17 extends Thread { @Override public void run() { super.run(); try { System.out.println("begin"); Thread.sleep(100000); System.out.println("end"); } catch (InterruptedException e) { System.out.println("线程沉睡中被中断,进入 catch !" + " this.interrupted() = "+this.interrupted()); e.printStackTrace(); } } }
-
测试类
public class MyThread17Test { public static void main(String[] args) { try { MyThread17 myThread17 = new MyThread17(); myThread17.start()