Thread.stop() 与 ThreadDeath 的理解、注意点以及误区

2023-05-16

MySQL 普通查询、流式查询、游标查询以及使用 mybatis 如何实现

    • Thread.stop() 的缺陷
    • 顶级的异常处理器不会打印关于 `ThreadDeath` 的信息
    • ThreadDeath 只是一个通知,捕获 ThreadDeath 可导致线程不会终止
    • 执行外部代码,超时自动终止线程的例子
    • 参考

通常情况下终止线程的方式是使用中断,或者使用一个标志位。但这些方法只适用于我们自己编写的代码,即我们知道代码是如何实现的、是否响应中断、是否是用标志位判断终止与否。但对于外部代码,比如说来着网络的 class 文件,其中有一个死循环,我们用一个线程来执行它,如何才能终止它的执行?我的方式是 Thread.stop()ThreadDeath

Thread.stop() 可以强制线程停止执行。会停止执行当前代码并抛出 ThreadDeath 错误。使用时要注意一下几点:

  1. Thread.stop() 方法有缺陷,它会解锁已锁定的所有监视器(synchronized 锁)。 如果这些锁之前保护的任何对象处于不一致的状态,则损坏的对象将对其他线程可见,从而可能导致任意行为。
  2. 默认的情况下,顶级的异常处理器不会打印关于 ThreadDeath 的信息,也不会以其他方式通知应用程序。若要获取 ThreadDeath 的信息,必须手动捕获 ThreadDeath
  3. 如果我们捕获了 ThreadDeath 但又做了其他的操作,线程则无法及时终止
  4. Thread.stop()Thread.interrupt()只是以抛出异常的方式给了应用程序一个通知,都不是强制终止线程,最起码不像 kill -9 tid 那样强制、暴力、有效。区别在于 Thread.interrupt() 只能在响应中断的方法上抛出异常,而 Thread.stop() 可以在任意地方抛出异常。

Thread.stop() 的缺陷

在下面的代码中,countlistlock 保护,count 自增的同时,list 中也应该添加一个元素,也就是说 countlist.size() 始终都应该一样。但如果在 count++ 之后,还没来得及执行 list.add(new Object()) 时调用了 thread.stop(),这会导致线程终止并释放锁,造成数据的不一致,countlist.size() 分别为 10

private static final Object lock = new Object();

private static int count = 0;

private static final List<Object> list = new LinkedList<>();


public static void main(String[] args) throws InterruptedException {

    Runnable runnable = () -> {
        synchronized (lock) {
            count++;

            longTime();

            list.add(new Object());
        }
    };

    Thread thread = new Thread(runnable);
    thread.start();

    Thread.sleep(10);
    thread.stop();

    synchronized (lock) {
        System.out.println(count);
        System.out.println(list.size());
    }
}

public static void longTime() {
    for (int i = 0; i < Integer.MAX_VALUE; i++) {
        for (int j = 0; j < Integer.MAX_VALUE; j++) {}
    }
}

// 执行结果
1
0

顶级的异常处理器不会打印关于 ThreadDeath 的信息

以下代码不会打印任何错误信息:

public static void main(String[] args) throws InterruptedException {

    Runnable runnable = () -> {
        for (;;) {}
    };

    Thread thread = new Thread(runnable);
    thread.start();

    Thread.sleep(10);
    thread.stop();
}

必须手动捕获 ThreadDeath,手动打印错误信息

Runnable runnable = () -> {
    try {
        for (;;) {}
    } catch (ThreadDeath e) {
        e.printStackTrace();
    }
};

错误信息:

java.lang.ThreadDeath
	at java.base/java.lang.Thread.stop(Thread.java:1717)
	at com.example.test.main(T2.java:29)

ThreadDeath 只是一个通知,捕获 ThreadDeath 可导致线程不会终止

