5

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

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。

4

2 回答 2

7

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

public class Wrapper {
    public static <T> T wrap(Class<T> 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);
    }

    ....
}
于 2010-07-05T11:14:29.983 回答
0

我是否正确地理解了您顺序运行处于同一嵌套级别的方法?如果是这样,为什么不将计算方法实现为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<CompoundProcess> subProcesses1 = new ArrayList<CompoundProcess>();
        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<CompoundProcess> subProcesses2 = new ArrayList<CompoundProcess>();
        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<CompoundProcess> processes1 = new ArrayList<CompoundProcess>() {};
        processes1.add(new CompoundProcess(subProcesses1));
        processes1.add(new CompoundProcess(subProcesses2));

        CompoundProcess process = new CompoundProcess(processes1);
        process.run();
    }


    static class CompoundProcess implements Runnable {

        private List<CompoundProcess> processes = new ArrayList<CompoundProcess>();

        public CompoundProcess() {
        }

        public CompoundProcess(List<CompoundProcess> processes) {
            this.processes = processes;
        }

        public void run() {
            for (Runnable process : processes) {
                if (Thread.interrupted()) {
                    throw new RuntimeException("The processing was interrupted");
                } else {
                    process.run();
                }
            }
        }
    }

}
于 2010-07-05T11:47:53.287 回答