Java 如何使外部方法可中断? 问题
我正在通过一个。我希望能够中断这些方法,但不幸的是,它们自己并没有检查中断标志。有没有办法强制从这些方法引发异常 我知道,在我的具体情况下,从任意位置抛出异常是我愿意抓住这个机会并准备处理后果的 细节 我所说的“外部方法”是指一些来自外部库的方法,我不能修改它的代码(我可以,但只要发布新版本,它就会成为维护的噩梦) 外部方法的计算成本很高,不受IO限制,因此它们不会对常规中断做出响应,我也无法强制关闭通道、套接字或其他东西。正如我前面提到的,它们也不检查中断标志 该代码在概念上类似于:Java 如何使外部方法可中断? 问题,java,multithreading,aop,aspectj,executorservice,Java,Multithreading,Aop,Aspectj,Executorservice,我正在通过一个。我希望能够中断这些方法,但不幸的是,它们自己并没有检查中断标志。有没有办法强制从这些方法引发异常 我知道,在我的具体情况下,从任意位置抛出异常是我愿意抓住这个机会并准备处理后果的 细节 我所说的“外部方法”是指一些来自外部库的方法,我不能修改它的代码(我可以,但只要发布新版本,它就会成为维护的噩梦) 外部方法的计算成本很高,不受IO限制,因此它们不会对常规中断做出响应,我也无法强制关闭通道、套接字或其他东西。正如我前面提到的,它们也不检查中断标志 该代码在概念上类似于: // m
// 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
}
}
@Before("call(* *.*(..)) && withincode(@Interruptable * *.*(..))")
public void checkInterrupt(JoinPoint thisJoinPoint) {
if (Thread.interrupted()) throw new ForcefulInterruption();
}
@Before("call(* *.*(..)) && withincode(@Interruptable * *.*(..))")
public void checkInterrupt(JoinPoint thisJoinPoint) {
if (Thread.interrupted()) throw new ForcefulInterruption();
}
我试过的
从理论上讲,它可以做我想做的事情,但它不仅已被弃用,而且仅适用于实际的线程,而我正在处理执行器任务(也可能与将来的任务共享线程,例如在线程池中工作时)。然而,如果找不到更好的解决方案,我会将代码转换为使用老式线程,并使用此方法
我尝试过的另一个选择是用一个特殊的“可中断”注释标记myMethod()
和类似的方法,然后使用AspectJ(我承认我是新手)捕获那里的所有方法调用,比如:
// 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
}
}
@Before("call(* *.*(..)) && withincode(@Interruptable * *.*(..))")
public void checkInterrupt(JoinPoint thisJoinPoint) {
if (Thread.interrupted()) throw new ForcefulInterruption();
}
@Before("call(* *.*(..)) && withincode(@Interruptable * *.*(..))")
public void checkInterrupt(JoinPoint thisJoinPoint) {
if (Thread.interrupted()) throw new ForcefulInterruption();
}
但是withincode
对于匹配方法调用的方法不是递归的,因此我必须将此注释编辑到外部代码中
最后,这类似于-尽管一个显著的区别是我现在处理的是一个外部库。如果内部方法具有类似的名称,那么您可以使用xml(spring/AspectJ)中的切入点定义而不是注释,因此不需要对外部库进行代码修改。这个解决方案也不容易,但是它可以工作:使用Javassist或CGLIB,您可以在每个内部方法(可能是由main run()方法调用的方法)的开头插入代码,以检查线程是否处于活动状态,或者其他标志(如果是其他标志,您还必须添加它,以及设置它的方法)
我建议使用Javassist/CGLIB,而不是通过代码扩展类,因为您提到它是外部的,您不想更改源代码,而且将来可能会更改。因此,在运行时添加中断检查将适用于当前版本,也适用于将来的版本,即使内部方法名称发生更改(或其参数、返回值等)。您只需使用该类并在每个非run()方法的方法的开头添加中断检查。我想到了以下奇怪的想法:
- 使用字节码修改库,如Javassist,在字节码的各个点引入中断检查。仅仅在方法的开头可能是不够的,因为您提到这些外部方法不是递归的,所以您可能希望在任何时候强制停止它们。在字节码级别执行此操作也将使其具有非常高的响应性,例如,即使外部代码在循环中运行,也可能引入中断检查。但是,这会增加一些开销,因此总体性能会变慢
- 为外部代码启动单独的进程(例如单独的VM)。中止进程可能比其他解决方案更容易编码。缺点是您需要外部代码和您的代码之间的某种通信通道,例如IPC、套接字等。第二个缺点是您需要更多的资源(CPU、内存)来启动新的虚拟机,并且可能是特定于环境的。如果您使用外部代码启动几个任务,而不是数百个任务,那么这将起作用。此外,性能也会受到影响,但计算本身将与原始计算一样快。可以使用java.lang.Process.destroy()强制停止进程
- 使用自定义安全管理器,该管理器对每个checkXXX方法执行中断检查。如果外部代码以某种方式调用特权方法,您可以在这些位置中止。例如,如果外部代码定期读取系统属性,则java.lang.SecurityManager.checkPropertyAccess(String)就是一个例子
id
字段,您将能够识别执行它的线程。)@Before("call(* *.*(..)) && withincode(@Interruptable * *.*(..))")
public void checkInterrupt(JoinPoint thisJoinPoint) {
if (Thread.interrupted()) throw new ForcefulInterruption();
}