• 多线程情况下获取数据出现的不一致


    前提:要在游戏业务中新建游戏业务日志,用于后台和运营查询数据。

    在Service层,找到相应的业务方法,这里举例:reward(Player player,HttpReqest req),

    要在reward方法中,new rewardLogData(),同时把业务中的moneyDIff传输给LogData中。

    在这里我们使用了Lambda表达式来表示线程执行方法的过程。 ModuleHandler.addMessage()指的是另一条线程执行代码。

    reward方法代码大概如下:

    1.新旧数据都在ModuleHandler.addMessage()方法中

    public rewardService (Player player ,HttpReqest req) {
    ConfigReward reward = req.getReward();
    //业务的逻辑变化
    ModuleHandler.addMessage(()->{
         int oldMoney = reward.getMoney();
          changeMoney(player);
    int newMoney=reward.getMoney();
            int moneyDiff = newMoney-oldMoney;  
            new LogData(player,moneyDiff).post();
    
    });
    
    }
    private void changeMoney(Player player,ConfigReward  reward ) {
        ModuleHandler2.addMessage(()->{
          changeMoney0(player,reward);
      
    });
    
    }
    

      

     2.将newMoney和oldMoney放在了ModuleHandler2中:

    public rewardService (Player player) {
    ConfigReward reward = configRewardManager.getReward();
    //业务的逻辑变化
    ModuleHandler.addMessage(()->{
          changeMoney(player);
    });
    }
    private void changeMoney(Player player,ConfigReward  reward ) {
        
        ModuleHandler2.addMessage(()->{
    int oldMoney = reward.getMoney(); changeMoney0(player,reward); int newMoney=reward.getMoney(); int moneyDiff = newMoney-oldMoney; new LogData(player,moneyDiff).post(); }); }

      以上2种方法得到的moneyDiff结果却不同,为什么呢?

    第一种方法:走到moduleHandler.addMessage()的时候,先得到了oldMoney,之后执行moduleHandler2线程的方法,由于这个方法是异步执行的。 

    打个比方,moduleHandler在CPU的1核执行方法,moduleHandler2在CPU的2核执行方法,moduleHandler内的方法可以继续执行,所以他不知道2核发生的改变,此时得到的oldMoney和newMoney是一样的!moneyDiff = 0; 

    第二种方法:是在同一个线程中执行,执行完changeMoney0()之后,数据发生改变,moneyDiff则不为0。

    总结:多线程问题中,要注意不同线程中,执行方法的逻辑不是逐行执行的,要考虑异步情况。

    用到的MessageHandler类中

    private Queue<Message<H> > messages = new LinkedBlockingQueue();
    private ExecutorService DEFAULT_EXECUTOR_SERVICE =Executors.newFixedPool();
    public void  addMessage(Message<H> message) {
    
      messags.add(message);
    executorService.execute(this);
    
    }
    

      

  • 相关阅读:
    知方可补不足~Sqlserver发布订阅与sql事务的关系
    基础才是重中之重~泛型类的静态构造方法可不是只执行一次呀
    EF架构~通过EF6的DbCommand拦截器来实现数据库读写分离~终结~配置的优化和事务里读写的统一
    EF架构~通过EF6的DbCommand拦截器来实现数据库读写分离~再续~添加对各只读服务器的心跳检测
    windows服务的创建、安装和调试
    Axure RP 实践.1
    实习第一天之数据绑定:<%#Eval("PartyName")%>'
    Hadoop云计算大数据书籍分享
    Android利用setLayoutParams在代码中调整布局(Margin和居中)
    TopCoder中插件的用法
  • 原文地址:https://www.cnblogs.com/patatoforsyj/p/11456218.html
Copyright © 2020-2023  润新知