IDEA debug ConcurrentLinkedQueue时抽风
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了IDEA debug ConcurrentLinkedQueue时抽风,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含2955字,纯文字阅读大概需要5分钟。
内容图文
![IDEA debug ConcurrentLinkedQueue时抽风](/upload/InfoBanner/zyjiaocheng/1197/3ec883bbaffd4bb381478555067846d4.jpg)
1. 介绍
如标题所见,我在使用IDEA debug ConcurrentLinkedQueue的Offer方法时,发生了下面的情况。
代码如下:
ConcurrentLinkedQueue<string> queue = new ConcurrentLinkedQueue<>();
queue.offer("A");
queue.offer("B");
第一种打断点的地方:
第二种打断点的地方:
如你所见,相同的地方,打断点的地方不同,导致代码执行的路径都不同,当时我也是迷茫的。
2. 解释原因
IDEA 默认会开启以上两个配置
- Enable alternative view for Collection classes; Select this option to display contents of classes that implement Collection, Map, or List in a more convenient format (for example, to display each map entry as a key-value pair).属于集合的类以更加方便的格式展示其内容(例如,展示map的entry就以键值对展示)
- Enable toString() object view;Allows you to configure which classes use the result of toString() as their display value.展示值以它们toString()的结果展示。
debug时,代码之外,额外执行的只有toString,第一个配置也会调用toString,所以我们定位到了罪魁祸首是toString。我们看看ConcurrentLinkedQueue的toString
2.1 toString
我们去看看哪个类中实现了toString
??
??
最后找到了AbstractCollection中实现了toString
iterator(), 在ConcurrentLinkedQueue有实现。
在iterator()的实现中,跟这篇文章有关的方法是advance()
移动到下一个有效节点并返回 item 以返回 next(),如果没有,则返回 nul
private E advance() {
lastRet = nextNode;
E x = nextItem;
Node<e> pred, p;
// 第一次进来,nextNode还没被赋值,此时默认值为null
if (nextNode == null) {
// 这里就是关键了
p = first();
pred = null;
} else {
pred = nextNode;
p = succ(nextNode);
}
for (;;) {
if (p == null) {
nextNode = null;
nextItem = null;
return x;
}
E item = p.item;
if (item != null) {
nextNode = p;
nextItem = item;
return x;
} else {
// skip over nulls
Node<e> next = succ(p);
if (pred != null && next != null)
pred.casNext(p, next);
p = next;
}
}
}
返回链表第一个活跃的结点(非空,指向的item不为空),如果链表为空就返回null
Node<e> first() {
restartFromHead:
for (;;) {
for (Node<e> h = head, p = h, q;;) {
boolean hasItem = (p.item != null);
if (hasItem || (q = p.next) == null) {
// 更新头结点
updateHead(h, p);
return hasItem ? p : null;
}
else if (p == q)
continue restartFromHead;
else
p = q;
}
}
}
这篇文章也提到过,updateHead()方法。JAVA并发(4)-并发队列ConcurrentLinkedQueue
更新头结点,将之前的头结点的next指向自己。
final void updateHead(Node<e> h, Node<e> p) {
if (h != p && casHead(h, p))
h.lazySetNext(h);
}
2.2 debug
我们按照最上面的代码且按照第一种打断点的方式重新debug,下面会以图片形式展示整个过程。
- 初始状态,此时A已进入队成功
- 我们知道了,使用IDEA debug时,会调用类的toString()方法,此时调用toString()方法后,状态如下
此时,Node1的next被修改成指向自身。
这里也是网上很多博客会认为,第一次入队后,会把第一个节点的next指向自身的原因,其实并不会的。
- 当我们debug到queue.offer("B")时,此时执行到offer()方法中的else if (p == q)时,就为true了
3. 总结
经过了上面的分析,大家应该知道为什么会出现文章开头的问题了吧。也许你会迷迷糊糊的,因为涉及到了ConcurrentLinkedQueue的源码分析。
那我就用一句话,告诉你原因吧,当使用IDEA debug时,默认那两个配置是启用的,两个配置会调用toString,我们应该清楚toString是否被重写;是否影响debug某个类时,代码的执行路径。
可能你会觉得是IDEA的bug(我当时也这样认为),但是我们先看看下面取消两个配置前后的debug情况
-
取消配置前
-
取消配置
一眼就可以看出,取消配置前在debug时,更加直观。
可能你会认为是Doug Lea的bug(反正我不敢这么想。当然这句话只是开玩笑啦)。
我只是让大家记住IDEA在debug时会存在这样的问题,大家也可以在评论区告诉其他同学,除了ConcurrentLinkedQueue外,还有哪些类,在哪种情况下会存在这样的问题
可能大家会有疑问,在debug时,调用了toString,那是否影响后续的执行。不会的,因为tail节点会被修改的在后续的执行中。可以结合上面那篇博客,就很清楚了。
4. 参考
- IDEA debug ConcurrentLinkedQueue 的时候踩的坑 --- 给我提供了问题所在
- Customize views
原文:https://www.cnblogs.com/ukyu/p/14849335.html
内容总结
以上是互联网集市为您收集整理的IDEA debug ConcurrentLinkedQueue时抽风全部内容,希望文章能够帮你解决IDEA debug ConcurrentLinkedQueue时抽风所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。