Java
停止一个线程意味着在任务处理完任务之前停掉正在做的操作,也就是放弃当前的操作。停止一个线程可以用 Thread.stop() 方法,但最好不要用它。虽然它确实可以停止一个正在运行的线程,但是这个方法是不安全的,而且是已被废弃的方法。
在 java 中有以下 3 种方法可以终止正在运行的线程:

  1. 使用退出标志,使线程正常退出,也就是当 run 方法完成后线程终止。
  2. 使用 stop 方法强行终止,但是不推荐这个方法,因为 stopsuspendresume 一样都是过期作废的方法。
  3. 使用 interrupt 方法中断线程。

    1、停止不了的线程

    interrupt() 方法的使用效果并不像 for+break 语句那样,马上就停止循环。调用 interrupt 方法是在当前线程中打了一个停止标志,并不是真的停止线程。 ```java public class MyThread extends Thread { public void run(){
    1. super.run();
    2. for(int i=0; i<500000; i++){
    3. System.out.println("i="+(i+1));
    4. }
    } }

public class Run { public static void main(String args[]){ Thread thread = new MyThread(); thread.start(); try { Thread.sleep(2000); thread.interrupt(); } catch (InterruptedException e) { e.printStackTrace(); } } }

  1. 输出结果:
  2. ```java
  3. ...
  4. i=499994
  5. i=499995
  6. i=499996
  7. i=499997
  8. i=499998
  9. i=499999
  10. i=500000

2、判断线程是否停止状态

Thread.java 类中提供了两种方法:

  1. this.interrupted(): 测试当前线程是否已经中断;
  2. this.isInterrupted(): 测试线程是否已经中断;

那么这两个方法有什么图区别呢?
先来看看 this.interrupted() 方法的解释:测试当前线程是否已经中断,当前线程是指运行 this.interrupted() 方法的线程。

  1. public class MyThread extends Thread {
  2. public void run(){
  3. super.run();
  4. for(int i=0; i<500000; i++){
  5. i++;
  6. // System.out.println("i="+(i+1));
  7. }
  8. }
  9. }
  10. public class Run {
  11. public static void main(String args[]){
  12. Thread thread = new MyThread();
  13. thread.start();
  14. try {
  15. Thread.sleep(2000);
  16. thread.interrupt();
  17. System.out.println("stop 1??" + thread.interrupted());
  18. System.out.println("stop 2??" + thread.interrupted());
  19. } catch (InterruptedException e) {
  20. e.printStackTrace();
  21. }
  22. }
  23. }

运行结果:

  1. stop 1??false
  2. stop 2??false

类 Run.java 中虽然是在 thread 对象上调用以下代码:thread.interrupt(), 后面又使用

  1. System.out.println("stop 1??" + thread.interrupted());
  2. System.out.println("stop 2??" + thread.interrupted());

来判断 thread 对象所代表的线程是否停止,但从控制台打印的结果来看,线程并未停止,这也证明了 interrupted() 方法的解释,测试当前线程是否已经中断。这个当前线程是 main,它从未中断过,所以打印的结果是两个 false.
如何使 main 线程产生中断效果呢?

  1. public class Run2 {
  2. public static void main(String args[]){
  3. Thread.currentThread().interrupt();
  4. System.out.println("stop 1??" + Thread.interrupted());
  5. System.out.println("stop 2??" + Thread.interrupted());
  6. System.out.println("End");
  7. }
  8. }

运行效果为:

  1. stop 1??true
  2. stop 2??false
  3. End

方法 interrupted() 的确判断出当前线程是否是停止状态。但为什么第 2 个布尔值是 false 呢?官方帮助文档中对 interrupted 方法的解释:
测试当前线程是否已经中断。线程的中断状态由该方法清除。 换句话说,如果连续两次调用该方法,则第二次调用返回 false
下面来看一下 inInterrupted() 方法。

  1. public class Run3 {
  2. public static void main(String args[]){
  3. Thread thread = new MyThread();
  4. thread.start();
  5. thread.interrupt();
  6. System.out.println("stop 1??" + thread.isInterrupted());
  7. System.out.println("stop 2??" + thread.isInterrupted());
  8. }
  9. }

运行结果:

  1. stop 1??true
  2. stop 2??true

isInterrupted() 并为清除状态,所以打印了两个 true

3、能停止的线程 — 异常法

