业务中经常碰到查询一个list后又需要对list进行后续处理(在sql层面不方便处理),需要循环遍历list

如果list中各item的业务独立,可用future模式来大大提高性能

1.关于future模式的概念

参考:彻底理解Java的Future模式  https://www.cnblogs.com/cz123/p/7693064.html

先上一个场景:假如你突然想做饭,但是没有厨具,也没有食材。网上购买厨具比较方便,食材去超市买更放心。

实现分析:在快递员送厨具的期间,我们肯定不会闲着,可以去超市买食材。所以,在主线程里面另起一个子线程去网购厨具。

但是,子线程执行的结果是要返回厨具的,而run方法是没有返回值的。所以,这才是难点,需要好好考虑一下。

2.关于实现

(1) callable+future+线程池:

  1. Future<Integer> future =es.submit(calTask);

callable无法直接start,需要借助线程池

Future<T> = 线程池.submit(Callable<T>);

Future<T>.get();

(2)   callable +futuretask+线程池

  1. FutureTask<Integer> futureTask=new FutureTask<>(calTask);
  2. //执行任务
  3. es.submit(futureTask);

FutureTask<T> = new FutureTask<T>(Callable<T>);

线程池.submit(FutureTask<T>)

FutureTask<T>.get();

(3)   callable +futuretask+Thread

同时FureTask也实现了runnable,可以直接允许不用线程池

