如何杀死不可中断的线程?

我们举办了一场AI编程竞赛,参赛者将使用我们提供的API编写在JVM上运行的AI 。 我们通过限制它们可以用SecurityManager做什么来将它们放入沙箱中,并且在运行时它们只是设置了几个标志,这是他们的决定。 我们的系统和他们的AI之间唯一的交互是通过这些标志,所以如果他们的线程突然死亡,对我们没有任何不良影响。

AI计算时间太长时,我们想关闭他们的线程。 但是,我们无法找到保证我们将销毁其线程的方法。 一个可能的原因是AI进入无限循环而没有阻塞,使得Thread.interrupt()无用。 Thread.stop()是不可靠的,因为如果它们在try catch块中, ThreadDeathexception将被捕获,并且对我们没有任何问题,因为它们没有触及任何坏事,我们不关心它们是否死亡。

目前我们只是忽略他们的线程并在超时之后继续它们,但是它们的无限循环将继续在后台处理直到JVM死掉。 这对我们来说是不可接受的,因为我们将在24/7的Web服务器上在后台运行匹配,因此我们希望尽可能多的稳定性。 一种想法是在一个单独的JVM运行每个游戏,但这比我们想要的要复杂得多。

是否有任何确定的消防方法来摧毁线程?

为他们提供他们必须定期调用的方法,即使在计算过程中也是如此。 如果你判断他们已经“死了”,那么这个方法就会永远沉睡。 显然,如果他们真的死了,他就行不通,但你应该抓住大多数问题。

http://docs.oracle.com/javase/6/docs/api/java/lang/Thread.html#stop%28java.lang.Throwable%29

传入他们无法了解的Throwable的自定义子类,并且可以使用正则表达式检查他们的代码: /catch\s*(\s*Throwable/以确保它们不会在任何地方捕获Throwable。

通常,不,您不应该停止JVM中的任意线程(因此不推荐使用这些方法)。 问题的根源在于,当您杀死线程时,您不知道线程在系统中的哪个位置。 在最糟糕的情况下,它可能位于JVM基础结构内部的同步块的中间,该块未准备好引发意外exception。 (几乎不可能编写可以在任意点被exception杀死的健壮的同步代码。)

有关更多详细信息,请参阅此问题的高评价答案: Java app服务器是否能够销毁线程? 如果有,怎么样?

您可以通过合作设计逃脱,要求AI线程退出。 如果确实如此,那你很好。 如果没有,则需要重新启动JVM。

在尝试了几件事之后,我们得出的结论是没有保证的解决方案。 通过在线程上调用stop(),该线程能够捕获ThreadDeath throwable并完全忽略它。 因此,如果它在while循环中连续捕获它,或者如果它以递归方式调用捕获它的方法,则不能保证可以杀死它。

由于我们无法控制在这种情况下运行的代码,并且该代码不一定是Java(我们也支持Jython),我们可以提出的最佳解决方案是生成一个进入的线程一个循环,在线程上连续调用suspend()然后stop()。 结果适用于大多数情况,但偶尔无法杀死恶意线程。