public static void main(String[] args) throws InterruptedException {

    Runnable runnable = () -> {
        try {
            for (;;) {}
        } catch (ThreadDeath e) {
            e.printStackTrace();
            int i = 0;
            for (;;) {
                System.out.println(i++);
            }
        }
    };

    Thread thread = new Thread(runnable);
    thread.start();
    thread.stop();
}

上述代码中的线程不会终止,应该会一直打印,但我在测试时打印到 348067 左右就停了,但 jvm 没有退出,不知道为什么???

java.lang.ThreadDeath
	at java.lang.Thread.stop(Thread.java:858)
	at T3.main(T3.java:28)
0
1
2
3
4
5
6
7
8

执行外部代码,超时自动终止线程的例子

假设外部代码实现了 Runnable 接口

public static void main(String[] args) throws InterruptedException {

    Runnable runnable = () -> {
        for (;;) {}
    };
    invoke(runnable, 10, TimeUnit.SECONDS);
}

public static void invoke(Runnable runnable, long timeout, TimeUnit timeUnit) {
    Thread thread = new Thread(runnable, "thread-runnable-xx");
    thread.start();
    try {
        thread.join(timeUnit.toMillis(timeout));
    } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
    }
    thread.stop();
}

这种方法有一个缺陷:如果外部代码捕获了 ThreadDeath,可能线程就无法终止了。例如:

public static void main(String[] args) throws InterruptedException {

    Runnable runnable = () -> {
        try {
            for (;;) {}
        } catch (ThreadDeath e) {
            e.printStackTrace();
            int i = 0;
            for (;;) {
                System.out.println(i++);
            }
        }
    };
    invoke(runnable, 10, TimeUnit.SECONDS);
}

