我目前正在使用Java实现的ACID语义测试事务系统。该系统具有回调处理程序,允许在事务期间执行任意调试操作,例如,抛出一个模拟错误的异常。
然而,在实践中,可能发生的是线程的死亡(例如,通过OutOfMemoryError)或整个JVM的死亡(sigsev或OS进程终止)。我可以看到,在JUnit测试中模拟JVM进程的意外关闭是不可能的(因为JUnit在同一个JVM中运行)。但杀死一个线程怎么样?我知道Thread#stop()
,但它已被弃用,而且在线程中抛出ThreadDeathError
。我想模拟的是瞬间"死亡"阻止甚至catch(Throwable t)
子句被触发的线程。这可以用Java完成,而不会杀死JUnit测试运行器吗?
同样,不是生产用途,它只是严格测试。
答案 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
中加注t1
。 t1
线程可以通过轮询检测异步异常。
来自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());
}