java一个线程能否结束另一个永不停止的线程执行_如何终止一个线程

(45) 2024-06-12 08:01:01

在Java中停止一个线程有三种办法 :

1.正常结束执行;

2.发生异常;

3.被其他线程stop(Java官方不建议)

参考:https://docs.oracle.com/javase/8/docs/technotes/guides/concurrency/threadPrimitiveDeprecation.html

为什么Thread.stop弃用?

因为它本质上是不安全的。停止线程会导致它解锁已锁定的所有监视器。(当ThreadDeath异常传播到堆栈中时,监视器将被解锁。)如果先前受这些监视器保护的任何对象处于不一致状态,则其他线程现在可以以不一致的状态查看这些对象。据说这些物体已被 损坏。当线程对受损对象进行操作时,可能会导致任意行为。这种行为可能很微妙并且难以检测,或者可能是明显的。与其他未经检查的异常不同,它会 ThreadDeath默默地杀死线程; 因此,用户没有警告他的程序可能被破坏。

java一个线程能否结束另一个永不停止的线程执行_如何终止一个线程 (https://mushiming.com/)  第1张

 

所以如果遇到一种特殊情况某一个线程A会一直执行下去停不下来,这种情况是存在的比如那种需要持续取样的线程A,当然了在正常代码里会有“停止”功能,外部线程B可以发送停止信号给A,A可以直接结束。

如果A线程没有这种信号量那么B线程还可以主动停止他么?答案是不可以!

public class Test { public static void main(String args[]) throws InterruptedException { Thread thread1 = new Thread() { public void run() { fun_a(); } }; thread1.start(); int a = 0; while (a < 100) { Thread.sleep(1000); a++; if (a == 3) { a = 100; thread1.interrupt(); //thread1.stop(); //throw new RuntimeException("主函数抛出异常"); } } } public static void fun_a() { for (; ; ) { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(">> " + DateUtil.getNowTimeString()); } } } 

java一个线程能否结束另一个永不停止的线程执行_如何终止一个线程 (https://mushiming.com/)  第2张

 可以看到interrupt并不能让运行中的线程停止,这个是很容易被误解的地方。这个方法的作用并不是中断线程,而是设置一个标识,通知该线程可以被中断了,到底是继续执行,还是中断返回,由线程本身自己决定。

当对一个线程调用了interrupt()之后,如果该线程处于被阻塞状态(比如执行了wait、sleep或join等方法),那么会立即退出阻塞状态,并抛出一个InterruptedException异常,在代码中catch这个异常进行后续处理。如果线程一直处于运行状态,那么只会把该线程的中断标志设置为 true,仅此而已,所以interrupt()并不能真正的中断线程,不过在rpc调用的场景中,请求线程一般都处于阻塞状态,等待数据返回,这时interrupt()方法是可以派上用场的。

参考:Java中如何实现线程的超时中断

 

修改子线程的代码:

public static void fun_a() { for (; ; ) { try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException("子线程抛出异常"); //e.printStackTrace(); } System.out.println(">> " + DateUtil.getNowTimeString()); } }

这次是可以结束子线程,前提是子线程自己有异常捕获机制,可以接受其他线程发来的InterruptedException:

java一个线程能否结束另一个永不停止的线程执行_如何终止一个线程 (https://mushiming.com/)  第3张

 

主线程每隔2秒对子线程进行一次Interrupted:

package com.t.www; public class Test { final static Object lock = new Object(); volatile boolean stop = false; public static void main(String args[]) throws InterruptedException { Thread thread1 = new Thread() { public void run() { fun_a(); } }; thread1.start(); System.out.println("> 1 主线程start " + DateUtil.getNowTimeString()); int a = 0; while (a < 3) { Thread.sleep(2000); a++; System.out.println("> 2 主线程对子线程开始interrupt " + DateUtil.getNowTimeString()); thread1.interrupt(); System.out.println("> 3 主线程对子线程完成interrupt " + DateUtil.getNowTimeString()); } } public static void fun_a() { for (; ; ) { try { System.out.println(">> 1 子线程wait " + DateUtil.getNowTimeString()); synchronized (lock) { lock.wait(); } Thread.sleep(1000); } catch (InterruptedException e) { //throw new RuntimeException("子线程抛出异常"); e.printStackTrace(); } System.out.println(">> 2 子线程完成 " + DateUtil.getNowTimeString()); } } } 

 java一个线程能否结束另一个永不停止的线程执行_如何终止一个线程 (https://mushiming.com/)  第4张

 修改子线程代码:

try { System.out.println(">> 1 子线程wait " + DateUtil.getNowTimeString()); synchronized (lock) { lock.wait(); } Thread.sleep(1000); } catch (InterruptedException e) { //throw new RuntimeException("子线程抛出异常"); //e.printStackTrace(); System.out.println(">> 2 子线程捕获异常 " + DateUtil.getNowTimeString()); }

java一个线程能否结束另一个永不停止的线程执行_如何终止一个线程 (https://mushiming.com/)  第5张

从运行结果看和前面一致,只是没有抛出异常。 

 

修改代码子线程使用while(!Thread.currentThread().isInterrupted())判断:

public class Test { public static void main(String args[]) throws InterruptedException { Thread thread1 = new Thread() { public void run() { fun_a(); } }; thread1.start(); System.out.println("> 1 主线程start " + DateUtil.getNowTimeString()); int a = 0; while (a < 3) { Thread.sleep(2000); a++; System.out.println("> 2 主线程对子线程开始interrupt " + DateUtil.getNowTimeString()); thread1.interrupt(); System.out.println("> 3 主线程对子线程完成interrupt " + DateUtil.getNowTimeString()); } } public static void fun_a() { while(!Thread.currentThread().isInterrupted()){ try { System.out.println(">> 1 子线程 " + DateUtil.getNowTimeString()); Thread.sleep(1000); } catch (InterruptedException e) { //throw new RuntimeException("子线程抛出异常"); //e.printStackTrace(); System.out.println(">> 2 子线程捕获异常 " + DateUtil.getNowTimeString()); } System.out.println(">> 3 子线程完成 " + DateUtil.getNowTimeString()); } System.out.println(">> 4 子线程正常结束 " + DateUtil.getNowTimeString()); } } 

可以看到这次因为子线程增加了状态判断所以可以正常结束: 

java一个线程能否结束另一个永不停止的线程执行_如何终止一个线程 (https://mushiming.com/)  第6张

比较优雅的方式是使用一个变量在线程间通信,需要注意的是要保证可见性:

public class Test { private static volatile boolean finished = false; // ① volatile条件变量 public static void main(String args[]) throws InterruptedException { Thread thread1 = new Thread() { public void run() { fun_a(); } }; thread1.start(); System.out.println("> 1 主线程start " + DateUtil.getNowTimeString()); int a = 0; while (a < 3) { Thread.sleep(2000); a++; } System.out.println("> 1 主线程 a=" +a+" "+ DateUtil.getNowTimeString()); finished=true; } public static void fun_a() { while(!finished){ try { System.out.println(">> 1 子线程 " + DateUtil.getNowTimeString()); Thread.sleep(1000); } catch (InterruptedException e) { //throw new RuntimeException("子线程抛出异常"); //e.printStackTrace(); System.out.println(">> 2 子线程捕获异常 " + DateUtil.getNowTimeString()); } System.out.println(">> 3 子线程完成 " + DateUtil.getNowTimeString()); } System.out.println(">> 4 子线程正常结束 " + DateUtil.getNowTimeString()); } } 

java一个线程能否结束另一个永不停止的线程执行_如何终止一个线程 (https://mushiming.com/)  第7张

------------------

如何停止线程或任务

 

如何停止一个正在运行的java线程

java一个线程能否结束另一个永不停止的线程执行_如何终止一个线程 (https://mushiming.com/)  第8张

java一个线程能否结束另一个永不停止的线程执行_如何终止一个线程 (https://mushiming.com/)  第9张

了解Java中的线程中断

如何在Java中正确停止Thread?

你如何杀死Java中的线程?

如何在运行时停止/终止长时间运行的Java线程?超时 - >取消 - >中断状态

Java - 从不同的类停止线程

How To Stop A Thread In Java?

如何超时一个线程

 

参考《Effective Java 中文版 第3版

java一个线程能否结束另一个永不停止的线程执行_如何终止一个线程 (https://mushiming.com/)  第10张

THE END

发表回复