真的,你不能......唯一的方法是使用thread.stop,同意“合作”方法(例如偶尔检查Thread.isInterrupted或调用抛出InterruptedException的方法,例如Thread。 sleep()),或者以某种方式完全调用另一个 JVM 中的方法。
对于某些类型的测试,调用 stop() 是可以的,但它可能会损坏测试套件的状态,因此如果要避免交互影响,则必须在每次调用 stop() 后重新启动 JVM。
有关如何实现协作方法的详细说明,请查看Sun 的关于已弃用的 Thread 方法的常见问题解答。
对于现实生活中这种方法的一个示例,Eclipse RCP 的 Job API 的“IPProgressMonitor”对象允许某些管理服务(通过“取消”方法)向子流程发出信号,它们应该停止。当然,这依赖于定期实际检查 isCancelled 方法的方法,而他们经常无法做到这一点。
一种混合方法可能是用中断很好地询问线程,然后在几秒钟后用停止坚持。同样,您不应该在生产代码中使用 stop ,但在这种情况下它可能没问题,尤其是。如果您很快退出 JVM。
为了测试这种方法,我编写了一个简单的工具,它接受一个可运行文件并尝试执行它。随意评论/编辑。
public void testStop(Runnable r) {
Thread t = new Thread(r);
t.start();
try {
t.join(2000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
if (!t.isAlive()) {
System.err.println("Finished on time.");
return;
}
try {
t.interrupt();
t.join(2000);
if (!t.isAlive()) {
System.err.println("cooperative stop");
return;
}
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.err.println("non-cooperative stop");
StackTraceElement[] trace = Thread.getAllStackTraces().get(t);
if (null != trace) {
Throwable temp = new Throwable();
temp.setStackTrace(trace);
temp.printStackTrace();
}
t.stop();
System.err.println("stopped non-cooperative thread");
}
为了测试它,我编写了两个相互竞争的无限循环,一个是合作的,一个从不检查其线程的中断位。
public void cooperative() {
try {
for (;;) {
Thread.sleep(500);
}
} catch (InterruptedException e) {
System.err.println("cooperative() interrupted");
} finally {
System.err.println("cooperative() finally");
}
}
public void noncooperative() {
try {
for (;;) {
Thread.yield();
}
} finally {
System.err.println("noncooperative() finally");
}
}
最后,我编写了测试(JUnit 4)来练习它们:
@Test
public void testStopCooperative() {
testStop(new Runnable() {
@Override
public void run() {
cooperative();
}
});
}
@Test
public void testStopNoncooperative() {
testStop(new Runnable() {
@Override
public void run() {
noncooperative();
}
});
}
我以前从未使用过 Thread.stop(),所以我不知道它的操作。它的工作原理是从目标线程当前正在运行的任何地方抛出一个 ThreadDeath 对象。这扩展了错误。因此,虽然它并不总是干净地工作,但它通常会使简单的程序具有相当合理的程序状态。例如,调用任何 finally 块。如果你想成为一个真正的混蛋,你可以抓住ThreadDeath(或错误),然后继续运行,无论如何!
如果不出意外,这真的让我希望更多的代码遵循 IProgressMonitor 方法 - 向可能需要一段时间的方法添加另一个参数,并鼓励方法的实现者偶尔轮询 Monitor 对象以查看用户是否希望系统提供向上。将来我会尝试遵循这种模式,尤其是可能是交互式的方法。当然,您不一定事先知道将以这种方式使用哪些方法,但我猜这就是 Profiler 的用途。
至于“完全启动另一个JVM”方法,这将需要更多的工作。我不知道是否有人编写了委托类加载器,或者是否包含在 JVM 中,但这种方法需要这样做。