我正在通过ExecutorService运行某些外部方法的多次调用。我希望能够中断这些方法,但是不幸的是,它们不能自行检查中断标志。有什么办法可以强制从这些方法引发异常?
我知道从任意位置抛出异常是潜在的危险,在我的具体情况下,我愿意抓住这次机会并准备处理后果。
“外部方法”是指某些来自外部库的方法,并且我无法修改其代码(可以,但是,每当发布新版本时,这都会成为维护的噩梦)。
外部方法计算量大,不受IO限制,因此它们不响应常规中断,因此无法强制关闭通道或套接字等。如前所述,它们也不检查中断标志。
代码在概念上类似于:
// my code public void myMethod() { Object o = externalMethod(x); } // External code public class ExternalLibrary { public Object externalMethod(Object) { innerMethod1(); innerMethod1(); innerMethod1(); } private void innerMethod1() { innerMethod2(); // computationally intensive operations } private void innerMethod2() { // computationally intensive operations } }
Thread.stop()理论上将执行我想要的操作,但不仅不赞成使用它,而且还仅适用于实际线程,而我正在使用执行程序任务(例如,在线程池中工作时,它们也可能与将来的任务共享线程) 。不过,如果找不到更好的解决方案,我将把代码转换为使用老式线程,然后使用此方法。
Thread.stop()
我尝试过的另一种选择是myMethod()使用特殊的“ Interruptable”注释标记和类似的方法,然后使用AspectJ(我承认是新手)来捕获那里的所有方法调用-类似于:
myMethod()
@Before("call(* *.*(..)) && withincode(@Interruptable * *.*(..))") public void checkInterrupt(JoinPoint thisJoinPoint) { if (Thread.interrupted()) throw new ForcefulInterruption(); }
但是withincode它并不递归到匹配方法所调用的方法,因此我将不得不将此注释编辑到外部代码中。
withincode
我已经解决了我的问题的丑陋解决方案。它不是很漂亮,但是可以在我的情况下使用,因此我将其发布在这里,以防它对其他人有帮助。
我所做的是 分析 应用程序的库部分,希望我可以隔离一小部分被重复调用的方法,例如某些get方法equals()或类似的东西;然后我可以在其中插入以下代码段:
get
equals()
if (Thread.interrupted()) { // Not really necessary, but could help if the library does check it itself in some other place: Thread.currentThread().interrupt(); // Wrapping the checked InterruptedException because the signature doesn't declare it: throw new RuntimeException(new InterruptedException()); }
通过编辑库的代码手动插入它,或者通过编写适当的方面自动插入它。请注意,如果库尝试捕获并吞下一个RuntimeException,则抛出的异常可以替换为库未尝试捕获的其他内容。
RuntimeException
幸运的是,使用的VisualVM,我能找到一个 单一 的具体用法我正在图书馆的过程中调用了非常高数十倍方法。添加以上代码段后,它现在可以正确响应中断。
这当然是不可维护的,再加上什么也不能保证库在其他情况下会重复调用此方法。但这对我有用,并且由于配置其他应用程序并在其中插入检查相对容易,因此我认为这是一个通用的解决方案,尽管很难看。