java - 出于测试目的终止 Java 线程

标签 java multithreading unit-testing jvm kill

我目前正在测试一个用 Java 实现的具有 ACID 语义的事务系统。系统具有回调处理程序,允许在事务期间执行任意调试操作,例如抛出模拟错误的异常。

然而,实际上可能发生的是线程死亡(例如,由于 OutOfMemoryError)或整个 JVM 死亡(sigsev 或操作系统进程终止)。我可以看到,在 JUnit 测试中模拟 JVM 进程的意外关闭是不可能的(因为 JUnit 运行在同一个 JVM 中)。但是杀死一个线程呢?我知道 Thread#stop() ,但它已被弃用,而且会在线程中引发 ThreadDeathError 。我想模拟的是线程的瞬时“死亡”,它甚至阻止了 catch(Throwable t) 子句的触发。这可以在 Java 中完成,而不杀死 JUnit 测试运行程序吗?

再次强调,这不用于生产用途,它仅用于严格测试。

最佳答案

the instantaneous "death" of a thread that prevents even catch(Throwable t) clauses from firing. Can this be done in Java?

没有。这是不可能的。

JVM 使用操作系统线程,因此依赖于底层操作系统调度程序。所以在JVM层面,JVM不能抢占java线程。 java 线程必须主动挂起。 (这是常见情况,但仍然特定于平台和 JVM)

public static void main(String[] args) throws InterruptedException {
  Thread t1 = new Thread(new Runnable() {
    @Override
    public void run() {
      while (true) {
        int i = 0;
        i++;
      }
    }
  });
  t1.start();
  Thread.sleep(1000);
  t1.stop();
  Thread.sleep(1000);
  System.out.println(t1.isAlive());
}

在上面的代码中,stop() 起作用了。但您可能想知道为什么没有 wait()/sleep() 的无限循环看起来像“不自愿被挂起”?

stop()t1 中引发异步异常t1线程可以通过轮询的方式检测异步异常。

来自Java Virtual Machine Specification :

The stop methods may be invoked by one thread to affect another thread or all the threads in a specified thread group. They are asynchronous because they may occur at any point in the execution of the other thread or threads. An internal error is considered asynchronous

A simple implementation might poll for asynchronous exceptions at the point of each control transfer instruction.

这意味着,在编译后的代码中,在 jump 之前的 while 循环末尾,有一条指令来轮询异常。如果异常存在,t1线程跳转到异常处理程序并自行停止。

因此,如果我让线程忽略所有异常,并且线程不自行停止,则不可能杀死 java 线程。

这是一个 stop() 不起作用的示例:

public static void main(String [] args) throws InterruptedException {
  Thread t1 = new Thread(new Runnable() {
    @Override
    public void run() {
      while (true) {
        try {
          while (true) {
            int i = 0;
            i++;
          }
        } catch (Throwable e) {
          e.printStackTrace();
        }
      }
    }
  });
  t1.start();
  Thread.sleep(1000);
  t1.stop();
  Thread.sleep(1000);
  System.out.println(t1.isAlive());
}

关于java - 出于测试目的终止 Java 线程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39083394/

相关文章:

java - 将带引号的 Java 字符串拆分为不带引号的参数

java - 无法从 jar 文件启动 JavaFx 应用程序。未找到类异常

java - 在java中设置代理

java - 如何在Java中创建可以代表两种不同类型的对象类型

.net - 不可变对象(immutable对象)的线程安全性如何?

带参数传递的 Java 并行 for 循环

ios - 核心数据持久存储异步保存

unit-testing - 暂时获得 Jest 报道,只显示特定文件夹中的文件

angularjs - 单元测试 AngularJS 指令

unit-testing - 在grails单元测试中访问resources.xml/appContext.xml定义的bean