如何编写可中断的方法

我有一个方法,从概念上看,它看起来像:

Object f(Object o1) { Object o2 = longProcess1(o1); Object o3 = longProcess2(o2); return longProcess3(o3); } 

过程本身也可能是复合的:

 Object longProcess1(Object o1) { Object o2 = longSubProcess1(o1); return longSubProcess2(o2); } 

等等,不同的过程可能存在于不同的模块中。 大多数进程都很长,因为它们计算成本高,而不是IO绑定。

到目前为止一切都那么好,但现在我希望f作为一个整体可以打断。 推荐的Java方法是使用Thread.interrupted()定期检查中断的标志。 它非常简单,但如果我需要将我的方法更改为以下内容,它很快就会变得很麻烦:

 Object f(Object o1) { Object o2 = longProcess1(o1); if (Thread.interrupted()) throw new InterruptedException(); Object o3 = longProcess2(o2); if (Thread.interrupted()) throw new InterruptedException(); return longProcess3(o3); } Object longProcess1(Object o1) { Object o2 = longSubProcess1(o1); if (Thread.interrupted()) throw new InterruptedException(); return longSubProcess2(o2); } ... 

现在, 我确实理解了这样工作的理性 – 它允许我更好地控制何时抛出InterruptedException(例如),避免让对象处于不一致的状态 – 但我很想知道是否有更优雅的做法*

*在Java中,不是AspectJ,我认为这是非常合适的,但我坚持使用Java。

您可以使用接口和动态代理:

 public class Wrapper { public static  T wrap(Class intf, final T impl) { ClassLoader cl = Thread.currentThread().getContextClassLoader(); Object proxy = Proxy.newProxyInstance(cl, new Class[] {intf}, new InvocationHandler() { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (Thread.interrupted()) { throw new InterruptedException(); } return method.invoke(impl, args); } }); return intf.cast(proxy); } } interface Processes { Object longProcess1(Object o); ... } public class ProcessesImpl implement Processes { Processes self = Wrapper.wrap(Processes.class, this); public Object f(Object o1) { Object o2 = self.longProcess1(o1); Object o3 = self.longProcess2(o2); return self.longProcess3(o3); } public Object longProcess1(Object o1) { Object o2 = self.longSubProcess1(o1); return self.longSubProcess2(o2); } .... } 

我是否正确地按顺序运行处于相同嵌套级别的方法? 如果是这样,为什么不将你的计算方法实现为java.lang.Runnable实例,将它们组织成列表并在循环中启动它们? 那么你只有一个地方有Thread.interrupted()检查。

您可以考虑使用java.util.concurrent.ExecutorService来促进对计算任务的控制。

更新了一个示例:

 import java.util.ArrayList; import java.util.List; public class Test { public static void main(String[] args) { List subProcesses1 = new ArrayList(); subProcesses1.add(new CompoundProcess() { public void run() { System.out.println("Process 1.1"); } }); subProcesses1.add(new CompoundProcess() { public void run() { System.out.println("Process 1.2"); } }); List subProcesses2 = new ArrayList(); subProcesses2.add(new CompoundProcess() { public void run() { System.out.println("Process 2.1"); } }); subProcesses2.add(new CompoundProcess() { public void run() { System.out.println("Process 2.2"); } }); List processes1 = new ArrayList() {}; processes1.add(new CompoundProcess(subProcesses1)); processes1.add(new CompoundProcess(subProcesses2)); CompoundProcess process = new CompoundProcess(processes1); process.run(); } static class CompoundProcess implements Runnable { private List processes = new ArrayList(); public CompoundProcess() { } public CompoundProcess(List processes) { this.processes = processes; } public void run() { for (Runnable process : processes) { if (Thread.interrupted()) { throw new RuntimeException("The processing was interrupted"); } else { process.run(); } } } } }