异步并发保持数据一致性

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

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

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

【知识点】:原子操作--》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则通过一种线程安全的加减操作接口。















参与评论 您还未登录,请先 登录 后发表或查看评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页

打赏作者

ItJavawfc

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值