Java并发统计变量值偏差原因及解决方案

 更新时间:2020年06月01日 12:00:55   作者:天恩seo  
这篇文章主要介绍了Java并发统计变量值偏差原因及解决方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

1 问题描述

在一个项目中,需要对发送的请求结果进行统计,开发同事定义了两个全局共享变量CommonUtil.ReqFailNum和ReqNum,分别记录请求失败数和发送的请求数。并在每次发送请求之前都假定该请求会处理失败,先对其累加,直到成功收到200的返回码后,重新修正失败数量。

最后当应用处理请求处于较频繁的阶段时,出现了ReqFailNum最后减为负数的情况,一次正常请求完成时,

CommonUtil.ReqFailNum ++;和CommonUtil.ReqFailNum --应该是成对出现的,这个统计值不应该为负数的。

发送请求的代码如下:

private static boolean XMLPost(String content, String sendUrl) throws Exception{
  boolean bn = false;
  
  if ( null != content ) {
      //初始假设请求发送失败,等待正常返回200后再将失败记录数--
      CommonUtil.ReqFailNum ++;
      
      URL url =null;
      URLConnection con = null;
      OutputStreamWriter out = null;
      try {
        url = new URL(sendUrl);
        con = url.openConnection();
      }catch (MalformedURLException e1) {
        throw new ConnException("MalformedURLException");
      } catch (IOException e) {
        throw new ConnException("IOException");
      }
      con.setConnectTimeout(2000);
      con.setReadTimeout(2000);
      con.setDoOutput(true);
      con.setRequestProperty("Connection", "keep-alive");
      con.setRequestProperty("Pragma:", "no-cache");
      con.setRequestProperty("Cache-Control", "no-cache");
      con.setRequestProperty("Content-Type", "text/xml");
      
      try {
        out = new OutputStreamWriter(con.getOutputStream(), "UTF-8");
        out.write(content);
        out.flush();
        out.close();
      } catch (UnsupportedEncodingException e) {
        throw new ConnException("UnsupportedEncodingException");
      } catch (IOException e) {
        String exceptionStr = CommonUtil.stackTraceStr(e);
        throw new ConnException("IOException."+exceptionStr);
      }finally{
        try {
          if(out != null){
            out.close();
          }
        } catch (IOException e) {
          
          throw new ConnException("IOException...");
        }
      }
      
      String headline = con.getHeaderField(0);
      if (headline != null && headline.indexOf("200") > -1) {
        CommonUtil.ReqFailNum --;
        CommonUtil.ReqNum ++;
        bn = true;
        logger.info("sendUrl:: return 200 ok" );
      }
  }
  return bn;
}

2 错误原因分析  

  统计变量在并发环境下,开发人员却忽视了其安全问题。由于该方法在Action中调用,客户端的每个请求,都会调用该方法。而Web服务器处理客户端的请求时,对每个请求都创建了一个线程去处理。这段对统计变量操作的代码,曝露在多线程环境下,却没有任何同步处理,很容易导致统计数据的不一致问题。  

  在这个应用中,ReqFailNum++这个操作实际上应该是一个原子操作,它包含了对内存的三个动作“读-修改-写”,并且结果状态依赖于之前的状态。上述代码,在没有同步的情况下,当两个线程同时执行这行代码时,可能读到的是同一个值,同时+1 ,最终应该是两次累计操作,结果只累加了一次,由于丢失了一次递增操作,最终的统计值就偏差了1。

  由于++代码是方法最初的几行,线程同时执行++操作的概率较大,而CommonUtil.ReqFailNum --;是在请求成功处理完成后执行的,这段时间涉及到网络请求,处理时间不确定性较大,所以- -操作同时执行的概率也较低。最终ReqFailNum++丢失的次数会多于ReqFailNum--丢失的次数,从而导致这个共享变量ReqFailNum的值成了负数。

3 解决办法  

  1)使用锁,将ReqFailNum++或--的操作放在同步代码块中  

  2)由于是简单的统计变量,可以利用原子变量的特性,使用AtomicInteger或AtomicLong

结论:Web项目中,共享变量的线程安全性容易被忽视,加上数据不一致问题的出现具有偶发、不可预测等因素(本来想截个图的,但是应用目前并发量小,没有出现数据不一致的现象,这也是并发问题隐蔽而不易被发现的原因),为了防患于未然,在项目伊始就应该分析并发因素,让开发人员关注可变状态的线程安全性问题,是非常必要的。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

相关文章

  • Java网络编程之UDP协议详细解读

    Java网络编程之UDP协议详细解读

    这篇文章主要介绍了Java网络编程之UDP协议详细解读,UDP协议全称是用户数据报协议,在网络中它与TCP协议一样用于处理数据包,是一种无连接的协议,在OSI模型中,在第四层——传输层,处于IP协议的上一层,需要的朋友可以参考下
    2023-12-12
  • Java数据结构超详细分析二叉搜索树

    Java数据结构超详细分析二叉搜索树

    二叉搜索树是以一棵二叉树来组织的。每个节点是一个对象,包含的属性有left,right,p和key,其中,left指向该节点的左孩子,right指向该节点的右孩子,p指向该节点的父节点,key是它的值
    2022-03-03
  • apllo开源分布式配置中心详解

    apllo开源分布式配置中心详解

    这篇文章主要为大家介绍了apllo开源分布式配置中心部署详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-02-02
  • Java文件操作之IO流 File类的使用详解

    Java文件操作之IO流 File类的使用详解

    在java中提供有对于文件操作系统的支持,这个支持在java.io.File类中进行了定义,也就是说在整个java.io包中File类是唯一一个与文件本身操作有关的类(创建,删除,重命名)有关的类,而如果想要进行File类的操作,我们需要提供有完整的路径支持,而后可以调用相应的方法进行处理
    2021-09-09
  • 图片叠加效果Java代码实现

    图片叠加效果Java代码实现

    这篇文章主要为大家详细介绍了图片叠加效果Java代码实现,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-02-02
  • java读取解析xml文件实例

    java读取解析xml文件实例

    这篇文章主要介绍了java读取解析xml文件实例,本文创建了一个XML解析类同时讲解了循环节点输出方式,需要的朋友可以参考下
    2015-03-03
  • java中断线程的正确姿势完整示例

    java中断线程的正确姿势完整示例

    这篇文章主要为大家介绍了java中断线程的正确姿势完整示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-05-05
  • IDEA远程连接HBase及其Java API实战详解

    IDEA远程连接HBase及其Java API实战详解

    这篇文章主要介绍了IDEA远程连接HBase及其Java API实战详解,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-04-04
  • java中gc算法实例用法

    java中gc算法实例用法

    在本篇文章里小编给大家整理了一篇关于java中gc算法实例用法,有兴趣的朋友们可以参考学习下。
    2021-01-01
  • Java堆&优先级队列示例讲解(下)

    Java堆&优先级队列示例讲解(下)

    这篇文章主要通过示例详细为大家介绍Java中的堆以及优先级队列,文中的示例代码讲解详细,对我们了解java有一定帮助,需要的可以参考一下
    2022-03-03

最新评论