在Java中,使用多线程向列表中添加一些信息最有效的方法是什么?
我有一些任务,使用多线程技术,以最有效的方式从多个链接聚合一些信息。链接位于某个数组中。现在,我有了类似于此的解决方案:在Java中,使用多线程向列表中添加一些信息最有效的方法是什么?,java,multithreading,list,concurrency,Java,Multithreading,List,Concurrency,我有一些任务,使用多线程技术,以最有效的方式从多个链接聚合一些信息。链接位于某个数组中。现在,我有了类似于此的解决方案: Arrays.stream(link).parallel().forEach(link -> { try { String result = doSomeJobWithLink(link); System.out.println(result); } catch (IOException e
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);
List resultList=Collections.synchronizedList(new ArrayList());
Arrays.stream(link).parallel().forEach(link->{
试一试{
字符串结果=doSomeJobWithLink(链接);
结果列表。添加(结果);
}捕获(IOE异常){
e、 printStackTrace();
}
});
resultList.forEach(System.out::println);
但这需要5-8秒而不是2秒。我能不能加快速度?使用以下代码:
List<String> resultList = Arrays.stream(link).parallel().map(v -> doSomeJobWithLink(v)).collect(Collectors.toList());
List resultList=Arrays.stream(link.parallel().map(v->doSomeJobWithLink(v)).collect(Collectors.toList());
通常我们避免在流管道中尝试捕获,但若必须捕获异常,请阅读
不要仅仅因为可以而使用parallel
,因为额外的开销会比没有parallel
请参见使用以下代码:
List<String> resultList = Arrays.stream(link).parallel().map(v -> doSomeJobWithLink(v)).collect(Collectors.toList());
List resultList=Arrays.stream(link.parallel().map(v->doSomeJobWithLink(v)).collect(Collectors.toList());
通常我们避免在流管道中尝试捕获,但若必须捕获异常,请阅读
不要仅仅因为可以而使用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());
List resultList=Arrays.stream(link.parallel().map(e->{
字符串结果=null;
试一试{
结果=doSomeJobWithLink(e);
}捕获(IOEX异常){
例如printStackTrace();
返回null;
}
返回结果;
}).filter(e->e!=null).collect(collector.toList());
不确定下面的代码是否能提高性能,但我认为这将是一种更干净的方法来解决您的问题
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());
List resultList=Arrays.stream(link.parallel().map(e->{
字符串结果=null;
试一试{
结果=doSomeJobWithLink(e);
}捕获(IOEX异常){
例如printStackTrace();
返回null;
}
返回结果;
}).filter(e->e!=null).collect(collector.toList());
当您这样做时,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 resultList=Arrays.stream(link.parallel().map(e->{
试一试{
返回doSomeJobWithLink(e);
}捕获(IOEX异常){
例如printStackTrace();
返回null;
}
返回结果;
}).filter(Objects::nonNull).collect(collector.toList());
尽管不建议吞咽异常,除非这是不可避免的。当您这样做时,
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 resultList=Arrays.stream(link.parallel().map(e->{
试一试{
返回doSomeJobWithLink(e);
}捕获(IOEX异常){
例如printStackTrace();
返回null;
}
返回结果;
}).filter(Objects::nonNull).collect(collector.toList());
尽管不建议忽略异常,除非这是不可避免的。尝试将结果列表的初始容量设置为输入数组的大小。是的,现在是2秒,尝试将结果列表的初始容量设置为输入数组的大小。是的,现在是2秒,THX返回null始终是实现NPE的第一步。不要那样做。抛出自定义异常或返回空列表。返回null始终是NPE的第一步。不要那样做。抛出自定义异常或返回空列表