2009-12-11 75 views
1

我一直在使用来自ExecutorCompletionService的示例代码,并将以下示例代码放在一起。 solve()中的代码按预期工作并打印
1
2
3
4
5
solve2()中的代码不会打印任何内容,实际上也不会退出。在将作业提交给ExecutionService之前或之后构建ecs是无关紧要的。使用“ExecutorCompletionService”与Callbable与Runnable的问题

是否没有办法在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); 
} 

}

回答

3

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

另外,您不需要专门创建FutureTask来提交到ExecutorCompletionService。这些未来任务已经在内部为您创建。这就是为什么当致电ecs.take();时你得到Future<String>

鉴于此,您的solve2函数是完全无用的。您已在solve1中正确执行此操作。

+0

谢谢。解决直接来自Java网站。一个同事,我无法弄清楚为什么第二个版本(这基本上是我们在我们的代码中做的)是行不通的。谢谢! – Jim 2009-12-14 15:50:15

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,作为ECS会将可调用的结果放入队列中。这个结果可以通过take()或poll()来获得。 如果您直接在ExecutorService上提交可调用对象,ECS无法了解其完成情况。 如果你看看ECS的javadoc,它说的是完全相同的东西+很好的例子(甚至更好的解释)。我建议你也去看看源代码java.util.concurrent.ExecutorCompletionService

+0

是的,ECS javadocs是我从中获得第一个解决方案的地方,但是我们对FutureTask的事情有了一个先入为主的观点。 谢谢! – Jim 2009-12-14 15:52:27