杀死Java线程用于测试目的

时间:2016-08-22 15:26:54

标签: java multithreading unit-testing jvm kill

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

然而,在实践中,可能发生的是线程的死亡(例如,通过OutOfMemoryError)或整个JVM的死亡(sigsev或OS进程终止)。我可以看到,在JUnit测试中模拟JVM进程的意外关闭是不可能的(因为JUnit在同一个JVM中运行)。但杀死一个线程怎么样?我知道Thread#stop(),但它已被弃用,而且在线程中抛出ThreadDeathError。我想模拟的是瞬间"死亡"阻止甚至catch(Throwable t)子句被触发的线程。这可以用Java完成,而不会杀死JUnit测试运行器吗?

同样,不是生产用途,它只是严格测试。

1 个答案:

答案 0 :(得分:2)

  瞬间"死亡"一个线程阻止甚至捕获(Throwable t)子句被触发。这可以用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()的无限循环看起来像#34;并没有自愿被暂停"

stop()asynchronous exception中加注t1t1线程可以通过轮询检测异步异常。

来自Java Virtual Machine Specification

  

一个线程可以调用stop方法来影响另一个线程或指定线程组中的所有线程。它们是异步的,因为它们可能在执行其他线程或线程的任何时刻发生。内部错误被视为异步

     

一个简单的实现可能会在每个控制转移指令处轮询异步异常。

这意味着,在编译代码中,在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());
}