java - 如何最有效地将一些信息添加到 Java 中的多个线程列表中?
问题描述
我有一些任务以最有效的方式聚合来自多个链接的一些信息,使用多线程。链接位于某个数组中。到目前为止,我有这样的解决方案:
Arrays.stream(link).parallel().forEach(link -> {
try {
String result = doSomeJobWithLink(link);
System.out.println(result);
} catch (IOException e) {
e.printStackTrace();
}
});
它工作得很好(工作已经完成了 2 秒)。
但我不想在我的 try 块中打印结果,而是在某个列表(或其他集合)中收集结果,所以我这样做了:
List<String> resultList = Collections.synchronizedList(new ArrayList<>());
Arrays.stream(link).parallel().forEach(link -> {
try {
String result = doSomeJobWithLink(link);
resultList.add(result);
} catch (IOException e) {
e.printStackTrace();
}
});
resultList.forEach(System.out::println);
但它花了大约 5-8 秒而不是两秒。我可以以某种方式加快速度吗?
解决方案
当您这样做时Collections.synchronizedList(new ArrayList<>())
,您将 asynchronized
放在整个列表上,即列表上的任何操作即使读取也共享相同的互斥锁,这会降低性能并且是限制因素。
更好的方法是只收集到普通列表,收集器保证无序并发减少。
对于并发收集器,实现可以自由(但不要求)同时实现归约。并发减少是从多个线程同时调用累加器函数的一种方法,使用相同的并发可修改结果容器,而不是在累加期间保持结果隔离。仅当收集器具有 Collector.Characteristics.UNORDERED 特征或原始数据无序时,才应应用并发减少。
所以下面应该显着提高性能,
List<String> resultList = Arrays.stream(link).parallel().map(e -> {
try {
return doSomeJobWithLink(e);
} catch (IOException ex) {
ex.printStackTrace();
return null;
}
return result;
}).filter(Objects::nonNull).collect(Collectors.toList());
尽管不建议吞下异常,除非这是不可避免的。
推荐阅读
- javascript - 根据结果js增加计数
- javascript - 我正在尝试显示一个数组,其中包含来自 json 文件的数据 + 我添加的更多数据,但它只显示来自 json 文件的数据
- javascript - 如何在以下网格中找到每个单元格的中心坐标?
- azure - 相当于通过 Azure Blob 的 S3 预签名 URL 上传文件
- pyqt - 将 PyQt UI 作为 python 文件和作为 ui 文件有什么区别?
- python - 我希望游戏在猜到该短语时结束。播放器循环也不起作用
- python - 当服务器没有 ping 间隔时 Websocket 会自动关闭
- mysql - sql:显示所有行,只是用不同的数字
- java - 无法在 Java 中获取单元测试的 thenReturn() 值
- neovim - NVim 没有获取文件