一种Furture模式处理请求中循环独立的任务的方法
业务中经常碰到查询一个list后又需要对list进行后续处理(在sql层面不方便处理),需要循环遍历list
如果list中各item的业务独立,可用future模式来大大提高性能
1.关于future模式的概念
参考:彻底理解Java的Future模式 https://www.cnblogs.com/cz123/p/7693064.html
先上一个场景:假如你突然想做饭,但是没有厨具,也没有食材。网上购买厨具比较方便,食材去超市买更放心。
实现分析:在快递员送厨具的期间,我们肯定不会闲着,可以去超市买食材。所以,在主线程里面另起一个子线程去网购厨具。
但是,子线程执行的结果是要返回厨具的,而run方法是没有返回值的。所以,这才是难点,需要好好考虑一下。
2.关于实现
(1) callable+future+线程池:
- Future<Integer> future =es.submit(calTask);
callable无法直接start,需要借助线程池
Future<T> = 线程池.submit(Callable<T>);
Future<T>.get();
(2) callable +futuretask+线程池
- FutureTask<Integer> futureTask=new FutureTask<>(calTask);
- //执行任务
- 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模式处理请求中循环独立的任务的方法相关推荐
- matlab换挡程序,一种基于MATLAB换挡过程中快速锁定分析数据的方法与流程
本发明涉及汽车变速器数据分析,特别的,涉及一种基于matlab换挡过程中快速锁定分析数据的方法. 背景技术: 自动变速器的核心功能是能根据驾驶员意图进行自动换挡,解放驾驶员的左脚:在自动变速器的使用过 ...
- 几种在shell命令行中过滤adb logcat输出的方法
几种在shell命令行中过滤adb logcat输出的方法 分类标签: LogCat ADB 我们在Android开发中总能看到程序的log日志内容充满了屏幕,而真正对开发者有意义的信息被淹没在洪流 ...
- 手把手教你应用三种工厂模式在SpringIOC中创建对象实例【案例详解】
目录 一.工厂模式介绍 二.通过静态工厂方法创建Bean实例 三.通过实例工厂方法创建Bean实例 四.通过自定义的factoryBean来创建bean对象 Hello,你好呀,我是灰小猿!一个超会写 ...
- java post 多个参数_四种常见的post请求中的参数形式
1).HTTP 协议是以 ASCII 码 传输,建立在 TCP/IP 协议之上的应用层规范.规范把 HTTP 请求分为三个部分:状态行.请求头.消息主体. 2).协议规定 POST 提交的数据必须放在 ...
- shell脚本循环执行一个linux命令,Linux中循环执行shell命令的方法
Linux命令行,循环执行shell命令 死循环 命令格式while true ;do ; done; 可以将 command 替换为任意命令. 下面以echo "hello"; ...
- 解决百度网盘上传请求中或上传慢的方法
百度网盘正常情况下是超快的,不应该是 "上传请求中" 或 几 k 的速度. 原因是因为 DNS 解释问题.尤其是海外用户.例如,使用 DNS 8.8.8.8 PS C:\WINDO ...
- 8086的两种工作模式_8086系统中最小模式与最大模式两种工作方式的主要区别是什么?...
展开全部 最小模式和最大模式的主要区别为以下几方面: 1.处理系统方面 最小模式:系统里e68a843231313335323631343130323136353331333366306533就808 ...
- Node.js设置CORS跨域请求中多域名白名单的方法
允许跨域请求,主要就是配置Response响应头中的 Access-Control-Allow-Origin 属性为你允许该接口访问的域名. 最常见的设置是: res.header('Access-C ...
- Deepin 15.11在大黄蜂模式无法启用笔记本Nvidia独立显卡的解决方法
20200325 参考: <Deepin Linux v15.11显卡驱动安装Bumblebee> <Bumblebee> 案例: 微星GT60(4600集显.770M独显)在 ...
最新文章
- Linux设备文件简介。
- 数据挖掘实战:带你做客户价值分析(附代码)
- VTK:PolyData之PointsProjectedHull
- 往Cloud Foundry上部署应用背后的技术实现
- 怎样在excel表格中画斜线并打字_一日一技丨Excel斜线表头如何制作?标题、表头的4个技巧...
- react 子传参父_react子父传参有几种方法?
- 前端实现图片悬浮_悬浮图片之上效果实现
- 佳能c3320怎么设置接收方_入门级单反相机佳能800D是否值得买?在我看来价格决定一切...
- python除法保留两位小数_除法巧算(Ⅱ),任何整数除7~9,11的快速心算技巧,爸妈收藏...
- LINUX修改权限modify,linux文件权限查看及修改(实用)(View and modify Linux file permissions (practical)).doc...
- 如何写数学建模竞赛论文
- 计算机应用基础的课程讨论,(计算机教学论文:计算机应用基础课程教学方法的讨论.doc...
- 计算机上自带的打字游戏,完美运行金山打字通2016(包括自带的小游戏)
- I/O——Spring cache abstraction
- 倪光南思考中关村问题
- STM32F103_study61_The punctual atoms(Clock System Intro)
- JS(javascript)在自动化测试项目中的应用【软件测试开发入门教程】
- python如何读取二进制文件为图片_Python二进制文件读取并转换
- mp4 转 m3u8 java_java下载m3u8转ts合成mp4
- 根据经纬度调用Google地图显示对应位置