Как записать прерываемые методы

У меня есть метод, который, концептуально, смотрит что-то как:

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.

5
задан Oak 5 July 2010 в 11:55
поделиться

2 ответа

Вы можете использовать интерфейс и динамический прокси:

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);
    }

    ....
}
7
ответ дан 14 December 2019 в 08:40
поделиться

Правильно ли я понял, что вы последовательно запускаете методы, находящиеся на одном уровне вложенности? Если да, то почему бы просто не реализовать свои методы вычислений как экземпляры 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();
                }
            }
        }
    }

}
0
ответ дан 14 December 2019 в 08:40
поделиться
Другие вопросы по тегам:

Похожие вопросы: