????????刚接手一个项目,收到很多用户反馈某列表搜索太慢,每次点击【查询】需要3s多,看了下代码逻辑,大概是该项目只有主键id数据,但是列表需要展示id对应的所有全部数据,所以需要先查询出id列表,然后根据id列表遍历调用dubbo接口来获取数据进行整合,返回给前端;一个id调用dubbo接口的耗时大概150ms,最优情况下搜索只有1条数据,那么接口耗时150ms,但是如果是模糊搜索20条数据,则遍历查询耗时就需要3s多,而且查看链路统计,超过50%的请求都是模糊搜索,所以大部分用户搜索列表都是好使3s,所以肯定要优化一下;
方案两个:
1. 合作方提供一个dubbo接口,参数为List<int> id,调用一次完善所有数据,但是合作方推脱不给做,只能自己想办法; 2. 使用Callable多线程优化for循环调用dubbo接口;
Callable这里不做介绍了,大家有兴趣可以搜一下,它相对其他多线程操作有两个特点:
1. 可以获取线程执行结果;
2. 可以抛出线程中的异常
直接贴代码参考下:
1. 创建CallableTask类实现Callable接口
import java.util.concurrent.Callable;
/**
* Callable任务类
* 实现Callable接口,并实现call方法
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class CallableTask implements Callable<String> {
/**
* 定义成员变量,接收参数
*/
private String s;
@Override
public String call() throws Exception {
//模拟调用dubbo接口
Thread.sleep(1000);
return s;
}
}
2. 线程池中提交CallableTask
public void testCallable() throws InterruptedException, ExecutionException {
//定义列表,元素10个
List<String> list = Lists.newArrayList("a","b","c","d","e","f","g","h","i","j");
//正常单线程逻辑
StringBuilder sb = new StringBuilder();
Long start = System.currentTimeMillis();
for (String s : list) {
//模拟调用dubbo接口
Thread.sleep(1000);
sb.append(s);
}
System.out.println(sb + "====>单线程逻辑===>cast:" + (System.currentTimeMillis() - start));
//使用Callable多线程逻辑
Long start1 = System.currentTimeMillis();
List<Future> futureList = new ArrayList<>();
//这里注意,一定要先收集future列表,再遍历future的get方法,因为get方法是阻断的,如果在for循环中get方法,那么和单线程没有任何区别
for (String s : list) {
//获取future,在最后用来获取线程执行结果
Future<String> future = executorService.submit(new CallableTask(s));
futureList.add(future);
}
StringBuilder sb1 = new StringBuilder();
for (Future future : futureList) {
//获取线程结果
sb1.append(future.get());
}
System.out.println(sb + "====>callable多线程====>cast:" + (System.currentTimeMillis() - start1));
}
3. 执行结果?
|