У меня есть метод, который, концептуально, смотрит что-то как:
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-bound.
Пока неплохо, но теперь я хочу 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 (например), будет брошен, избегая уезжающих объектов в непоследовательных состояниях - но мне любопытно знать, существует ли более изящный способ сделать that*.
* В Java, не AspectJ, который я предполагаю, является очень соответствующим здесь, но я застреваю с Java.
Вы можете использовать интерфейс и динамический прокси:
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);
}
....
}
Правильно ли я понял, что вы последовательно запускаете методы, находящиеся на одном уровне вложенности? Если да, то почему бы просто не реализовать свои методы вычислений как экземпляры 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();
}
}
}
}
}