参考

  • Why are Thread.stop, Thread.suspend and Thread.resume Deprecated?
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Thread.stop() 与 ThreadDeath 的理解、注意点以及误区 的相关文章

  • std::atomic_thread_fence

    在原子变量的存取上应用不同的memory order可以实现不同的内存序来达到数据同步的目的 xff0c 而在C 43 43 11及之后的标准里 xff0c 除了利用原子操作指定内存序 xff0c 还定义了单独使用 内存栅栏 xff08 s
  • 【C++11多线程】线程的创建与结束:thread

    文章目录 1 普通函数作为线程函数 1 1 thread 1 2 join 1 3 detach 1 4 joinable 2 函数对象作为线程函数 3 lambda表达式作为线程函数 4 类成员函数作为线程函数 5 向线程函数传递参数 1
  • Android的消息处理机制(图+源码分析)——Looper,Handler,Message

    百度二面的时候 觉得自己源码分析太差 没有深入 面试官估计觉得我很不爽 恩 来吧 自己结合这篇文章 基本上把android消息机制给弄清楚了 http www androidzz com 2011 09 android looper han
  • 03C++11多线程编程之测试join,detach传各种实参时形参的拷贝次数

    03C 11多线程编程之测试join detach传各种实参时形参的拷贝次数 首先我们看下面的总结测试图 然后一步步的测试 1 这里我们先测试join传实参的类型 当实参为普通对象时 1 当形参为普通对象时 拷贝了两次 2 当形参为引用时
  • java中的锁池和等待池

    在java中 每个对象都有两个池 锁 monitor 池和等待池 wait notifyAll notify 三个方法都是Object类中的方法 锁池 假设线程A已经拥有了某个对象 注意 不是类 的锁 而其它的线程想要调用这个对象的某个sy
  • C#-Async关键字(异步方法)

    async关键字 异步方法 async关键字是C 特有的 Java没有这玩意 async在C 世界里是上下文关键字 它只有在修饰一个方法的时候才自动被编译器识别为关键字 在代码的其他位置上可以被用作变量名等其他任何用途 async关键字用来
  • java线程的五大状态,阻塞状态详解

    一 状态简介 一个线程的生命周期里有五大状态 分别是 新生 就绪 运行 死亡 运行后可能遇到的阻塞状态 二 相关方法 2 1 新生状态 Thread t new Thread 正如我们前面所说的 一个线程开始之后有自己的内存空间 这些工作空
  • java多线程实战( 多个线程 修改同一个变量)

    java多线程实战 多个线程 修改同一个变量 synchronized 同步 介绍 java多线程实战 需求 创建两个线程 分别输出 a b 要求输出总和为30个 线程介绍 一 定义线程 1 扩展java lang Thread类 此类中有
  • Linux 线程同步的三种方法

    线程的最大特点是资源的共享性 但资源共享中的同步问题是多线程编程的难点 linux下提供了多种方式来处理线程同步 最常用的是互斥锁 条件变量和信号量 一 互斥锁 mutex 通过锁机制实现线程间的同步 初始化锁 在Linux下 线程的互斥量
  • java常见笔试题目

    1 下列那一行代码编译后不会出现警告或错误 1 char c a 2 byte b 257 3 boolean b null 4 int i 10 5 float f 1 3 2 下面这段代码编译时会发生什么情况 public class
  • Java 线程创建方法

    除了继承Thread 实现Runnable Callable三种创建线程方式外的第四种创建方式 实现java util concurrent ThreadFactory接口 实现newThread Runnable r 方法 这种方式应用于
  • muduo1——编程风格:面向对象的编程和基于对象的编程(上)

    muduo库其实不是面向对象的编程 而是基于对象的编程 那么在进入正式的muduo源码分析之前 先来看看这两种编程风格 一 面向对象编程风格 通过对一个线程类的封装来进行讲解 Thread是一个抽象类不能实例化对象 TestThread是派
  • wxWidgets开发之多线程wxThread编程

    上节说到使用wxCondition来实现某一消息处理的业务场景的多线程处理方法 在此之前先分享一下wxCondition用法 条件变量 最常用在多线程环境下 用来指示当前所在线程的某些条件已经满足 其他线程可以共享该线程的数据 或者去完成预
  • 笔试题10:Runnable接口与Thread类的区别?

    1 线程类继承自Thread则不能继承自其它类 而Runnable接口可以 2 线程类继承自Thread相对于Runnable来说 使用线程的方法更方便一些 3 实现Runnable接口的线程类的多个线程 可以更方便的访问同一变量 而Thr
  • 实时系统RTX之理解一

    文献来源 http wzhyblog yo2 cn articles e5 ae 9e e6 97 b6 e7 b3 bb e7 bb 9frtx e5 ae 98 e6 96 b9 e6 96 87 e6 a1 a3 e4 b8 ad e
  • 使用org.apache.tools.zip包操作文件

    import java io import org apache tools zip import java util Enumeration 功能 zip压缩 解压 支持中文文件名 说明 本程序通过使用Apache Ant里提供的zip工
  • python基于字典多线程目录枚举工具

    基于字典多线程目录枚举工具 整体思路 命令行参数获取 字典文件的读取 多线程访问 命令行参数获得 使用模块 sys getopt sys argv获取命令行执行的数据 参数获得 opt args getopt getopt sys argv
  • 多线程之创建工作者线程和用户界面线程区别

    转帖 部分原创 1 工作者线程倾向于琐碎的处理 与它不同的是 用户界面线程具有自己的界面而且实际上类似于运行其他应用程序 创建线程而不是其他应用程序的好处是线程可与应用程序共享程序空间 这样可以简化线程与应用程序共享数据的功能 2 典型情况
  • Java调用Win API

    官方网站 http jawinproject sourceforge net 把lib文件夹下的jawin jar和jawin stubs jar放到 JAVA HOME jre lib ext 目录下 把bin文件夹下的jawin dll
  • QT实现多线程,以及子线程调用主线程方法与变量

    实现思路 第一步需要将子线程声明为主线程的友元类 第二步是将主线程类对象的地址通过信号槽传递给子线程中创建的对象 使得子线程能访问主线程的数据的 1 子线程 displayresult h 头文件 伪代码 include tabwindow

随机推荐