为什么Java中多线程程序速度慢却不怎么使用CPU时间?
为什么Java中多线程程序速度慢却不怎么使用CPU时间?
我的Java程序使用java.util.concurrent.Executor来运行多个线程,每个线程都启动一个可运行类,在该类中从C:驱动器上的逗号分隔文本文件中读取并循环遍历行以将文本拆分和解析为浮点数,之后将数据存储到:
static Vector static ConcurrentSkipListMap
我的电脑是Win 7 64位,Intel Core i7,有六个* 2核心和24GB的RAM,我已经注意到程序将运行2分钟并完成所有1700个文件,但CPU使用率仅约为10%至15%,无论我使用多少线程,使用:
Executor executor=Executors.newFixedThreadPool(50);
Executors.newFixedThreadPool(500)不会有更好的CPU使用率或更短的完成任务的时间。没有网络流量,所有东西都在本地C:驱动器上,有足够的RAM供更多线程使用,但将线程增加到1000时会出现“OutOfMemoryError”。
为什么更多的线程不能转化为更多的CPU使用率和较短的处理时间,为什么?
编辑:我的硬盘是SSD 200 GB。
编辑:最后发现问题在于,每个线程将其结果写入共享的日志文件,每次运行应用程序的次数越多,日志文件越大,速度越慢,由于它是共享的,这肯定会减慢进度,因此在停止写入日志文件后,它在10秒内完成了所有任务!
OutOfMemoryError
可能是由于Java的内存限制而引起的。尝试使用 这里 的一些参数来增加最大内存。
对于速度,Adam Bliss提出了一个好建议。如果这是同一个文件,那么我认为有多个线程同时尝试读取它可能会导致文件锁定的大量争用。更多的线程甚至意味着更多的争用,这甚至可能导致更糟糕的性能。因此,如果可能的话,只需加载文件一次。即使是一个大文件,您也有24GB的RAM。您可以容纳相当大的文件,但您可能需要增加JVM允许的内存以允许整个文件被加载。
如果有多个文件被使用,请考虑这个事实:您的磁盘一次只能读取一个文件。因此,如果线程没有花费太多时间在处理上,那么尝试同时使用磁盘的多个线程可能不太有效。由于CPU使用率很低,可能是线程加载了一部分文件,然后快速运行缓冲的部分,然后花费大量时间等待其余的文件加载完毕。如果你一遍遍地加载文件,这甚至仍然适用。
简而言之:磁盘IO可能是您的罪魁祸首。您需要努力减少它,以便线程在文件内容上的竞争不会太激烈。
编辑:
经过进一步的考虑,更可能是同步问题。线程可能被阻塞,尝试将结果添加到结果列表中。如果频繁访问,这将导致锁对象的大量争用。考虑进行一些操作,如让每个线程在本地列表(例如ArrayList
,它是非线程安全的)中保存其结果,然后将所有值分块复制到最终共享列表中,尝试减少争用。