java.util.concurrent多线程并行处理返回处理结果(计算一个list集合)
普通情况下,我们使用Runnable作为主要的任务表示形式,可是Runnable是一种有非常大局限的抽象,run方法中仅仅能记录日志,打印,或者把数据汇总入某个容器(一方面内存消耗大,还有一方面须要控制同步,效率非常大的限制),总之不能返回运行的结果;
比方同一时候1000个任务去网络上抓取数据,然后将抓取到的数据进行处理(处理方式不定),
最好的方式就是提供回调接口,把处理的方式最为回调传进去;
可是如今我们有了更好的方式实现:CompletionService + Callable
CompletionService将Executor(线程池)和BlockingQueue(堵塞队列)结合在一起,同一时候使用Callable作为任务的基本单元,整个过程就是生产者不断把Callable任务放入堵塞对了,Executor作为消费者不断把任务取出来运行,并返回结果;
优势:
a、堵塞队列防止了内存中排队等待的任务过多,造成内存溢出(毕竟一般生产者速度比較快,比方爬虫准备好网址和规则,就去运行了,运行起来(消费者)还是比較慢的)
b、CompletionService能够实现,哪个任务先运行完毕就返回,而不是按顺序返回,这样能够极大的提升效率
以下代码实现list集合分发多线程串行计算返回计算结果
package com.project.service.service.impl;
import com.google.common.collect.Lists;
import lombok.Getter;
import lombok.Setter;
import java.util.List;
import java.util.concurrent.*;
public class Test {
/**
* 多线程并发遍历list源数据
* 将每个线程处理结果返回
* @param args
* @throws Exception
*/
public static void main (String[]args) throws Exception{
//创建操作源数据 list集合
List list = Lists.newArrayList();
for(int i =1;i<=21;i++){
Student student=new Student(i,"test-"+i);
list.add(student);
}
//创建线程池
ExecutorService exec = Executors.newFixedThreadPool(10);
CompletionService<List<Student>> cpiService =new ExecutorCompletionService<>(exec);
int f=0;
int i =0 ;
//分发线程
while (true){
f=f+1;
int g=(i+10)>list.size()?(list.size()):(i+10);
testCallable callable=new testCallable(f,list.subList(i,g));
if(!exec.isShutdown()){
cpiService.submit(callable);
}
i=(g);
if(i>=(list.size()))
break;
}
System.out.println("f:"+f+";i:"+i+";size:"+list.size());
//获取线程处理结果
for(int h=0;h<f;h++){
List<Student> students=cpiService.take().get();
for(Student student:students){
System.out.println("result-"+h+"-["+student+"]");
}
}
//关闭多线程池
exec.shutdown();
}
@Getter
@Setter
static class Student {
private int id ;
private String name ;
public Student(int id, String name) {
this.id = id;
this.name = name;
}
public Student() {
}
@Override
public String toString() {
return id+"-student{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
//创建多线程处理类
static class testCallable implements Callable<List<Student>>{
private int flag;
private List<Student> students;
public testCallable(int flag, List<Student> students) {
this.flag = flag;
this.students = students;
}
public testCallable() {
}
@Override
public List<Student> call() throws Exception {
students.stream().forEach(e->printStudent(flag,e));
return students;
}
public void printStudent(int i,Student student ){
System.out.println("call-"+i+"-["+student+"]");
}
}
}
本文介绍了如何使用Java的CompletionService结合Executor和BlockingQueue来处理并发计算任务,强调了Callable任务的优势以及CompletionService如何避免内存溢出和提高效率。通过示例代码展示了如何对list集合进行多线程并行计算并获取结果。
1077

被折叠的 条评论
为什么被折叠?



