使用Callbable与Runnable的“ExecutorCompletionService”时出现问题

时间:2009-12-11 14:34:50

标签: java concurrency executorservice

我一直在使用ExecutorCompletionService中的示例代码,并将以下示例代码放在一起。 solve()中的代码按预期工作并打印
1
2
3
4
5
solve2()中的代码不会打印任何内容,实际上永远不会退出。是否在将作业提交到ExecutionService之前或之后构建了ecs并不重要。

没有办法在FutureTasks中使用CompletionService构造吗?我已经重写了我的生产代码以直接获取()FutureCask的结果,而不是尝试从ExecutorCompletionService获取()它们,但它(当前)导致了一些看起来很乱的东西。简而言之,下面的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);
}

}

2 个答案:

答案 0 :(得分:3)

solve2中,当您使用现有ExecutorCompletionService创建ExecutorService时,包装器会忽略提交的任务,因为它使用单独的LinkedBlockingQueue。提交的任务不会被继承。因此,当您执行ecs.take().get();时,您的代码会阻塞,因为ExecutorCompletionService本身没有提交任何任务。

此外,您无需专门创建FutureTask即可提交给ExecutorCompletionService。这些Future任务已经在内部为您创建。这就是您在致电Future<String>时获得ecs.take();的原因。

鉴于此,您的solve2功能完全没用。您已在solve1中正确执行此操作。

答案 1 :(得分: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的包装器,但您必须将您的callables提交给ECS,因为ECS将获取可调用的结果,将其放入队列。然后可以通过take()或poll()获得此结果。 如果直接在ExecutorService上提交可调用对象,则ECS无法知道其完成情况。 如果你看一下ECS的javadoc,就会说出完全相同的东西+很好的例子(更好的解释)。我建议你也看看源代码java.util.concurrent.ExecutorCompletionService