Leader:这样的 Bug 你也写的出来???
Hello~各位读者新年好!不知道大家春节假期是否已延长,小黑哥刚接到通知,假期延长到 2 月 2 号,另外回去之后需要在家办公,自行隔离两周。还没试过在家办公,小黑哥就怕到时候生物钟还没调整过来,一觉睡醒已经是下午了。。。

前言
春节假期,还躺在床上小黑哥,收到对账系统的一条预警短信,提示当前系统资金核对存在问题。关于资金的问题,都是大问题,小黑哥连忙拔出电脑,连上 VPN,登录生产环境的查看相关日志。
通过日志,很快小黑哥定位到相关代码。

有的同学可能一下子就能看出这里的问题, Long 对象采用 !=进行比较,这真是一个低级 Bug。幸好 Leader 还不知道,赶紧悄悄修复一下。

现在回想小黑哥当初写这段代码的时候,误以为两个 Long 对象比较将会进行自动拆箱,转变为两个基本数值类型比较。
下面开始复习一下 Java 自动装箱与拆箱机制。
自动装箱与拆箱机制
自动装箱(Autoboxing),是 JDK5 新增的一种语法糖,将会在代码编译时自动将原始类型转换为其对应的对象包装器类。例如将 int 转换为 Integer,double 转换为 Double。如果转换结果相反,我们就将其称为拆箱。
下面是一个自动装箱的例子:

上面代码 li.add(i) 就发生自动装箱,将基本数据类型 long 转换为其包装类 Long。
查看这段代码对应的字节码。

图上黄线标注的字节码对应的代码为 li.add(i)。从这我们可以看到 long 类型的自动装箱实际上调用 Long#valueOf 方法。所以编译器运行时将之前的代码转换为下面的代码

接下来我们来看一个自动拆箱的例子:

由于 Long 包装类对象不能用于求模(%)以及 +=,所以这段代码将会发生自动拆箱,将 Long 转化为 long 类型。相应的这里我们也看下其编译之后的字节码。

这里的字节码比之前的复杂很多,这里主要关注黄线部分。可以看到这里调用 Long#longValue 将 Long 对象转为 long 类型。所以自动拆箱这个例子,最后编译器生成字节码等同于以下代码:

Java 规定的 8 种数据类型都有其对应包装类,这些都可以进行相应的自动装箱和拆箱。

这里小结一下:
- 自动装箱机制是通过调用包装器类
valueOf实现 - 自动拆箱机制通过调用包装器类的相应的
**Value,如longValue,intValue实现
Cache 陷阱
自动装箱和拆箱概念说起其实挺简单的,但是如果使用不当可能就会踩坑。
我们来看一段代码:

如果你对上面的结果的不是很清楚,恭喜你,暖男小黑哥帮你排雷了。
上面输出结果为:
true
false
这里输出结果之所以为这样,主要与 LongCache 有关。自动装箱进制将会调用 Long#valueOf,其源码如下:

只要数值范围位于 [-128,127] 之间,valueOf 就会返回 LongCache.cache 这个数组中的值。所以 aLong/bLong其实是同一个对象,cLong/dLong 是两个不用对象的。
Long#valueOf 这个方法通过 Cache 减少创建对象的数量,提高相应的空间以及时间性能。

至于为什么缓存 [-128,127] 之间的数字,而没有缓存更多的值,甚至缓存所有的值?
这是因为 Long 范围为[-263,263],总共 2^64 ,这么多对象实例,显然不宜全部缓存。至于 [-128,127] 之间数字 JDK 设计者认为这些数字使用频率高,个人认为这是一个经验值。
另外这个 cache可能会导致另外一个问题:锁共用。

上面代码看起来 A 类使用 along 这个对象锁,而 B 类使用 blong 这个对象锁,看起来两个风马牛不相及,但是实际上两个对象由于 Cache 机制,导致其实际上使用同一个对象,A 与 B 共用同一把锁。
除了 Long#valueOf 方法中存在 Cache 以外,Byte,Short,Integer,Character 也存在相应的 Cache 值。其中 Integer 对象可以通过 -XX:AutoBoxCacheMax=<size> 改变 Cache 初始范围。
技术总结
通过自动装箱与拆箱机制,大大减少了数据类型转化的代码,但是同时带来一些隐藏的问题。这里我们需要记住:
- 所有对象之间不能使用
==比较,需要使用equals代替,推荐使用JDK7提供的Objects#equals方法,该方法可以有效避免比较过程空指针问题 - 基本数据类型的包装类不适合当做锁对象
各位读者朋友们,请牢记这两个总结,不要踩中这两个坑哦。另外推荐大家安装一下 FindBugs 这个插件,通过这个插件扫描代码,可以找出代码中的相关缺陷。上面两个问题,通过 FindBugs都能扫描出来,简直神器。
对象比较问题:

锁问题

