我有 ArrayList
。它包含大约20,000个文件路径元素。
private List<Path> listOfPaths = new ArrayList<>();
我想在多线程模式下阅读这些路径上的文件内容。问题在于此代码运行速度很慢。如何选择几个线程,以便每个线程读取文件并将其写入dto
?如何解决一个线程开始处理文件的问题,以使另一个线程与同一文件不执行相同的操作?
您可能可以在较小的块中将作品分开,每个线程处理所有文件的一部分。每个线程都会有自己的数据列表进行处理和处理的数据列表,以避免尝试同时读取相同数据的任何风险。所有线程完成后,您将升级结果。
实际上,您可以让Java 8平行流对您进行艰苦的分裂/Mergin等。
使用不使用多个线程的标准流:
List<ParamsDTO> paramsList = listOfPaths.stream().map(p -> readFile(p)).collect(Collectors.toList());
使用并行流以提高性能:
List<ParamsDTO> paramsList = listOfPaths.parallelStream().map(p -> readFile(p)).collect(Collectors.toList());
您将函数定义为以下位置:
public ParamDTO readFile(Path p) {
ParamsDTO params = new ParamsDTO();
params.setParams(Files.readAllBytes(path));
return params;
}
从长远来看,您可能希望超越它,根据磁盘类型的类型控制并行性的水平,并获得更多的控制权,使用Java 5执行者来管理线程池特征和普通的可运行或期货要运行任务。
我创建了IOPOOL,以不用IO操作来阻止common-pool(默认在并行流操作上使用(。通常,如果您正在执行IO操作,则建议您可以创建core-count* 2
线程,但是确实有限制。
您可以像下面这样做。这不会按顺序处理您的文件列表。
ForkJoinPool ioPool = new ForkJoinPool(8);
ForkJoinTask<?> tasks = ioPool.submit(
() -> pathList.parallelStream().forEach(//your code here);
tasks.get(); // this blocks until all threads finishes in the pool