您的位置:首页 > 其它

异步并发保持数据一致性

2015-12-30 03:27 323 查看
问题背景:项目中不断切换界面的过程中网络异步请求【耗时操作】,但是数据并未加载完成,此时界面中触碰事件时候,直接崩掉【频率低但存在】。

解决思路:监听异步操作完成后才让界面上的按钮可以响应单击【触碰】事件,数据在加载完成前,界面上的按钮触碰事件都应该被屏蔽掉。

实现:用原子操作记录每个异步线程执行开始和执行结束,最终通过标志位来判断所有的网路请求是否执行完,如果执行完、数据加载完毕,界面即可点击触碰操作。

【知识点】:原子操作--》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则通过一种线程安全的加减操作接口。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息