CompletableFuture是什么?
CompletableFuture是jdk8以来出现的一个专门处理并发的类库,是Future的加强版,集成了更多的方法以应对更加复杂的业务场景。
本节内容需要有一定的函数式编程基础以及lambda表达式基础。
传送门
大家一起找出所有成年人
结合之前业务中的场景,抽象出了这样一个模型,假设从数据库中得到一群人员信息,要筛选出所有成年人。
此时可以将所有的返回结果全部存入一个map中,等待并发结束再去查看所有map中的结果。
import java.util.ArrayList;
import java.util.HashMap;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executors;
public class CompletableFutureTest {
public static void main(String[] args) {
ArrayList<Person> persons = new ArrayList<Person>();
persons.add(new Person("小明", 18));
persons.add(new Person("小华", 17));
persons.add(new Person("小红", 16));
persons.add(new Person("大明", 19));
persons.add(new Person("超明", 20));
System.out.println(persons);
//并发找出所有成年人,并存入map中
ArrayList<CompletableFuture<Boolean>> resList = new ArrayList<CompletableFuture<Boolean>>();
HashMap<Person, Boolean> map = new HashMap<>();
for (Person person : persons) {
resList.add(CompletableFuture.supplyAsync(() -> findMan(person), Executors.newFixedThreadPool(5)).whenComplete((r, e) -> {
if (null == e) {
map.put(person, r);
} else {
System.out.println("执行错误");
}
}));
}
//从map中获取结果
CompletableFuture.allOf(resList.toArray(new CompletableFuture[resList.size()])).whenComplete((r, e) -> {
if (null == e) {
map.forEach((key,value)->{
String msg = value ? (key+"已成年"):(key+"未成年");
System.out.println(msg);
});
} else {
System.out.println("执行错误");
}
}).join();
}
//判断一个人是否成年
private static boolean findMan(Person person) {
return person.getAge() >= 18 ? true : false;
}
}
从传送门中可知,supplyAsync是供给型接口,无需传入参数,有返回值,其他的可以类比,此处的whenComplete则是并发处理完成后异步回调需要做的处理。allOf则是等待所有并发完成,join()和get()方法都是用来获取CompletableFuture异步之后的返回值。join()方法抛出的是uncheck异常(即未经检查的异常),不会强制开发者抛出。get()方法抛出的是经过检查的异常,ExecutionException, InterruptedException 需要用户手动处理。
此时就可以巧妙地通过一个中间map来进行结果传递。
成年认证
此时如果不同的机构对于成年的认证不同,A机构认为大于18岁才能算成年,B机构认为大于等于18岁就算成年。此时又可以对findMan进行封装,可以通过反射获取特定的类进行校验,以SpringBoot工程为例。
此时可以给person加一个属性,认证机构。
@Data
@AllArgsConstructor
public class Person {
private String name;
private int age;
private String department;
}
编写工具类获取SpringApplicationContext
public class SpringContextUtil implements ApplicationContextAware {
private static ApplicationContext applicationContext = null;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
SpringContextUtil.applicationContext = applicationContext;
}
public static ApplicationContext getApplicationContext(){
return applicationContext;
}
}
定义接口以及实现类
public interface Department {
boolean findManByDepartment(Person person);
}
@Service
public class A implements Department {
@Override
public boolean findManByDepartment(Person person) {
return person.getAge() > 18 ? true : false;
}
}
@Service
public class B implements Department{
@Override
public boolean findManByDepartment(Person person) {
return person.getAge() >= 18 ? true : false;
}
}
通过反射动态返回结果
public class CompletableFutureTest {
public static void main(String[] args) {
ArrayList<Person> persons = new ArrayList<Person>();
persons.add(new Person("小明", 18,"A"));
persons.add(new Person("小华", 17,"B"));
persons.add(new Person("小红", 16,"A"));
persons.add(new Person("大明", 19,"B"));
persons.add(new Person("超明", 20,"A"));
System.out.println(persons);
//并发找出所有成年人,并存入map中
ArrayList<CompletableFuture<Boolean>> resList = new ArrayList<CompletableFuture<Boolean>>();
HashMap<Person, Boolean> map = new HashMap<>();
for (Person person : persons) {
resList.add(CompletableFuture.supplyAsync(() -> findMan(person), Executors.newFixedThreadPool(5)).whenComplete((r, e) -> {
if (null == e) {
map.put(person, r);
} else {
System.out.println("执行错误");
}
}));
}
//从map中获取结果
CompletableFuture.allOf(resList.toArray(new CompletableFuture[resList.size()])).whenComplete((r, e) -> {
if (null == e) {
map.forEach((key,value)->{
String msg = value ? (key+"已成年"):(key+"未成年");
System.out.println(msg);
});
} else {
System.out.println("执行错误");
}
}).join();
}
private static boolean findMan(Person person){
boolean flag = false;
try {
ApplicationContext applicationContext = SpringContextUtil.getApplicationContext();
Class<?> clazz = Class.forName(person.getDepartment());
Method method = clazz.getDeclaredMethod("findManByDepartment", person.getClass());
flag = (boolean) method.invoke(applicationContext.getBean(clazz), person);
} catch (Exception e) {
System.out.println("执行错误");
}
return flag;
}
}
总结
通过以上方法就可以对并发处理进行管控以及结果记录或处理,可以大大的提高系统性能和工作效率。