FutureTask<Class> ft = new FutureTask<Class>((Callable<Class>)
Thread thread = new Thread(ft);
thread.start;

FutureTask<T> = new FutureTask<T>(Callable<T>);

Thread = new Thread(FutureTask<T>);

Thread.start();

FutureTask<T>.get();

参考:Java多线程编程:Callable、Future和FutureTask浅析(多线程编程之四)     博客比较深入

http://blog.csdn.net/javazejian/article/details/50896505

3. 应用

业务模型是这样的:

List<T> = sql;for(T : list<T>) {sql(T);T.doSomething();
}

以future模式重构

List<T> = sql;List<FutureTask<T>> taskList = new ArrayList<FutureTask<T>>(list.size());for(T t: list<T>) {FutureTask<T>  f = new FutureTask<T>(new TaskCallable<T>(t));      taskList.add(f);Thread thread = new Thread(f);thread.start();}for(FutureTask<T> ft : taskList) {ft.get();}

将T分为多个线程并行处理,同时等待所有计算结果,整合后返回

这种模式在业务中达到以下效果:

原(ms) 现(ms)
455 179
422 152
422 120
450 102
517 92
480 88
   

另一个请求:

原 A(ms) 现 B(ms)
1217 216
584 184
505 171
503 116
556 96
线上60ms 22ms
   

可以看到,微观上响应速度提高了5倍

以腾讯压力测试:

  A B
20并发(4*4)2分钟 第一次 tps:127.18   97.15ms tps:212.98    57.57ms
第二次 tps:123.59  100.57ms tps:208.77   57.50ms
100并发  唯一一次 tps:241.39  233.02ms tps:256.48   209.21ms
不处理   唯一一次     tps:793.77  71.93ms    
     
     

分析:

20并发下,性能差不多差一倍

100并发下,差距不大了,推测为mysql顶不住了,证明这种方案在高压下不可取,原本一次查询变成了n+1次,应尽量避免

4.封装

虽然原则上予以避免,力求在单次sql层面解决,但迫于需求频繁修改,由于这种情况比较常见,故封装一下:

@Service
public class FurtureService<T> {/**** @param o   外部类对象,用于取得某对象的内部类* @param list    待循环多线程处理的数据* @param c    内部Callable类型* @param args    内部类参数 数组*/public void run(Object o, List<T> list, Class c, Object [] args) throws IllegalAccessException, InvocationTargetException, InstantiationException, ExecutionException, InterruptedException {List<FutureTask<Class>> taskList = new ArrayList<FutureTask<Class>>(list.size());//    ExecutorService exec = Executors.newFixedThreadPool(list.size());Constructor [] constructor = null;constructor = c.getConstructors();for(int i=0; i<list.size(); ++i) {T t = list.get(i);FutureTask<Class> ft = new FutureTask<Class>((Callable<Class>) constructor[0].newInstance(o, list.get(i), args));taskList.add(ft);//    exec.submit(ft);Thread thread = new Thread(ft);thread.start();}for (FutureTask<Class> ft : taskList) {ft.get();}//    exec.shutdown();}}

调用:

    @Autowiredprivate FurtureService<T> furtureService;
furtureService.run(this, list, ComputeTask.class, new Object[]{para});

其实还是有优点的:

1.提高了cpu使用率

2.一定程度弥补了不能在数据库层面一并取出数据的性能

缺点:

1.数据库压力倍增,1次sql变成了n+1次sql查询

 

355

308

311

275

271

205

178

119

105

84

91

96

455

422

422

450

517

480

250

179

152

120

102

92

88

转载于:https://www.cnblogs.com/silyvin/p/9106705.html

一种Furture模式处理请求中循环独立的任务的方法相关推荐

  1. matlab换挡程序,一种基于MATLAB换挡过程中快速锁定分析数据的方法与流程

    本发明涉及汽车变速器数据分析,特别的,涉及一种基于matlab换挡过程中快速锁定分析数据的方法. 背景技术: 自动变速器的核心功能是能根据驾驶员意图进行自动换挡,解放驾驶员的左脚:在自动变速器的使用过 ...

  2. 几种在shell命令行中过滤adb logcat输出的方法

    几种在shell命令行中过滤adb logcat输出的方法 分类标签: LogCat  ADB 我们在Android开发中总能看到程序的log日志内容充满了屏幕,而真正对开发者有意义的信息被淹没在洪流 ...

  3. 手把手教你应用三种工厂模式在SpringIOC中创建对象实例【案例详解】

    目录 一.工厂模式介绍 二.通过静态工厂方法创建Bean实例 三.通过实例工厂方法创建Bean实例 四.通过自定义的factoryBean来创建bean对象 Hello,你好呀,我是灰小猿!一个超会写 ...

  4. java post 多个参数_四种常见的post请求中的参数形式

    1).HTTP 协议是以 ASCII 码 传输,建立在 TCP/IP 协议之上的应用层规范.规范把 HTTP 请求分为三个部分:状态行.请求头.消息主体. 2).协议规定 POST 提交的数据必须放在 ...

  5. shell脚本循环执行一个linux命令,Linux中循环执行shell命令的方法

    Linux命令行,循环执行shell命令 死循环 命令格式while true ;do ; done; 可以将 command 替换为任意命令. 下面以echo "hello"; ...

  6. 解决百度网盘上传请求中或上传慢的方法

    百度网盘正常情况下是超快的,不应该是 "上传请求中" 或 几 k 的速度. 原因是因为 DNS 解释问题.尤其是海外用户.例如,使用 DNS 8.8.8.8 PS C:\WINDO ...

  7. 8086的两种工作模式_8086系统中最小模式与最大模式两种工作方式的主要区别是什么?...

    展开全部 最小模式和最大模式的主要区别为以下几方面: 1.处理系统方面 最小模式:系统里e68a843231313335323631343130323136353331333366306533就808 ...

  8. Node.js设置CORS跨域请求中多域名白名单的方法

    允许跨域请求,主要就是配置Response响应头中的 Access-Control-Allow-Origin 属性为你允许该接口访问的域名. 最常见的设置是: res.header('Access-C ...

  9. Deepin 15.11在大黄蜂模式无法启用笔记本Nvidia独立显卡的解决方法

    20200325 参考: <Deepin Linux v15.11显卡驱动安装Bumblebee> <Bumblebee> 案例: 微星GT60(4600集显.770M独显)在 ...

最新文章

  1. Linux设备文件简介。
  2. 数据挖掘实战:带你做客户价值分析(附代码)
  3. VTK:PolyData之PointsProjectedHull
  4. 往Cloud Foundry上部署应用背后的技术实现
  5. 怎样在excel表格中画斜线并打字_一日一技丨Excel斜线表头如何制作?标题、表头的4个技巧...
  6. react 子传参父_react子父传参有几种方法?
  7. 前端实现图片悬浮_悬浮图片之上效果实现
  8. 佳能c3320怎么设置接收方_入门级单反相机佳能800D是否值得买?在我看来价格决定一切...
  9. python除法保留两位小数_除法巧算(Ⅱ),任何整数除7~9,11的快速心算技巧,爸妈收藏...
  10. LINUX修改权限modify,linux文件权限查看及修改(实用)(View and modify Linux file permissions (practical)).doc...
  11. 如何写数学建模竞赛论文
  12. 计算机应用基础的课程讨论,(计算机教学论文:计算机应用基础课程教学方法的讨论.doc...
  13. 计算机上自带的打字游戏,完美运行金山打字通2016(包括自带的小游戏)
  14. I/O——Spring cache abstraction
  15. 倪光南思考中关村问题
  16. STM32F103_study61_The punctual atoms(Clock System Intro)
  17. JS(javascript)在自动化测试项目中的应用【软件测试开发入门教程】
  18. python如何读取二进制文件为图片_Python二进制文件读取并转换
  19. mp4 转 m3u8 java_java下载m3u8转ts合成mp4
  20. 根据经纬度调用Google地图显示对应位置

热门文章

  1. python画图添加数据标签_Python plt.bar 添加数据标签
  2. 破世界纪录了!用Python实现自动扫雷!
  3. 拜尔模板 bayer pattern
  4. 工业ERP系统特点和优势有哪些?
  5. 面试系列--关于以往工作的问题
  6. ISO PAS 21448 SOTIF(预期功能安全)笔记(四)
  7. c语言实现-五子棋(单双人,可改棋盘大小)
  8. C++随机数之线性同余发生器
  9. NLP-gensim库
  10. java毕业设计汽车资讯网站mybatis+源码+调试部署+系统+数据库+lw