帮助文档
- Autoboxing and Unboxing『https://docs.oracle.com/javase/tutorial/java/data/autoboxing.html』
- 极客时间-『Java并发编程实战』专栏
Leader:这样的 Bug 你也写的出来???的更多相关文章
- 今天写代码遇到了一个BUG
在我们日常写注释是需要注意,在有返回值的里面不要用以下方式注释,不然不会报错,运行状态码返回也是200,但就不是想要的结果. 下面举个例子 return { 'token':token, 'user_ ...
- 修改BUG心得
修改BUG心得 分类: 项目管理/CMMI2013-01-14 22:06 845人阅读 评论(0) 收藏 举报 目录(?)[-] 一 二 三 一. 1.写第一版时就杜绝这些的发生. 2.思维要开 ...
- [中英对照]The Art Of Reporting Bugs | 报bug的艺术
前言:因为最近要给兄弟Team分享一下如何有效地报告bug, 故多做一做功课.下面给出一篇博客的中英文对照翻译. The Art Of Reporting Bugs | 报bug的艺术 My init ...
- 做一名开源社区的扫地僧——从Bug report到Google Summer of Code(GSoC):从200个bug到5000美金
今年的软件自由日(SFD),我在广州Linux用户组的线下活动上做了一个分享,主题叫做<做一名开源社区的扫地僧(上)>.我把演讲的内容重新整理扩充, 写出了文字版, 希望可以跟更多朋友分享 ...
- margin和padding那点事及常见浏览器margin padding相关Bug
用Margin还是用Padding 何时应当使用margin: 需要在border外侧添加空白时. 空白处不需要背景(色)时. 上下相连的两个盒子之间的空白,需要相互抵消时.如15px + 20px的 ...
- 正则转nfa:bug出现。
本人写的一个正则到nfa的bug 刚写完前面的那篇,自己用脑子过了一下,发现了一个bug.具体情况如下. 这个bug的产生条件是多次调用假名的时候,每次调用都会修改假名的nfa图.直接这么说不好理解, ...
- IE6中的常见BUG与相应的解决办法
开发前端的同学一定都知道,IE6是兼容BUG最多的浏览器,它不支持PNG alpha通道暂且不论.其文档的解析理解规范也引起了诸多恼人的BUG,有时甚至让人感到绝望.本文主要讲解一些比较容易遇到的IE ...
- 记一次亲身踩过的hibernate的bug
记一次亲身踩过的hibernate的bug 在写实体类时,经常会对域增加校验,例如@NotNull表示哪个字段不能为空,昨天晚上调试代码,就遇到了问题, @Entity public class Ap ...
- 客户端一致性与多Leader机制------《Designing Data-Intensive Applications》读书笔记7
接着上一篇的内容,我们继续来梳理分布式系统之中的副本机制与副本一致.上文我们聊到了在可用性与一致性之间的一个折中的一致性等级:最终一致性.我们顺着上篇的内容,由用户来分析一致性等级. 1. 客户端的困 ...
随机推荐
- 并查集-G - 食物链
G - 食物链 动物王国中有三类动物A,B,C,这三类动物的食物链构成了有趣的环形.A吃B, B吃C,C吃A.现有N个动物,以1-N编号.每个动物都是A,B,C中的一种,但是我们并不知道它到底是哪一种 ...
- 图的最小生成树prim算法模板
用prim算法构建最小生成树适合顶点数据较少而边较多的图(稠密图) prim算法生成连通图的最小生成树模板伪代码: G为图,一般为全局变量,数组d为顶点与集合s的最短距离 Prim(G, d[]){ ...
- 1 学习wcf 编写简单的WCF服务流程 并发布在IIS上
学习笔记 学习大佬的博客 https://www.cnblogs.com/iamlilinfeng/archive/2012/09/25/2700049.html 写一遍加深印象 图片看不清楚的 可 ...
- crontab实践
1.crontab概要 2.crontab使用 3.关键配置信息 3.1如何配置定时任务 4.注意事项 参考 https://www.cnblogs.com/keithtt/p/6946498.htm ...
- Java 数据库树形查询生成菜单结构
Java 数据库树形查询 JAVA从数据库读取菜单,递归生成菜单树. 定义菜单类 public class Menu { // 菜单id private String id; // 菜单名称 priv ...
- webpack配置的说明
{devtool: 'source-map',//要启用source-map需加上此配置项,同时css或less的loader要加上参数?sourceMap,js的loader不用加 entry: e ...
- HTML5学习(4)文本元素
使用VSCode编辑器,内置emmet插件. ctrl+/ 注释/取消注释 ctrl+enter 新起一行 ctrl+shift+enter 往上新起一行 h$*4>lorem10 <h1 ...
- JavaWeb项目忘记添加依赖
有的时候我们建项目的时候忘记添加项目的依赖了,这里示范一个提示错误,就是 The superclass "javax.servlet.http.HttpServlet" was n ...
- Kubernetes 升级记录:从 1.16.3 升级至 1.17.0
参考官方文档 Upgrading kubeadm clusters 在 ubuntu 18.04 上完成了升级,记录一下升级步骤. 一.升级第一个 master 节点 apt-get 安装 kubea ...
- KALI修改密码
许久不用的Kali,某天打开竟忘了密码! 网上的方法颇为简单,遂准备亲自试一下. #光标移动到第二行的“恢复模式”,按E进入[编辑模式] #进入编辑模式,鼠标是不可操作的,用方向键往下面翻 ...