问题描述
我通过 ExecutorService.我希望能够中断这些方法,但不幸的是它们不会自己检查中断标志.有什么办法可以强制从这些方法中引发异常?
I'm running multiple invocations of some external method via an ExecutorService. I would like to be able to interrupt these methods, but unfortunately they do not check the interrupt flag by themselves. Is there any way I can force an exception to be raised from these methods?
我知道从任意位置抛出异常是 潜在危险,在我的具体情况下,我愿意抓住这个机会并准备好应对后果.
I am aware that throwing an exception from an arbitrary location is potentially dangerous, in my specific case I am willing to take this chance and prepared to deal with the consequences.
我所说的外部方法"是指来自外部库的一些方法,我无法修改它的代码(我可以,但是每当发布新版本时,这都会使它成为维护噩梦).
By "external method" I mean some method(s) that come from an external library, and I cannot modify its code (well I can, but that will make it a maintenance nightmare whenever a new version is released).
外部方法的计算成本很高,不受 IO 限制,因此它们不会响应常规中断,而且我无法强制关闭通道或套接字或其他东西.正如我之前提到的,他们也不检查中断标志.
The external methods are computationally expensive, not IO-bound, so they don't respond to regular interrupts and I can't forcefully close a channel or a socket or something. As I've mentioned before, they also do not check the interrupt flag.
代码在概念上类似于:
// 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()
理论上会做我想要的,但它不仅被弃用,而且它也只可用于实际线程,而我正在处理执行程序任务(这也可能与未来的任务共享线程,例如在线程池中工作时).尽管如此,如果找不到更好的解决方案,我会将我的代码转换为使用老式线程来代替并使用此方法.
What I've Tried
Thread.stop()
will theoretically do what I want, but not only is it deprecated but it is also only available for actual threads, while I'm working with executor tasks (which might also share threads with future tasks, for example when working in a thread pool). Nevertheless, if no better solution is found, I will convert my code to use old-fashioned Threads instead and use this method.
我尝试过的另一个选项是用特殊的可中断"注释标记 myMethod()
和类似方法,然后使用 AspectJ(我承认我是新手)来捕获所有方法调用那里 - 类似:
Another option I've tried is to mark myMethod()
and similar methods with a special "Interruptable" annotation and then use AspectJ (which I am admittedly a newbie at) for catching all method invocations there - something like:
@Before("call(* *.*(..)) && withincode(@Interruptable * *.*(..))")
public void checkInterrupt(JoinPoint thisJoinPoint) {
if (Thread.interrupted()) throw new ForcefulInterruption();
}
但是 withincode
不会递归到匹配方法调用的方法,因此我必须将此注释编辑到外部代码中.
But withincode
isn't recursive to methods called by the matching methods, so I would have to edit this annotation into the external code.
最后,这类似于 我之前的一个问题 - 尽管值得注意不同的是,现在我正在处理一个外部库.
Finally, this is similar to a previous question of mine - though a notable difference is that now I'm dealing with an external library.
推荐答案
我找到了一个丑陋的解决方案来解决我的问题.它不是很漂亮,但对我来说很有效,所以我把它贴在这里,以防它对其他人有帮助.
I have hacked an ugly solution to my problem. It's not pretty, but it works in my case, so I'm posting it here in case it will help anyone else.
我所做的是分析我的应用程序的库部分,希望我可以隔离一小组重复调用的方法 - 例如一些 get
方法或equals()
或类似的东西;然后我可以在那里插入以下代码段:
What I did was profile the library parts of my application, hoping that I could isolate a small group of methods which are called repeatedly - for example some get
methods or equals()
or something along these lines; and then I could insert the following code segment there:
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
,则抛出的异常可能会替换为库未尝试捕获的其他内容.
Either inserting it manually by editing the library's code, or automatically by writing an appropriate aspect. Notice that if the library attempts to catch and swallow a RuntimeException
, the thrown exception could be replaced with something else the library doesn't try to catch.
幸运的是,使用 VisualVM,我能够找到单个在我对库的特定使用过程中,方法被调用的次数非常多.添加上述代码段后,现在可以正常响应中断了.
Luckily for me, using VisualVM, I was able to find a single method called a very high number of times during the specific usage I was making of the library. After adding the above code segment, it now properly responds to interrupts.
这当然是不可维护的,而且没有什么能真正保证库在其他场景中会重复调用这个方法;但它对我有用,而且由于分析其他应用程序并在那里插入检查相对容易,因此我认为这是一个通用的(虽然丑陋)解决方案.
This is of course not maintainable, plus nothing really guarantees the library will call this method repeatedly in other scenarios; but it worked for me, and since it's relatively easy to profile other applications and insert the checks there, I consider this a generic, if ugly, solution.
这篇关于如何使外部方法可中断?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!