异步并发保持数据一致性
2015-12-30 03:27
323 查看
问题背景:项目中不断切换界面的过程中网络异步请求【耗时操作】,但是数据并未加载完成,此时界面中触碰事件时候,直接崩掉【频率低但存在】。
解决思路:监听异步操作完成后才让界面上的按钮可以响应单击【触碰】事件,数据在加载完成前,界面上的按钮触碰事件都应该被屏蔽掉。
实现:用原子操作记录每个异步线程执行开始和执行结束,最终通过标志位来判断所有的网路请求是否执行完,如果执行完、数据加载完毕,界面即可点击触碰操作。
【知识点】:原子操作--》AtomicInteger AtomicBoolean的运用。
操作图如下:
所有的网络都是异步请求,将第一个获取数据的地方开始计数,第一个网络请求开始的时候开始计时,然后执行完后就将计数器减一,计时器不断的加一和减一,计数器是原子操作保证数据安全性。那么执行完后统计计数器的数,那么当计数器为0的时候,就是说明请求完毕,数据加载完毕。
Code实现:在网络请求的地方开始计时【建立网络请求的构造方法也行】
在网络请求数据完毕后:
工具代码如下:
理解下原子操作:AtomicInteger AtomicBoolean
AtomicInteger,一个提供原子操作的Integer的类。在Java语言中,++i和i++操作并不是线程安全的,在使用的时候,不可避免的会用到synchronized关键字。而AtomicInteger则通过一种线程安全的加减操作接口。
解决思路:监听异步操作完成后才让界面上的按钮可以响应单击【触碰】事件,数据在加载完成前,界面上的按钮触碰事件都应该被屏蔽掉。
实现:用原子操作记录每个异步线程执行开始和执行结束,最终通过标志位来判断所有的网路请求是否执行完,如果执行完、数据加载完毕,界面即可点击触碰操作。
【知识点】:原子操作--》AtomicInteger AtomicBoolean的运用。
操作图如下:
所有的网络都是异步请求,将第一个获取数据的地方开始计数,第一个网络请求开始的时候开始计时,然后执行完后就将计数器减一,计时器不断的加一和减一,计数器是原子操作保证数据安全性。那么执行完后统计计数器的数,那么当计数器为0的时候,就是说明请求完毕,数据加载完毕。
Code实现:在网络请求的地方开始计时【建立网络请求的构造方法也行】
this.doWorking = doWorking; if (this.doWorking!=null) { this.doWorking.beginThreadTask(); }
在网络请求数据完毕后:
if (this.doWorking!=null) { //在每次请求访问结束的时候,返回请求响应结果的时候将线程计数器减一 this.doWorking.endThreadTask(); }具体在获取数据代码中调用回掉函数就行:
@Override protected void initData() { DoWorking.singleRunOk(isWorking, new DoWorking.doWorkingCallBack() { @Override public void run(DoWorking doWorking) { //初始化 date2=new Date();获取用户做题时间
工具代码如下:
** * 作者: on 2015/12/28 11:12 * 邮箱:jd_education@163.com * * @Description: (原子操作:用户界面操作的一致性) */ public class DoWorking { private AtomicInteger count = new AtomicInteger(0); //原子操作 private AtomicBoolean isWorking; //= new AtomicBoolean(false); //设置 //功能: // 1. 顶层try住异常 // 2. 异常发送服务器日志 // 3. 一个线程运行时,别的线程直接返回 public static void singleRunOk(AtomicBoolean isWorking, doWorkingCallBack callback){ DoWorking dwork=new DoWorking(); dwork.isWorking=isWorking; if (isWorking==null) { try { callback.run(dwork);//用来执行用户的业务逻辑 } catch (Exception e) { SubmitErrorLogToServer.submitLog(e); } } else { //理解isWorking.compareAndSet(false, true):如果实际值【isWorking】和期望值【false】相等就把实际值设置为更新值【true】,并返回true //如果实际值isWorking和期望值不相等,那么就将实际值还是设为更新值,返回false //总结:实际值最终为更新值,返回值代表的是逻辑是否走通 if(!isWorking.compareAndSet(false, true)){ return; } dwork.count.incrementAndGet(); //count+1【count用来计数】 try { callback.run(dwork);//用来执行用户的业务逻辑 } catch (Exception e) { if (0 == dwork.count.decrementAndGet()) { isWorking.set(false); //如果退出到主程序就设为false } SubmitErrorLogToServer.submitLog(e); } if (0 == dwork.count.decrementAndGet()) { isWorking.set(false); } } } //功能: // 1. 顶层try住异常 // 2. 异常发送服务器日志 public static void safeRun(safeCallBack callback){ try { callback.run();//用来执行用户的业务逻辑 } catch (Exception e) { SubmitErrorLogToServer.submitLog(e); } } public void beginThreadTask() { count.incrementAndGet(); } public void endThreadTask() { if (0 == count.decrementAndGet()) { if (isWorking!=null) { isWorking.set(false); } } } public interface doWorkingCallBack { //回掉函数 void run(DoWorking dwork); } public interface safeCallBack { //initDa函数 void run(); }总结:基本上用接口回掉即可实现效果,其实计数可以理解为记录当前请求线程的id即可,线程池里面还有没有线程。
理解下原子操作:AtomicInteger AtomicBoolean
AtomicInteger,一个提供原子操作的Integer的类。在Java语言中,++i和i++操作并不是线程安全的,在使用的时候,不可避免的会用到synchronized关键字。而AtomicInteger则通过一种线程安全的加减操作接口。
相关文章推荐
- scp: command not found如何解决
- Reverse Words in a String II
- 使用Python创建简单的HTTP和FTP服务
- 在VS的EF中连接MySQL
- [Javascript] Intro to Recursion - Detecting an Infinite Loop
- [leetcode] 136. Single Number 解题报告
- 个人认为老罗的思路非常好
- 【Unity3D游戏开发】性能优化之spine提高80~90%的效率 (三一)
- ubuntu怎么关防火墙
- Android ActionBar的基本用法
- NETTY 编码器介绍
- 大数据分析(一)探索性分析
- linux中网络工具nc|netcat的使用
- showAsAction属性详解
- 归档日志路径
- 顺序存储队列实现
- 队列顺序循环存储实现
- CSS强制性换行
- 队列链式存储实现
- Ubuntu配置Java环境