当我使用Java开发一个(学术)软件时,我被迫使用一个执行得相当糟糕的API。这意味着对某一组输入数据的此API调用有时永远不会返回。这一定是软件中的一个错误,因为它提供的算法是确定性的,有时会终止于一组数据,有时它会在同一组数据上遇到无限循环......
但是,修复API或重新实现它只是超出了范围。我甚至拥有源代码,但API很大程度上依赖于其他未记录且没有源代码的API,并且当时从网络上消失(或者从未在那里?)。另一方面,这个“坏”API是解决我遇到的具体问题的唯一一个,所以我真的不得不坚持下去。
问题是:处理API的最干净的方法是什么呢?好吧,讨厌?当我遇到这个问题时,我决定将对API的调用放入一个单独的线程中。然后,另一个线程偶尔会检查此线程是否已终止。如果已经过了一定的时间,我会使用Thread#stop()
终止处理线程并再次开始处理,希望它会在下次返回。现在,我知道(并且当时知道)该方法已被弃用,不得使用。但是在这种学术背景下,让潜在软件运行到未定义状态而不是让它崩溃是可以接受的。
仅忽略已经遇到无限循环的处理线程也是不可接受的,因为它做了一些CPU密集型操作,这会大大减慢用户的机器速度。
我没有尝试的另一种方法是在单独的进程而不是线程中开始处理,因为可以干净地杀死子进程而不会使软件处于不一致状态。或者新的SwingWorker
类(尚未提供)可以完成这项工作吗?它有一个cancel()
方法,但是文档说它“尝试取消执行此任务”,所以它看起来也不像是一种可靠的方法。
答案 0 :(得分:11)
我建议使用单独的流程。除非第二个线程定期检查它是否被中断,否则一个线程基本上没有安全的方法来杀死Java中的第二个线程。
理想的解决方案是使用分离株。隔离本质上是Java应用程序可以创建,管理和通信的私有虚拟机。特别是,父应用程序可以安全地杀死隔离及其所有线程。
参考:JSR-000121 Application Isolation API Specification - Final Release
问题是找到支持隔离的JVM。
答案 1 :(得分:5)
我非常喜欢这种事情的独立流程。
生成子流程并等待结果。
如果API是非确定性的,请将计时器线程放在一个包装器中,使得错误的API成为主程序。
这样,子进程总是在给定时间内结束。它产生一个有用的结果或一个指示失败的系统退出代码。
答案 2 :(得分:2)
@ S.Lott和@Stephen C的答案都是关于如何处理这种情况的,但我想补充一点,在非学术环境中,你也应该考虑更换API尽快实用。在我们被锁定在一个糟糕的API中的情况下,通常是出于其他原因选择一个售卖的解决方案,我已经努力用我自己的功能替换它。您的客户不会像您的教授一样宽容,因为他们实际上必须使用您的软件(或不是!)而不仅仅是评级。
在某些情况下,使用胶带是解决问题的适当选择。但是当它导致你所描述的这种不良行为时,最好不要太长时间依赖它并开始进行真正的修复。
答案 3 :(得分:1)
最佳要做的事情就是重新实施相关API。但是,正如你所说,这是一个非常重要的,可能是超出范围的解决方案。
下一个最佳的事情是尽可能包装API。基本上,如果您可以提前确定导致失败的数据集的内容,则可以拒绝调用以保证确定性。这听起来并不适用于你,因为你建议重复使用相同数据集的调用有时会在先前的调用中无限循环时终止。
鉴于上述选项不可用:
我认为您的当前线程解决方案是最糟糕的选择。对于方法调用来说,启动一个进程似乎太重了,从性能的角度来看是可以接受的,即使它比使用线程更安全。 Thread.stop()非常危险,但如果你虔诚地阻止任何锁定,你就可以逃脱它。