首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >阻塞行为-并发数据结构Java

阻塞行为-并发数据结构Java
EN

Stack Overflow用户
提问于 2013-10-28 22:52:53
回答 3查看 535关注 0票数 0

我目前正在运行一个高度并发的基准测试,它从Java集合中访问一个ConcurrentSkipList。我发现线程在这个方法中被阻塞了,更准确地说是在这里:

代码语言:javascript
复制
java.util.concurrent.ConcurrentSkipListMap.doGet(ConcurrentSkipListMap.java:828)    
java.util.concurrent.ConcurrentSkipListMap.get(ConcurrentSkipListMap.java:1626)

(这是通过在超过10秒的间隔内打印每个单独线程的堆栈跟踪来获得的)。几分钟后仍未解决此问题

这是集合的预期行为吗?并发的其他集合可能会遇到什么阻塞?

在测试之后,我展示了与ConcurrentHashMap类似的行为:

代码语言:javascript
复制
java.util.concurrent.ConcurrentHashMap.get(ConcurrentHashMap.java:994)
EN

回答 3

Stack Overflow用户

发布于 2013-10-28 23:04:28

这很可能是一个虚假的结果。

当您请求Java转储其所有当前堆栈跟踪时,它会告诉每个线程在到达屈服点时等待,然后捕获跟踪,然后恢复所有线程。正如您可以想象的那样,这意味着在这些跟踪中过度表示了屈服点;这些跟踪包括同步的方法、volatile访问等。ConcurrentSkipListMap.head是在doGet中访问的volatile字段。

有关更详细的分析,请参阅this paper

Solaris Studio有一个分析器,可以从操作系统捕获堆栈跟踪并将其转换为Java堆栈跟踪。这消除了对屈服点的偏见,并为您提供了更准确的结果;您可能会发现doGet几乎完全消失了。我只是幸运地在Linux上运行它,即使这样,它也不是开箱即用的。如果你感兴趣,请在评论中问我如何设置它,我很乐意帮助你。

作为一种更简单的方法,您可以使用System.nanoTime()包装您对ConcurrentSkipList.get的调用,以检查您的时间是否真的花在这里。计算出你在该方法上花费了多少时间,并确认它是否与你所期望的大致相同,因为分析器说你在该方法上花费了某某百分比的时间。

不知羞耻的自我插拔:几个月前,我创建了一个simple program that demonstrates this,用于工作演示文稿。如果您针对一个分析器运行它,它应该显示SpinWork.work出现了很多次,而HardWork.work根本没有出现--尽管后者实际上需要更多的时间。它不包含屈服点。

票数 5
EN

Stack Overflow用户

发布于 2013-10-28 23:02:01

好吧,它并不是以最真实的形式阻塞。阻塞意味着线程活动的暂停。ConcurrentSkipListMap是非阻塞的,它会一直旋转直到成功。但它也保证它最终会成功(也就是说,它不应该进入无限循环)

也就是说,除非你异步地做很多很多get和put,我不明白你怎么能在这个方法上花费这么多时间。

如果你可以用一个例子重新创建它,并与我们分享,这可能会有所帮助。

票数 0
EN

Stack Overflow用户

发布于 2013-10-28 23:05:59

ConcurrentHashMap.get是易失性读取,这意味着在执行读取之前,CPU必须完成所有未完成的写入。这称为存储/加载屏障。这取决于其他线程/核心中正在进行的工作,这可能需要很长时间。参见https://www.cs.umd.edu/users/pugh/java/memoryModel/jsr-133-faq.html

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/19638005

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档