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

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

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

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

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

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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 11:34:16

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

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

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

票数 1
EN

Stack Overflow用户

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

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

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

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

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

或者更简单:

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

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 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 11:35:05

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

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

https://stackoverflow.com/questions/22361522

复制
相关文章
JUC多线程:线程池的创建及工作原理
线程池主要是为了解决 新任务执行时,应用程序为任务创建一个新线程 以及 任务执行完毕时,销毁线程所带来的开销。通过线程池,可以在项目初始化时就创建一个线程集合,然后在需要执行新任务时重用这些线程而不是每次都新建一个线程,一旦任务已经完成了,线程回到线程池中并等待下一次分配任务,达到资源复用的效果。
全栈程序员站长
2022/06/29
4210
JUC多线程:线程池的创建及工作原理
JUC 多线程 线程池
线程池主要是控制运行线程的数量,处理过程中将任务放入队列,然后在线程创建后启动这些任务,如果线程数量超过了最大数量的线程排队等候,等其他线程执行完毕,再从队列中取出任务来执行。
万能青年
2019/08/30
6430
JUC 多线程 线程池
Java多线程和线程池
在java中,如果每个请求到达就创建一个新线程,开销是相当大的。在实际使用中,服务器在创建和销毁线程上花费的时间和消耗的系统资源都相当大,甚至可能要比在处理实际的用户请求的时间和资源要多的多。除了创建和销毁线程的开销之外,活动的线程也需要消耗系统资源。如果在一个jvm里创建太多的线程,可能会使系统由于过度消耗内存或“切换过度”而导致系统资源不足。为了防止资源不足,服务器应用程序需要采取一些办法来限制任何给定时刻处理的请求数目,尽可能减少创建和销毁线程的次数,特别是一些资源耗费比较大的线程的创建和销毁,尽量利
Java编程指南
2019/08/02
8410
Java多线程和线程池
Java线程池的使用及工作原理
在日常开发过程中总是以单线程的思维去编码,没有考虑到在多线程状态下的运行状况。由此引发的结果就是请求过多,应用无法响应。为了解决请求过多的问题,又衍生出了线程池的概念。通过“池”的思想,从而合理的处理请求。本文记录了Java中线程池的使用及工作原理,如有错误,欢迎指正。
程序员的时光001
2021/06/09
6340
Java线程池的使用及工作原理
【多线程】线程池源码(1)
上一篇文章讲了有关线程池的一些简单的用法,这篇文章主要是从源码的角度进一步带大家了解线程池的工作流程和工作原理。
用户8902830
2021/08/10
3310
【多线程】线程池源码(1)
Java多线程_Java线程池的大小与线程池死锁
线程池大小对系统性能是有一定影响的,过大或者过小都会无法发挥最优的系统性能, 线程池大小不需要非常精确,只要避免极大或者极小的情况即可, 一般来说,线程池大小需要考虑CPU数量,内存大小等因素. 在书中给出一个估算线程池大小的公式:
玖柒的小窝
2021/11/08
9040
【多线程】线程池源码(3)
线程池的源码解读就先告一段落了(其实总感觉缺了什么东西,但是又找不到),本篇文章就简单总结下之前讲的流程及一些用法。
用户8902830
2021/08/10
2800
【多线程】线程池源码(3)
Java多线程和线程池
在java中,如果每个请求到达就创建一个新线程,开销是相当大的。在实际使用中,服务器在创建和销毁线程上花费的时间和消耗的系统资源都相当大,甚至可能要比在处理实际的用户请求的时间和资源要多的多。除了创建和销毁线程的开销之外,活动的线程也需要消耗系统资源。如果在一个jvm里创建太多的线程,可能会使系统由于过度消耗内存或“切换过度”而导致系统资源不足。为了防止资源不足,服务器应用程序需要采取一些办法来限制任何给定时刻处理的请求数目,尽可能减少创建和销毁线程的次数,特别是一些资源耗费比较大的线程的创建和销毁,尽量利 用已有对象来进行服务,这就是“池化资源”技术产生的原因。
全栈程序员站长
2021/04/07
4900
多线程之线程池(三)
线程池 线程的创建销毁会伴随着系统开销,影响效率 线程并发数量过多,抢占资源导致系统阻塞 对线程进行管理 创建线程池的方式 //五个参数的构造函数 public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,
OPice
2019/10/23
4080
【多线程】线程池源码(2)
时隔上一篇技术文章更新差不多有3个星期了,原因的话在上一篇文章中写啦。废话不多说,开始我们的线程池源码的第二轮阅读。
用户8902830
2021/08/10
2680
【多线程】线程池源码(2)
Spring Boot配置线程池使用多线程插入数据
最近在工作中需要将一大批数据导入到数据库中,因为种种原因这些数据不能使用同步数据的方式来进行复制,而是提供了一批文本,文本里面有很多行url地址,需要的字段都包含在这些url中。最开始是使用的正常的普通方式去写入,但是量太大了,所以就尝试使用多线程来写入。下面我们就来介绍一下怎么使用多线程进行导入。
用户4283147
2022/10/27
1.8K0
JUC并发编程(一)多线程使用和线程池
一个进程往往可以包含多个线程,至少包含一个! Java默认有几个线程? 2 个: mian、GC 对于Java而言:Thread、Runnable、Callable 三种实现线程的方式。 JAVA不能开启线程,是调用本地方法,查看start方法可以看到底层是C++来开启线程的
HcodeBlogger
2020/07/14
7370
JUC并发编程(一)多线程使用和线程池
【线程池】线程池与工作队列
为什么要用线程池? 诸如 Web 服务器、数据库服务器、文件服务器或邮件服务器之类的许多服务器应用程序都面向处理来自某些远程来源的大量短小的任务。请求以某种方式到达服务器,这种方式可能是通过网络协议(例如 HTTP、FTP 或 POP)、通过 JMS 队列或者可能通过轮询数据库。不管请求如何到达,服务器应用程序中经常出现的情况是:单个任务处理的时间很短而请求的数目却是巨大的。 构建服务器应用程序的一个过于简单的模型应该是:每当一个请求到达就创建一个新线程,然后在新线程中为请求服务。实际上,对于原型开发这种方
程序员互动联盟
2018/03/16
1.1K0
Java中多线程的使用(超级超级详细)线程池 7
线程池是一个容纳多个线程的容器,线程池中的线程可以重复使用,无需反复创建线程而消耗过多的资源
一只胡说八道的猴子
2020/09/27
7100
Java中多线程的使用(超级超级详细)线程池 7
Java面试必问之线程池的创建使用、线程池的核心参数、线程池的底层工作原理
大家在面试过程中,必不可少的问题是线程池,小编也是在面试中被问啥傻了,JUC就了解的不多。加上做系统时,很少遇到,自己也是一知半解,最近看了尚硅谷阳哥的课,恍然大悟,特写此文章记录一下!如果还不了解线程池的小伙伴,一定要认真看完,你会有收获的哈!!
掉发的小王
2022/07/11
2740
Java面试必问之线程池的创建使用、线程池的核心参数、线程池的底层工作原理
Android多线程编程__线程池(ThreadPoolExector)
当执行execute方法时,如果当前运行的线程未达到 corePoolSize(核心线程数)时就创建核心线程来处理任务,如果达到了核心线程数则将任务添加·到·LinkedBlockingQueue中,FixedThreadPool 就是一个有固定核心线程的线程池,并且这些线程不会被回收。当线程数超过 corePoolize 时,就将任务存储在任务队列中,当线程池有空闲线程是,则从任务队列中去任务执行。
Petterp
2022/02/09
3330
Android多线程编程__线程池(ThreadPoolExector)
Java 多线程(7)----线程池(下)
在上篇文章:Java 多线程—线程池(上) 中我们看了一下 Java 中的阻塞队列,我们知道阻塞队列是一种可以对线程进行阻塞控制的队列,并且在前面我们也使用了阻塞队列来实现 生产者-消费者模型 。在文章最后,我们还看了一下 Future 接口和其中对应的方法,如果你对这些不熟悉,建议先去看一下上一篇文章。有了前面的知识作为基础之后,我们来正式看一下 Java 中的线程池。
指点
2019/01/18
5290
Java 多线程(7)----线程池(下)
【多线程】线程池基本知识
上篇文章讲了下线程的创建及一些常用的方法,但是在使用的时候,大多数是采用了线程池来管理线程的创建,运行,销毁等过程。本篇将着重讲线程池的基础内容,包括通过线程池创建线程,线程池的基本信息等。
用户8902830
2021/08/10
2840
【多线程】线程池基本知识
线程池(1)——线程池的使用
概述 ---- 1.ThreadPoolExecutor 2.ForkJoinPool 3.ThreadPoolExecutor VS ForkJoinPool 第1节 ThreadPoolExecutor ---- ThreadPoolExecutor执行无返回值的任务。 public class ThreadTest { public static void main(String[] args) { /* 核心线程池的大小 */
黑洞代码
2021/01/14
2.9K0
线程池(1)——线程池的使用
java(7)-多线程和线程池
用Thread类的方式创建多线程的特点: 1、因为线程已经继承Thread类,所以不可以再继承其它类。 2、如果需要访问当前线程,直接使用this即可。
黄规速
2022/04/14
4820
java(7)-多线程和线程池

相似问题

使用线程池的多线程

42

让多线程池在类中工作

10

带工作池模块的多线程

12

多线程中工作池的内存泄漏

238

使用多线程池和连接池

11
添加站长 进交流群

领取专属 10元无门槛券

AI混元助手 在线答疑

扫码加入开发者社群
关注 腾讯云开发者公众号

洞察 腾讯核心技术

剖析业界实践案例

扫码关注腾讯云开发者公众号
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文