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()チェックのある場所は1つだけになります。

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 に答える