有了前面学习过的知识点,就可以在线程中用 for 语句来判断一下线程是否是停止状态,如果是停止状态,则后面的代码不再运行即可:

  1. public class MyThread extends Thread {
  2. public void run(){
  3. super.run();
  4. for(int i=0; i<500000; i++){
  5. if(this.interrupted()) {
  6. System.out.println("线程已经终止, for循环不再执行");
  7. break;
  8. }
  9. System.out.println("i="+(i+1));
  10. }
  11. }
  12. }
  13. public class Run {
  14. public static void main(String args[]){
  15. Thread thread = new MyThread();
  16. thread.start();
  17. try {
  18. Thread.sleep(2000);
  19. thread.interrupt();
  20. } catch (InterruptedException e) {
  21. e.printStackTrace();
  22. }
  23. }
  24. }

运行结果:

  1. ...
  2. i=202053
  3. i=202054
  4. i=202055
  5. i=202056

线程已经终止, for循环不再执行
上面的示例虽然停止了线程,但如果 for 语句下面还有语句,还是会继续运行的。看下面的例子:

  1. public class MyThread extends Thread {
  2. public void run(){
  3. super.run();
  4. for(int i=0; i<500000; i++){
  5. if(this.interrupted()) {
  6. System.out.println("线程已经终止, for循环不再执行");
  7. break;
  8. }
  9. System.out.println("i="+(i+1));
  10. }
  11. System.out.println("这是for循环外面的语句,也会被执行");
  12. }
  13. }

使用 Run.java 执行的结果是:

  1. ...
  2. i=180136
  3. i=180137
  4. i=180138
  5. i=180139

线程已经终止, for循环不再执行
这是for循环外面的语句,也会被执行
如何解决语句继续运行的问题呢?看一下更新后的代码:

  1. public class MyThread extends Thread {
  2. public void run(){
  3. super.run();
  4. try {
  5. for(int i=0; i<500000; i++){
  6. if(this.interrupted()) {
  7. System.out.println("线程已经终止, for循环不再执行");
  8. throw new InterruptedException();
  9. }
  10. System.out.println("i="+(i+1));
  11. }
  12. System.out.println("这是for循环外面的语句,也会被执行");
  13. } catch (InterruptedException e) {
  14. System.out.println("进入MyThread.java类中的catch了。。。");
  15. e.printStackTrace();
  16. }
  17. }
  18. }

使用 Run.java 运行的结果如下:

  1. ...
  2. i=203798
  3. i=203799
  4. i=203800

线程已经终止, for循环不再执行
进入MyThread.java类中的catch了。。。

  1. java.lang.InterruptedException
  2. at thread.MyThread.run(MyThread.java:13)

4、在沉睡中停止

如果线程在 sleep() 状态下停止线程,会是什么效果呢?

  1. public class MyThread extends Thread {
  2. public void run(){
  3. super.run();
  4. try {
  5. System.out.println("线程开始。。。");
  6. Thread.sleep(200000);
  7. System.out.println("线程结束。");
  8. } catch (InterruptedException e) {
  9. System.out.println("在沉睡中被停止, 进入catch, 调用isInterrupted()方法的结果是:" + this.isInterrupted());
  10. e.printStackTrace();
  11. }
  12. }
  13. }

使用 Run.java 运行的结果是:
线程开始。
在沉睡中被停止, 进入catch, 调用isInterrupted()方法的结果是:false

  1. java.lang.InterruptedException: sleep interrupted
  2. at java.lang.Thread.sleep(Native Method)
  3. at thread.MyThread.run(MyThread.java:12)

从打印的结果来看, 如果在 sleep 状态下停止某一线程,会进入 catch 语句,并且清除停止状态值,使之变为 false
前一个实验是先 sleep 然后再用 interrupt() 停止,与之相反的操作在学习过程中也要注意:

  1. public class MyThread extends Thread {
  2. public void run(){
  3. super.run();
  4. try {
  5. System.out.println("线程开始。。。");
  6. for(int i=0; i<10000; i++){
  7. System.out.println("i=" + i);
  8. }
  9. Thread.sleep(200000);
  10. System.out.println("线程结束。");
  11. } catch (InterruptedException e) {
  12. System.out.println("先停止,再遇到sleep,进入catch异常");
  13. e.printStackTrace();
  14. }
  15. }
  16. }
  17. public class Run {
  18. public static void main(String args[]){
  19. Thread thread = new MyThread();
  20. thread.start();
  21. thread.interrupt();
  22. }
  23. }

运行结果:

  1. i=9998
  2. i=9999

先停止,再遇到sleep,进入catch异常

  1. java.lang.InterruptedException: sleep interrupted
  2. at java.lang.Thread.sleep(Native Method)
  3. at thread.MyThread.run(MyThread.java:15)

5、能停止的线程 —- 暴力停止

使用 stop() 方法停止线程则是非常暴力的。

  1. public class MyThread extends Thread {
  2. private int i = 0;
  3. public void run(){
  4. super.run();
  5. try {
  6. while (true){
  7. System.out.println("i=" + i);
  8. i++;
  9. Thread.sleep(200);
  10. }
  11. } catch (InterruptedException e) {
  12. e.printStackTrace();
  13. }
  14. }
  15. }
  16. public class Run {
  17. public static void main(String args[]) throws InterruptedException {
  18. Thread thread = new MyThread();
  19. thread.start();
  20. Thread.sleep(2000);
  21. thread.stop();
  22. }
  23. }

运行结果:

  1. i=0
  2. i=1
  3. i=2
  4. i=3
  5. i=4
  6. i=5
  7. i=6
  8. i=7
  9. i=8
  10. i=9
  11. Process finished with exit code 0

6、方法 stop()java.lang.ThreadDeath 异常

调用 stop() 方法时会抛出 java.lang.ThreadDeath 异常,但是通常情况下,此异常不需要显示地捕捉。

  1. public class MyThread extends Thread {
  2. private int i = 0;
  3. public void run(){
  4. super.run();
  5. try {
  6. this.stop();
  7. } catch (ThreadDeath e) {
  8. System.out.println("进入异常catch");
  9. e.printStackTrace();
  10. }
  11. }
  12. }
  13. public class Run {
  14. public static void main(String args[]) throws InterruptedException {
  15. Thread thread = new MyThread();
  16. thread.start();
  17. }
  18. }

stop() 方法以及作废,因为如果强制让线程停止有可能使一些清理性的工作得不到完成。另外一个情况就是对锁定的对象进行了解锁,导致数据得不到同步的处理,出现数据不一致的问题。

7、释放锁的不良后果

使用 stop() 释放锁将会给数据造成不一致性的结果。如果出现这样的情况,程序处理的数据就有可能遭到破坏,最终导致程序执行的流程错误,一定要特别注意:

  1. public class SynchronizedObject {
  2. private String name = "a";
  3. private String password = "aa";
  4. public synchronized void printString(String name, String password){
  5. try {
  6. this.name = name;
  7. Thread.sleep(100000);
  8. this.password = password;
  9. } catch (InterruptedException e) {
  10. e.printStackTrace();
  11. }
  12. }
  13. public String getName() {
  14. return name;
  15. }
  16. public void setName(String name) {
  17. this.name = name;
  18. }
  19. public String getPassword() {
  20. return password;
  21. }
  22. public void setPassword(String password) {
  23. this.password = password;
  24. }
  25. }
  26. public class MyThread extends Thread {
  27. private SynchronizedObject synchronizedObject;
  28. public MyThread(SynchronizedObject synchronizedObject){
  29. this.synchronizedObject = synchronizedObject;
  30. }
  31. public void run(){
  32. synchronizedObject.printString("b", "bb");
  33. }
  34. }
  35. public class Run {
  36. public static void main(String args[]) throws InterruptedException {
  37. SynchronizedObject synchronizedObject = new SynchronizedObject();
  38. Thread thread = new MyThread(synchronizedObject);
  39. thread.start();
  40. Thread.sleep(500);
  41. thread.stop();
  42. System.out.println(synchronizedObject.getName() + " " + synchronizedObject.getPassword());
  43. }
  44. }

输出结果:

  1. b aa

由于 stop()方法以及在 JDK 中被标明为 “过期 / 作废” 的方法,显然它在功能上具有缺陷,所以不建议在程序张使用 stop()方法。

8、使用 return 停止线程

将方法 interrupt()return 结合使用也能实现停止线程的效果:

  1. public class MyThread extends Thread {
  2. public void run(){
  3. while (true){
  4. if(this.isInterrupted()){
  5. System.out.println("线程被停止了!");
  6. return;
  7. }
  8. System.out.println("Time: " + System.currentTimeMillis());
  9. }
  10. }
  11. }
  12. public class Run {
  13. public static void main(String args[]) throws InterruptedException {
  14. Thread thread = new MyThread();
  15. thread.start();
  16. Thread.sleep(2000);
  17. thread.interrupt();
  18. }
  19. }

输出结果:

  1. ...
  2. Time: 1467072288503
  3. Time: 1467072288503
  4. Time: 1467072288503

线程被停止了!
不过还是建议使用 “抛异常” 的方法来实现线程的停止,因为在 catch 块中还可以将异常向上抛,使线程停止事件得以传播。