取消动态加载的Callables我没写

时间:2012-07-24 19:51:53

标签: java concurrency classloader future callable

我有一些代码可以从目录中的几个JAR动态加载类。因为JAR中的代码是不可信的,所以我希望通过“沙盒化”来保护主应用程序免受编码不良或恶意的动态类的影响。我试图做的一件事是“timebox”不受信任的代码的执行,并且如果它花费的时间太长(例如因为它停留在无限循环中)就会杀死它。我正在尝试使用Callable和Future实现这一点,不是因为我想并行运行任务(我没有),而是利用完成的工作来提供返回值,捕获异常和取消正在运行的任务。但是,当我在一些测试代码上运行它时,我发现调用Future.cancel(true)似乎不会取消任务。

我在StackOverflow上看到了几个问题(such as this one),说明为什么会这样,答案总是一样的:取消(true)通过在运行Callable的线程上调用interrupt()来工作,要求取消之前取消的任务块在取消之前的中断()操作(如Thread.sleep())将生效。由于我不控制正在执行的代码,因此无法保证它会执行此操作,因此我无法确定是否已将其取消。

有没有什么方法可以运行动态加载的代码,然后在进行中杀死它并确保它死掉,即使它永远不会阻塞中断()ible操作?

// Assume: ExecutorService pool, Callable<T> task,
//  long timeout, TimeUnit timeUnit
Future<T> future = pool.submit(task);
T result;

try {
    result = future.get(timeout, timeUnit);
    // do something with result
} catch (TimeoutException ex) {
    future.cancel(true);
    // handle timeout
} catch (ExecutionException ex) {
    // handle exeception thrown by task
} catch (InterruptedException ex) {
    // handle InterruptedException
}

2 个答案:

答案 0 :(得分:3)

取消,或者更确切地说是线程中断,机制基本上是合作的,你无法阻止一个流氓任务。你唯一的选择,由于很多原因非常危险,是Thread.stop()他们。

答案 1 :(得分:1)

Thread.stopThread.destroy旁边,您可以进行终极沙盒操作,在Process p = Runtime.getRuntime().exec( cmd );的子进程中生成整个JVM。使用Process.destroy if necessary.

可以真正破坏该过程

为了简化流程创建,请使用ProcessBuilder。另外,查看可用的教程(this one is in french)来执行进程,等到完成(使用waitFor),然后管理流。

我已经看到它在我们需要将ps文档转换为pdf的产品中工作。我们正在转储ps文件,执行ps2pdf,然后读取输出文件。

Process的优点/缺点:

  • (+)真正沙盒化为一个单独的过程
  • ( - )之间的沟通 JVM难以处理
  • ( - )使应用程序的部署变得复杂 (JVM的路径,选项,当前目录等)

请注意,Thread.stopThread.destroy(我不确定它是否已实际实施)是不受欢迎的,因为它们在锁定获取和释放方面不安全。确保你阅读Why Are Thread.stop, Thread.suspend, Thread.resume and Runtime.runFinalizersOnExit Deprecated?如果在一个单独的线程中运行的不受信任的模块没有弄乱应用程序的锁,只有在最坏的情况下有自己的锁,那么Thread.stop可能仍然是最好的选择。

Thread.stop

的利弊
  • (+)易于使用
  • (+)可信和不受信任的代码之间的通信很容易
  • ( - )已弃用
  • ( - )在某些必须首先评估的特定情况下可能不安全