出于测试目的杀死 Java 线程

Kill Java Thread for testing purposes

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

然而,实际上可能发生的是线程死亡(例如,OutOfMemoryError)或整个 JVM 死亡(sigsev 或 OS 进程终止)。我可以看到在 JUnit 测试中模拟 JVM 进程的意外关闭是不可能的(因为 JUnit 运行在同一个 JVM 中)。但是如何杀死一个线程呢?我知道 Thread#stop(),但它已被弃用,而且会在线程中抛出 ThreadDeathError。我想模拟的是一个线程的瞬时 "death",它甚至可以防止 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 使用 OS 线程,因此依赖于底层的 OS 调度程序。所以在 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 中提出 asynchronous exceptiont1线程可以通过轮询检测异步异常。

来自 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());
}