1

ExecutorCompletionService のサンプル コードを使用して、次のサンプル コードをまとめました。solve() のコードは期待どおりに動作し、出力され ます。 solve2() のコードは何も出力せず、実際には終了しません。ジョブを ExecutionService に送信する前または後に ecs を構築するかどうかは問題ではありません。
1
2
3
4
5

FutureTasks で CompletionService コンストラクトを使用する方法はありませんか? ExecutorCompletionService から get() しようとするのではなく、FutureTask の結果を直接 get() するように本番コードを書き直しましたが、(現在) 見た目がややこしいものになっています。要するに、以下のsolve2の何が問題になっていますか? ありがとう。

import java.util.ArrayList;
import java.util.Collection;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletionService;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;

public class sample {
public static class stringCallable implements Callable<String>{
    String mstring;

    stringCallable(String s) {mstring = s;}
    @Override
    public String call() throws Exception {
        // TODO Auto-generated method stub
        return mstring;
    }
};

public static void main(String[] args) {
    // TODO Auto-generated method stub
    ArrayList<Callable<String>> list = new ArrayList<Callable<String>>();
    ExecutorService es = Executors.newFixedThreadPool(1);
    Executor e = Executors.newSingleThreadExecutor();
    list.add(new stringCallable("1"));
    list.add(new stringCallable("2"));
    list.add(new stringCallable("3"));
    list.add(new stringCallable("4"));
    list.add(new stringCallable("5"));

    try {
        solve(e, list);
    } catch (InterruptedException e1) {
        // TODO Auto-generated catch block
        e1.printStackTrace();
    } catch (ExecutionException e1) {
        // TODO Auto-generated catch block
        e1.printStackTrace();
    }
    System.out.println ("Starting Solver 2");

    try {
        solve2(es, list);
    } catch (InterruptedException e1) {
        // TODO Auto-generated catch block
        e1.printStackTrace();
    } catch (ExecutionException e1) {
        // TODO Auto-generated catch block
        e1.printStackTrace();
    }
}

static void solve(Executor e, Collection<Callable<String>> solvers)throws InterruptedException, ExecutionException {
    CompletionService<String> ecs = new ExecutorCompletionService<String>(e);
    for (Callable<String> s : solvers)
     ecs.submit(s);
    int n = solvers.size();
    for (int i = 0; i < n; ++i) {
        String r = ecs.take().get();
        if (r != null)
            use(r);
    }
}

static void solve2(ExecutorService e, Collection<Callable<String>> solvers)throws InterruptedException, ExecutionException {
    for (Callable<String> s : solvers){
        FutureTask<String> f = new FutureTask<String>(s);
          e.submit(f);
    }
    CompletionService<String> ecs = new ExecutorCompletionService<String>(e);
    int n = solvers.size();
    for (int i = 0; i < n; ++i) {
        String r = ecs.take().get();
        if (r != null)
            use(r);
    }
}

private static void use(String r) {
    System.out.println (r);
}

}

4

2 に答える 2

3

では、既存の を使用してsolve2を作成すると、別の を使用するため、サブミットされたタスクはラッパーによって無視されます。サブミットされたタスクは継承されません。したがって、それ自体にはサブミットされたタスクがないため、コードはブロックされます。ExecutorCompletionServiceExecutorServiceLinkedBlockingQueueecs.take().get();ExecutorCompletionService

また、に送信するための FutureTask を特に作成する必要はありませんExecutorCompletionService。これらの将来のタスクは、内部で既に作成されています。そのため、Future<String>を呼び出したときにが得られますecs.take();

これを考えると、あなたのsolve2機能はまったく役に立ちません。ですでに正しく実行していsolve1ます。

于 2009-12-11T15:27:05.893 に答える
0

これは私がそれを実装する方法です:

static void solve2(ExecutorService e, Collection<Callable<String>> solvers)throws InterruptedException, ExecutionException {
    CompletionService<String> ecs = new ExecutorCompletionService<String>(e);
    for (Callable<String> s : solvers){
        ecs.submit(s);
    }
    int n = solvers.size();
    for (int i = 0; i < n; ++i) {
        String r = ecs.take().get();
        if (r != null)
            use(r);
    }
}

ExecutorCompletionService は ExecutorService の「単なる」ラッパーですが、ECS は callable の結果を取得してキューに配置するため、callable を ECS に送信する必要があります。この結果は、take() または poll() を介して取得できます。ExecutorService で callable を直接送信すると、ECS はその完了を認識できません。ECSのjavadocを見ると、まったく同じこと+良い例(さらに良い説明)が書かれています。ソースコード java.util.concurrent.ExecutorCompletionService も参照することをお勧めします。

于 2009-12-11T15:18:03.710 に答える