引子

测不准原理中有一个现象:人们对光子的观测行为本身会影响观测的结果。近期在排查问题中也遇到了类似的“诡异”问题,初期百思不得其解,真相大白之后摇头苦笑,记在这里贻笑大方。

现象

先看一段经过简化的代码。

// 对象结构体
public class Foo {private int id;public Foo(int i) {this.id = i;}public Foo() {}public void setId(int id) {this.id = id;}public int getId() {return id;}
}// 处理逻辑
List<Foo> fooList = new ArrayList<>();
fooList.add(new Foo(1));List<Foo> newFooList=Lists.transform(fooList,new Function<Foo, Foo>(){@Overridepublic Foo apply(Foo input){Foo output=new Foo();// 一些处理逻辑output.setId(input.getId()*10);return output;}
});for(Foo foo:newFooList){// 后处理逻辑int id=foo.getId()*10;foo.setId(id);
}

问题:最后newFooList里面元素的id是多少?

上面的代码不复杂,JAVA又有强大趁手的调试工具,连上debugger单步走一遭就是。可是结果却令人惊讶:虽然每一行代码都走到了,最后的结果却是明白无误的10——中间的那次乘10操作被吃了?更诡异的事情在后面:如果在for循环里加一个断点,明白无误的看到新的id被赋值进去,但是把鼠标移到newFooList上,里面的指向的object对象里的值还是10,且每次看这个对象的地址都在不断递增,好像后台在不断的new对象,有内存泄露?

分析

对象的地址递增可以解释为何后处理逻辑的值设不进list里:看到的对象已经不是当初的保存对象了,当然看不到设置的值了。apply函数中有new更是高度怀疑对象。

为何list里保存对象会变呢?搂了一遍Guava list的源码,里面自己实现了一个list以及相应的listIterator,只要有对数组元素的查询遍历操作,就会调用apply函数,执行apply函数里的逻辑——也就是每次new一个新对象,且设id的值为10。

为何用idea查看时,断点没动,对象的地址在递增?这里估计是idea做了特殊处理:它会调用list的get方法,重新new对象并设初值,但是不会触发里面的断点。证据就是如果在里面加上print函数,虽然没有触发断点,但是有日志打印出来。

总结

这个问题的产生的根源就是对list.transform的行为逻辑想当然了,以为apply函数的用处是一次性的。虽然java8中已经提供了替代的stream,但是在一些老系统中仍然存在着guava的代码,如果对实现原理理解不清楚就会踩坑。在上述例子中,要注意List.transform后不要再对元素进行处理,如果一定要处理,需要将结果固定到一个数组中(使用Lists.newArrayList()或者ImmutableList.copyOf)。

测不准原理?记一次Guava队列问题的排查相关推荐

  1. 多队列 部分队列没有包_记一次TCP全队列溢出问题排查过程

    简介:记一次TCP全队列溢出问题排查过程 1. 前言 本文排查的问题是经典的TCP队列溢出问题,因TCP队列问题在操作系统层面没有明显的指标异常,容易被忽略,故把排查过程分享给大家. 2. 问题描述 ...

  2. 记一次服务器负载飙高排查过程

    记一次服务器负载飙高排查过程 问题描述 在前天呢,我们公司的三台部署着php项目的线上服务器A.B.C,其中一台服务器A出现了CPU负载飙高,与其他两台服务器相差好几倍,并且在前天之前都没有出现过这么 ...

  3. 转:记一次linux oom内存溢出排查过程

    @转:记一次linux oom内存溢出排查过程 记一次linux oom内存溢出排查过程 2018年08月16日 14:13:49 enchanterblue 阅读数 4099更多 分类专栏: --- ...

  4. 让人抓头的Java并发(四) 阻塞队列--CPU飙升排查案例

    在上一篇文章中给大家介绍了牛批的AQS,大致讲解了JUC中同步的思路.本来还没想好这一篇应该写点什么,刚好上周某个同事的代码出现问题,排查后发现是使用阻塞队列不当导致的,所以本篇决定介绍下阻塞队列. ...

  5. 记一次内存泄漏问题的排查经历

    源宝导读:随着系统越来越庞大,越来越复杂,疑难杂症问题也越来越多.本文将介绍明源研发协同平台团队针对一次内存泄露问题的排查过程和技术探索. 一.背景 内存泄漏,一个说大不大说下不小的瑕疵.作为开发者, ...

  6. linux 内存溢出排查_记一次JAVA 线上故障排查完整套路

    JAVA线上故障排查全套路 线上故障主要会包括cpu.磁盘.内存以及网络问题,而大多数故障可能会包含不止一个层面的问题,所以进行排查时候尽量四个方面依次排查一遍.同时例如jstack.jmap等工具也 ...

  7. 记一次频繁YoungGC生产问题排查思路及解决方案

    1.问题背景 系统开发了新功能上线,本来上完之后功能验收正常,就在大家都松了一口气安心听技术分享时,晚上6.56分突然收到了系统告警: YoungGC时间过长,说实话一开始看到这个告警心里是毫无波澜的 ...

  8. 记一次kafka数据丢失问题的排查

    2019独角兽企业重金招聘Python工程师标准>>> 数据丢失为大事,针对数据丢失的问题我们排查结果如下. 第一:是否存在数据丢失的问题?     存在,且已重现. 第二:是在什么 ...

  9. mysql死锁语句_记一次神奇的Mysql死锁排查

    背景 说起Mysql死锁,之前写过一次有关Mysql加锁的基本介绍,对于一些基本的Mysql锁或者死锁都有一个简单的认识,可以看下这篇文章为什么开发人员需要了解数据库锁.有了上面的经验之后,本以为对于 ...

最新文章

  1. 20172328 2018-2019《Java软件结构与数据结构》第八周学习总结
  2. 原来国家的名字可以如此浪漫!(ZZ)
  3. mysql默认安装目录说明
  4. 如何把新建的UI component添加到新的workcenter里
  5. 03-instancing 工程分析详解
  6. 用户数据报协议是啥?看完这文就懂了!| 技术头条
  7. 跳出多重循环_代码里的俄罗斯套娃 | 07 多重循环
  8. NYOJ——————数的长度(斯特林公式的应用)
  9. ASP.NET公司企业网站源码
  10. Python解标准数独
  11. PHPCMS 前台模板集合
  12. 单阶段和两阶段目标检测
  13. 与孤独世界的博弈——诺贝尔奖得主约翰·纳什的传奇一生
  14. 利用Python解决掉谷歌人机验证,全自动识别真的牛啊
  15. ANTLR4: No method for rule r or it has arguments
  16. JavaScript小游戏--翻牌记忆游戏
  17. metrics和graphite监控
  18. 数据分析师必须掌握的常见数据分析方法
  19. 近25年科技成果大盘点,有几大重要领域不得不看
  20. 数字内容市场水量上涨,阜博集团能否成为“鲶鱼”?

热门文章

  1. SQL 开窗函数使用
  2. ip地址位置提供商查询 cip.cc/ip
  3. ceisum 加载geojson,使用 Cesium 动态加载 GeoJSON 数据
  4. kubectl命令使用滚动更新和回滚
  5. 谷歌地图开发地图不能显示_Google,为什么地图不能让我在家工作?
  6. python免费课程全套-为了学习Python,我汇总了这10个免费的视频课程!
  7. 文本深度表示模型——word2vecdoc2vec词向量模型(转)
  8. Python爬虫+可视化实例:网易云音乐歌单
  9. Mock服务的理解和搭建
  10. 从破解虫脑到攻克人脑:一条“永生之路”的新赛道?