背景

    最近,在复习JUC的时候调试了一把ConcurrentLinkedQueue的offer方法,意外的发现Idea在debug模式下竟然会 “自动修改” 已经创建的Java对象,当时觉得这个现象很是奇怪,现在把问题的原因以及解决过程记录下来,希望你在调试的时候不要踩坑。

调试代码

    调试的代码很简单,就是多次调用offer方法,然后观察ConcurrentLinkedQueue的headtail属性。

import java.lang.reflect.Field;
import java.util.concurrent.ConcurrentLinkedQueue; public class ConcurrentLinkedQueueTest { public static void main(String[] args) {
ConcurrentLinkedQueue<String> queue = new ConcurrentLinkedQueue<>();
print(queue);
queue.offer("aaa");
print(queue);
queue.offer("bbb");
print(queue);
queue.offer("ccc");
print(queue);
} /**
* 打印并发队列head属性的identityHashCode
* @param queue
*/
private static void print(ConcurrentLinkedQueue queue) {
Field field = null;
boolean isAccessible = false;
try {
field = ConcurrentLinkedQueue.class.getDeclaredField("head");
isAccessible = field.isAccessible();
if (!isAccessible) {
field.setAccessible(true);
}
System.out.println("head: " + System.identityHashCode(field.get(queue)));
} catch (Exception e) {
e.printStackTrace();
} finally {
field.setAccessible(isAccessible);
}
}
}

调试过程

    上述代码在Idea中debug模式下head属性会无缘无故的被修改(run模式下正常,debug模式下关闭所有断点也正常),检查ConcurrentLinkedQueue的源码发现,head属性只有在构造器和反序列化的readObject共3处地方才会被直接赋值(不是cas修改),我也仔细检查了offer方法,确实没有修改head的地方。而Idea在debug时,把head属性修改为第一次offer的Node节点,这个现象就很奇怪了。

  • 在run模式下的输出结果,多次调用offer方法,head属性都是同一个对象(debug模式下关闭所有断点也是同样的效果)

  • 在offer方法中断点,然后debug并单步调试(Step over)

  • 在offer方法中断点,然后debug并直接运行到下一个断点(Resume program)

    由上可见,在debug进入offer方法之后head属性确实被修改了(对象已经不是同一个),而且这不是偶尔出现,而是一直可以复现的,Step over和Resume program也表现出了修改head属性不同的时机,这让人很费解。 更费解的是就算不在offer方法体里断点,在main方法中断点也会出现head被修改的现象。

  • 转战到Eclipse,同样的环境,同样的操作,在run和debug模式下都不会出现head被修改的情况

分析

    了解到Idea在debug模式下默认开启了toString预览特性(Settings>>Build,Execution,Deployment>>Debugger>>Data Views>>Java>>Enable 'toString()' object view),可是调用toString方法也不至于把对象本身都修改了啊,也专门看了下ConcurrentLinkedQueue的内部类Node,并没有复写toString方法(事后回顾,当时在这里疏忽了,下文会再介绍),但还是关掉特性再测试一遍,然而还是同样的结果,head属性任然被悄悄的修改了。第二天来到公司在同事的环境(IntelliJ IDEA 2019.1)上验证了下,还是同样的问题,排除Idea版本的因素。

    郁闷了一会儿,就向"网友"提问了链接,不久就得到了IntelliJ IDEA的产品经理yole的回复,他的意思还是Idea 的 Data Views 的 toString 在作怪,上文已经说过关掉toString特性还是有这个问题,但是他给了我一个重要的思路就是:在debug模式下,ConcurrentLinkedQueue的对象也会被调用toString方法的,在队列的toString方法中会获取队列的迭代器,而创建迭代器时会调用first方法,first方法里就会cas修改head属性。(之前确实没考虑到队列本身的toString方法,而是去看Node是否重写了toString,手动哭脸

最新文章

  1. Android(4)—Mono For Android 第一个App应用程序
  2. 大数据之sqoopCDH 备份
  3. vim 多行注释消除注释,多行删除
  4. 2016 Multi-University Training Contest 5 Divide the Sequence
  5. DLT(Diagnostic Log and Trace)嵌入式系统程序运行记录
  6. STM32 基DMA的DAC波形发生器
  7. asp.net MVC 框架中控制器里使用Newtonsoft.Json对前端传过来的字符串进行解析
  8. 分享一个.NET平台开源免费跨平台的大数据分析框架.NET for Apache Spark
  9. BZOJ4374 : Little Elephant and Boxes
  10. graalvm 简单试用
  11. D3.js的基础部分之选择集的处理 enter和exit的处理方法 (v3版本)
  12. 搭建laravel到nginx
  13. Unity中的 原生插件/平台交互 原理
  14. 如何完全卸载 mysql 数据库
  15. webstorm忽略node_modules目录
  16. avascript小技巧
  17. HTML学习---HTTP基础学习详解
  18. java通过jxls框架实现导入导出excel
  19. Java NIO框架 Mina、Netty、Grizzly
  20. [PHP开发必备] 走在大牛的路上 phpstudy最全的开发环境搭建

热门文章

  1. uva 1411 Ants (权值和最小的完美匹配---KM算法)
  2. html中布局,让下一个子元素占据剩余的高度
  3. MFC自己主动获取网络地址函数实现----广播地址,网关,子网掩码
  4. 打开google 新地址
  5. ubuntu tftp【转】
  6. 洛谷 P1570【NOIP2013】花匠
  7. python-----模糊搜索文件
  8. [国家集训队2]Tree I
  9. nginx开发(一) 源码-编译
  10. 在WIN7里IE8的开发人员工具打不开的解决办法