停止线程的正确姿势

雨点打透心脏的1/2处 2023-07-05 11:55 91阅读 0赞

推荐:Java并发编程汇总

停止线程的正确姿势

原文地址

Java线程状态和关闭线程的正确姿势

正文

线程的run()方法正常执行完毕之后线程就正常死亡进入TERMINATED状态了,那么如果我们有中途停止线程的需求,我们应该如何正确的结束一个线程呢?

使用interrupt()方法

在线程内部,其定义了一个变量来标识当前线程是否处于被打断状态,调用interrupt()方法则使这个状态变为true;换句话说,线程在阻塞状态的时候会检查标识状态,如果是true,则抛出InterruptedException,否则阻塞,所以不会打断非阻塞的线程,即对正在运行的线程此方法无效。我们采用这个方法加异常处理的方式来结束一个线程。

  1.   public static void main(String[] args) {
  2. Thread thread = new Thread(() -> {
  3. try {
  4. Thread.sleep(1);
  5. } catch (InterruptedException e) {
  6. e.printStackTrace();
  7. // 这里的return是必须的,原因后面说明
  8. return;
  9. }
  10. System.err.println("thread interrupt test...");
  11. });
  12. thread.start();
  13. thread.interrupt();
  14. System.out.println("main thread end...");
  15. }

在这里插入图片描述

这里关于线程中的打断标识变量(之后以interrupt称)需要说明的是,在特定的情况下其状态会被重置。

  1. 线程内部在catch了异常之后interrupt的状态会被重置为false。
  2. 线程调用了Thread.interrupted()方法之后,interrupt的状态会被重置为false。如果需要判断线程是否中断的话可以使用对象方法isInterrupted(),此方法不会重置。

所以在刚才的代码中需要加入return来结束线程,否则的话线程还是会继续往下执行,如下图:
在这里插入图片描述
使用isInterrupted()实现:

  1. public static void main(String[] args) throws InterruptedException {
  2. Thread thread = new Thread(() -> {
  3. while (!Thread.currentThread().isInterrupted()) {
  4. int k = 0;
  5. while (k++ < 10) {
  6. System.out.println("do something..." + k);
  7. }
  8. }
  9. System.err.println("thread end...");
  10. });
  11. thread.start();
  12. Thread.sleep(1);
  13. // 主线程流程执行完了,需要停止线程
  14. thread.interrupt();
  15. }

stop()方法——不正确的线程中断方法

在线程提供的方法中还有一个方法可以强制关闭线程——stop()。这个方法可以说是相当的霸道,给人一种“我不管,我就是要你现在立刻死亡(指线程)”的感觉,并且其还会释放线程所有的锁资源,这样可能会导致出现数据不一致从而出现线程不安全的情况,如下面例子。

  1. public class Test {
  2. public static volatile boolean flag = false;
  3. public int state = 0;
  4. public static void main(String[] args) throws InterruptedException {
  5. Test test = new Test();
  6. Thread thread = new Thread(() -> {
  7. synchronized (test) {
  8. try {
  9. test.state = 1;
  10. Thread.sleep(100);
  11. if (flag) {
  12. test.state = 2;
  13. }
  14. System.err.println("thread execute finished...");
  15. } catch (InterruptedException e) {
  16. e.printStackTrace();
  17. }
  18. }
  19. });
  20. thread.start();
  21. Thread.sleep(1);
  22. thread.stop();
  23. flag = true;
  24. System.out.println("state状态:" + test.state);
  25. }
  26. }

在这段代码中,进入线程时默认将state赋为1,接着过一段时间后如果触发了特定条件则把state赋为2,但是在特定条件触发之前,线程就被终止掉了,这个特定条件虽然符合但却没办法执行,从而导致数据的不一致。
结果图:
在这里插入图片描述

所以,我们应该采用上面正确的方式而不是stop()来中止线程。此外,stop()方法若在线程start()之前执行,那么在线程启动的时候就会立即死亡。

发表评论

表情:
评论列表 (有 0 条评论,91人围观)

还没有评论,来说两句吧...

相关阅读

    相关 启动线正确姿势

    推荐:[Java并发编程汇总][Java] 启动线程的正确姿势 通过之前的分析,我们知道了有两种定义线程执行逻辑的方法,而创建线程只有一种方法,也就是`new`一个`T

    相关 正确停止线

    原理介绍:使用interrupt来通知,而不是强制 核心:想要停止线程其实是如何运用interrupt来通知那个线程,以及被停止的线程如何配合。 我们作为想停止线程的