广州住房公积金建设银行预约网站首页网络营销常见术语
耗时的同步请求自动转异步请求
- 问题描述
- 问题处理
- 代码实现
问题描述
现在在项目中碰到一个情况,导出数据到excel,在数据量比较下的时候直接下载,在数据量比较大时保存到服务的文件列表,后续再供用户下载。
也就是需要避免前端因后端处理时间过长而提示超时的问题。
问题处理
步骤:
1、主线程开启线程1进行数据读取和转换byte数组,处理结束唤醒主线程
2、开启线程2进行计时,到时间后唤醒主线程
3、主线程阻塞,等待唤醒
4、判断是被哪个线程唤醒的,如果是线程1,直接返回数据,请求结束;如果是线程2,则表示读取转换未完成,需要转换为异步处理,这时直接结束请求,返回提示信息。
计划:
1、使用包括主线程在内的3个线程
2、使用CountDownLatch进行主线程唤醒
代码实现
伪代码如下:
ThreadPoolTaskExecutor executor;byte[] handle() throws InterruptedException, ExecutionException {// 技术器为 1,无论哪个线程计数,都会唤醒主线程CountDownLatch latch = new CountDownLatch(1);// 记录 是否数据处理完成AtomicBoolean flag = new AtomicBoolean(false);// 数据读取线程Future<List<Map<String, Object>>> future = executor.submit(() -> {synchronized (flag){flag.set(true);latch.countDown();}return readSomething();});executor.execute(() -> {try {Thread.sleep(5 * 1000);}catch (Exception ignored){}finally {latch.countDown();}});if (!flag.get()) {latch.await();}if (flag.get()) {// 数据读取完成List<Map<String, Object>> maps = future.get();// 返回下载数据return toExcelByte(maps);}else {// 数据读取未完成,需要转异步,并返回响应executor.execute(() -> {List<Map<String, Object>> maps;try {maps = future.get();} catch (InterruptedException | ExecutionException e) {e.printStackTrace();return;}toSaveLocal(toExcelByte(maps));});return "当前数据处理时间较长,请稍后在文件列表中下载".getBytes();}}List<Map<String, Object>> readSomething() {return Collections.EMPTY_LIST;
}byte[] toExcelByte(List<Map<String, Object>> maps) {// 数据保存到excel bytereturn new byte[]{};
}void toSaveLocal(byte[] bytes) {// 写到本地服务器,或者文件服务器,以供下载
}