做得漂亮:同时处理数组

时间:2009-05-27 07:02:56

标签: java multithreading concurrency

我想将此线性循环转换为并发循环:

for(Item item : ItemList) {
    processItem(item);
}

这真的是最短的方式吗?

class Worker implements Runnable {
    Item item;
    Worker(Item item) {
        this.item = item;
    }
    public void Run() {
        processItem(item);
    }
}

ExecutorService exec = Executors.newFixedThreadPool(THREADPOOL_SIZE);
for(Item item : ItemList) {
    exec.execute(new Worker(item));
}
exec.shutdown();

boolean properFinish = false;
try {
    properFinish = exec.awaitTermination(50, TimeUnit.SECONDS);
} catch (InterruptedException e) { 
    Thread.currentThread().interrupt();
}

具体来说,我想要一种使用匿名类的方法,但实际上,任何使这种更短且更易读的方法都会受到赞赏。

更新:刚刚意识到我有点愚蠢,因为在这个例子中使用匿名类非常容易:

for(final Item item : ItemList) {
    exec.execute(new Runnable() {
        public void run() {
            processItem(item);
        }
    });
}

在我的原始代码中,循环是一个简单的for (i=0; i<=ItemList.length(); i++),我无法想出以任何有意义的方式使我成为最终的方法。我想使用“for each”循环可以使情况更好。

还是,还有什么方法可以摆脱其余的样板吗?

更新2 :使用ExecutorCompletionService,假设processItem返回结果。

ExecutorService exec = Executors.newFixedThreadPool(THREADPOOL_SIZE);
CompletionService<ResultType> ecs = new ExecutorCompletionService<ResultType>(executor);
for(final Item item : ItemList) {
    ecs.submit(new Callable<ResultType>() {
        public ResultType call() {
            return processItem(item);
        }
    });
}

for(Item item : item) {
    // Do whatever with the results
    ecs.take().get();
}

这确实看起来更好。

2 个答案:

答案 0 :(得分:7)

查看JDK 6中的 ExecutorCompletionService - 而不是旋转自己的。它允许您为分配的任务执行多个线程,并在处理时获取每个线程的结果。

答案 1 :(得分:1)

如果您确实需要结果,并希望它们与提交的顺序相同,那么可能会执行以下操作:

List<Future<ResultType>> futures = new ArrayList<Future<ResultType>>();
for(final Item item : items) {
  futures.add(executor.submit(...))
}
List<ResultType> results = new ArrayList<ResultType>();
for(Future<ResultType> future : futures) {
  results.add(future.get());
}
return results;

编辑:如果你有一些过度工程,你可以返回一个迭代器,而不是做第二个循环(这样调用者可以在所有可用之前开始处理结果):

return Iterators.transform(results, new Function<Future<ResultType>,ResultType>() {
   public ResultType apply(Future<ResultType> future) {
       return future.get();
   }
})

使用google collection库中的“Iterators”。另一种可能性是返回Futures列表并让调用者等待。