我一直在使用ExecutorCompletionService中的示例代码,并将以下示例代码放在一起。 resolve()中的代码按预期工作并打印1
2
3
4
5
resolve2()中的代码不输出任何内容,并且实际上从不退出。在将作业提交给ExecutionService之前或之后构造ecs都没有关系。
没有办法在FutureTasks中使用CompletionService构造吗?我已经将生产代码重写为直接将FutureTask的结果获取(),而不是尝试从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);
}
}
最佳答案
在solve2
中,当使用现有的ExecutorCompletionService
创建ExecutorService
时,包装程序将忽略其提交的任务,因为它使用单独的LinkedBlockingQueue
。提交的任务不会被继承。因此,当您执行ecs.take().get();
时,您的代码会阻塞,因为ExecutorCompletionService
本身没有任何已提交的任务。
另外,您无需专门创建FutureTask即可提交到ExecutorCompletionService
。这些“未来”任务已经在内部为您创建。这就是为什么在调用Future<String>
时得到ecs.take();
的原因。
鉴于此,您的solve2
函数完全没有用。您已经在solve1
中正确地进行了操作。