我有一些代码可以从目录中的几个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
}
答案 0 :(得分:3)
取消,或者更确切地说是线程中断,机制基本上是合作的,你无法阻止一个流氓任务。你唯一的选择,由于很多原因非常危险,是Thread.stop()
他们。
答案 1 :(得分:1)
在Thread.stop
和Thread.destroy
旁边,您可以进行终极沙盒操作,在Process p = Runtime.getRuntime().exec( cmd );
的子进程中生成整个JVM。使用Process.destroy if necessary.
为了简化流程创建,请使用ProcessBuilder
。另外,查看可用的教程(this one is in french)来执行进程,等到完成(使用waitFor
),然后管理流。
我已经看到它在我们需要将ps文档转换为pdf的产品中工作。我们正在转储ps文件,执行ps2pdf
,然后读取输出文件。
Process
的优点/缺点:
请注意,Thread.stop
和Thread.destroy
(我不确定它是否已实际实施)是不受欢迎的,因为它们在锁定获取和释放方面不安全。确保你阅读Why Are Thread.stop, Thread.suspend,
Thread.resume and Runtime.runFinalizersOnExit Deprecated?如果在一个单独的线程中运行的不受信任的模块没有弄乱应用程序的锁,只有在最坏的情况下有自己的锁,那么Thread.stop
可能仍然是最好的选择。
Thread.stop