![](/img/trans.png)
[英]How to work with multiple threads in a most effective and without synchronize in java?
[英]How most effective add some info to list with multiple threads in 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<>())
,你把一个synchronized
放在整个列表上,即列表上的任何操作共享相同的互斥锁,甚至读取,这会降低性能,并且是限制因素。
更好的方法是只收集到普通列表, 收集器保证无序并发减少。
对于并发收集器,实现可以自由地(但不要求)同时实现减少。 并发减少是指从多个线程并发调用累加器函数,使用相同的可并发修改的结果容器,而不是在累加期间保持结果隔离。 仅当收集器具有 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());
尽管不建议吞下异常,除非这是不可避免的。
使用以下代码:
List<String> resultList = Arrays.stream(link).parallel().map(v -> doSomeJobWithLink(v)).collect(Collectors.toList());
通常我们避免在流管道中尝试捕获,但如果您必须捕获异常,请阅读Java Streams 中的异常处理
并且不要仅仅因为你可以使用parallel
,因为额外的开销你的工作将比没有parallel
需要更多的时间
不确定下面的代码是否会提高任何性能,但我认为这将是解决您问题的更简洁的方法。
List<String> resultList = Arrays.stream(link).parallel().map(e -> {
String result = null;
try {
result = doSomeJobWithLink(e);
} catch (IOException ex) {
ex.printStackTrace();
return null;
}
return result;
}).filter(e -> e != null).collect(Collectors.toList());
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.