首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >使用线程池多线程在for-循环中完成的工作。

使用线程池多线程在for-循环中完成的工作。
EN

Stack Overflow用户
提问于 2014-03-12 19:10:45
回答 3查看 5.1K关注 0票数 2

假设我有以下代码,我不想通过将工作负载分散到我的PC的多个CPU核上来优化它:

代码语言:javascript
运行
复制
double[] largeArray = getMyLargeArray();
double result = 0;
for (double d : largeArray)
    result += d;
System.out.println(result);

在本例中,我可以在多个线程上分发for-循环中完成的工作,并在继续打印result之前验证线程是否都已结束。因此,我想出了一个类似这样的东西:

代码语言:javascript
运行
复制
final double[] largeArray = getMyLargeArray();
int nThreads = 5;
final double[] intermediateResults = new double[nThreads];

Thread[] threads = new Thread[nThreads];
final int nItemsPerThread = largeArray.length/nThreads;
for (int t = 0; t<nThreads; t++) {
    final int t2 = t;
    threads[t] = new Thread(){
        @Override public void run() {
            for (int d = t2*nItemsPerThread; d<(t2+1)*nItemsPerThread; d++)
                intermediateResults[t2] += largeArray[d];
        }
    };
}
for (Thread t : threads)
    t.start();
for (Thread t : threads)
    try {
        t.join();
    } catch (InterruptedException e) { }
double result = 0;
for (double d : intermediateResults)
    result += d;
System.out.println(result);

假设largeArray的长度可以被nThreads除以。此解决方案工作正常。

但是,我遇到的问题是,在我的程序中经常会出现上述for-循环线程,这会导致大量开销,这是由于线程的创建和垃圾收集造成的。因此,我正在考虑使用ThreadPoolExecutor修改我的代码。然后,给出中间结果的线程将在下一次执行中被重用(在本例中是求和)。

由于我将中间结果存储在一个大小必须事先知道的数组中,所以我考虑使用一个大小固定的线程池。但是,我很难让线程知道它应该在数组中哪个位置存储它的结果。我应该定义我自己的ThreadFactory吗?

还是更好地使用由方法ExecutorService创建的Executors.newSingleThreadExecutor(ThreadFactory myNumberedThreadFactory)数组?

请注意,在我的实际程序中,很难用另一种类型的东西来替换double[] intermediateResults。我更喜欢一种仅限于创建正确的线程池的解决方案。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2014-03-12 19:34:16

但是,我很难让thread知道它应该在array中哪个位置存储它的结果。我应该定义我自己的ThreadFactory吗?

没必要那么做。执行器使用的接口(RunnableCallable)由线程运行,您可以向您想传递的实现传递任何参数(例如,数组、开始索引和结束索引)。

ThreadPoolExecutor确实是一个很好的解决方案。如果您有可运行的结果,也可以查看FutureTask

票数 1
EN

Stack Overflow用户

发布于 2014-03-12 19:43:02

ExecutorService为您提供了通过Future接口从线程池获取结果的API:

代码语言:javascript
运行
复制
 Future<Double> futureResult = executorService.submit(new Callable<Double>() {
     Double call() {
         double totalForChunk = 0.0;
         // do calculation here
         return totalForChunk;
     }
 });

现在,您需要做的就是提交任务(Callable实例)并等待结果可用:

代码语言:javascript
运行
复制
 List<Future<Double>> results = new ArrayList<Double>();
 for (int i = 0; i < nChunks; i++) {
     results.add(executorService.submit(callableTask));
 }

或者更简单:

代码语言:javascript
运行
复制
 List<Future<Double>> results = executorService.invokeAll(callableTaskList);

其余的都很简单,可以在results上迭代并收集总计:

代码语言:javascript
运行
复制
 double total = 0.0;
 for (Future<Double> result : results) {
     total += result.get(); // this will block until your task is completed by executor service
 }

尽管如此,您并不关心您在executor服务中有多少线程。您只需提交任务并在可用时收集结果。

票数 1
EN

Stack Overflow用户

发布于 2014-03-12 19:35:05

最好是创建"worker“线程,这些线程接收要从队列中执行的工作的信息。然后,您的流程将是创建一个最初为空的WorkQueue,然后创建并启动工作线程。每个工作线程将从队列中拾取其工作,完成工作,并将工作放在一个“已完成”队列上,供主线程拾取和处理。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/22361522

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档