如何将您的程序与“坏”API的调用隔离开来?

当我使用Java开发一个(学术)软件时,我被迫使用一个执行得相当糟糕的API。 这意味着对某一组输入数据的此API调用有时永远不会返回。 这一定是软件中的一个错误,因为它提供的算法是确定性的,有时会终止于一组数据,有时它会在同一组数据上遇到无限循环……

但是,修复API或重新实现它只是超出范围。 我甚至拥有源代码,但API严重依赖于其他API,这些API没有文档,没有源代码,并且从网络上消失(或者从未在那里?)。 另一方面,这个“坏”的API是解决我遇到的具体问题的唯一一个,所以我真的不得不坚持下去。

问题是:处理API的最干净的方法是什么呢?好吧,讨厌? 当我遇到这个问题时,我决定将对API的调用放入一个单独的线程中。 然后,另一个线程偶尔会检查此线程是否已终止。 如果已经过了一定的时间,我会使用Thread#stop()处理线程并再次开始处理,希望它会在下次返回。 现在,我知道(并且当时知道)该方法已被弃用,不得使用。 但是在这种学术背景下,让软件潜在地进入未定义状态而不是崩溃是可以接受的。

忽略已经遇到无限循环的处理线程也是不可接受的,因为它做了一些CPU密集型操作,这会大大减慢用户的机器速度。

我没有尝试的另一种方法是在单独的进程而不是线程中开始处理,因为可以干净地杀死子进程而不会使软件处于不一致状态。 或者新的SwingWorker类(尚未提供)是否完成了这项工作? 它有一个cancel()方法,但文档说“尝试取消执行此任务” ,所以它看起来也不像是一种可靠的方法。

我建议使用一个单独的过程。 除非第二个线程定期检查它是否已被中断,否则一个线程基本上没有安全的方法来杀死Java中的第二个线程。

理想的解决方案是使用分离株。 隔离本质上是Java应用程序可以创建,管理和通信的私有虚拟机。 特别是,父应用程序可以安全地杀死隔离及其所有线程。

参考: JSR-000121应用程序隔离API规范 – 最终版本

问题是找到支持Isolates的JVM。

我非常喜欢这种事情的独立流程。

产生一个子过程并等待结果。

如果API是非确定性的,则将计时器线程放在一个包装器中,使得错误的API成为主程序。

这样,子进程总是在给定时间内结束。 它要么产生有用的结果,要么产生指示失败的系统退出代码。

关于如何处理这种情况,@ S.Lott和@Stephen C的答案都是正确的,但我想补充一点,在非学术环境中,你也应该尽快替换API实际上。 在我们被锁定在一个糟糕的API中的情况下,通常是出于其他原因选择一个售卖的解决方案,我已经努力用我自己的function替换它。 您的客户不会像您的教授一样宽容,因为他们实际上必须使用您的软件(或不是!)而不仅仅是评级。

当然,使用胶带是解决问题的适当选择。 但是当它导致你描述的这种不良行为时,最好不要太长时间依赖它并开始进行真正的修复。

最好的办法是重新实现有问题的API。 但是,正如你所说,这是一个非常重要的,可能是超出范围的解决方案。

如果可能的话, 下一个最好的事情就是包装API。 基本上,如果您可以提前确定导致失败的数据集是什么,您可以拒绝保证确定性的调用。 听起来这听起来不适合你,因为你建议重复使用相同数据集的调用有时会在先前的调用中无限循环时终止。

鉴于上述选项不可用:
我认为您当前的线程解决方案最糟糕的选择 。 对于方法调用来说,启动一个进程似乎太重了,从性能的角度来看是可以接受的,即使它比使用线程更安全。 Thread.stop()是非常危险的,但如果你虔诚地阻止任何锁定,你可以逃脱它。