use*_*513 0 java collections concurrency multithreading synchronization
我目前正在运行一个高度并发的基准测试,它ConcurrentSkipList
从Java集合中访问一个.我发现线程在该方法中被阻塞,更准确地说:
java.util.concurrent.ConcurrentSkipListMap.doGet(ConcurrentSkipListMap.java:828)
java.util.concurrent.ConcurrentSkipListMap.get(ConcurrentSkipListMap.java:1626)
Run Code Online (Sandbox Code Playgroud)
(这是通过超过10秒的间隔打印每个单独线程的堆栈跟踪获得的).几分钟后仍未解决
这是集合的预期行为吗?什么是可能遇到阻塞的并发其他集合?
经过测试,我表现出与ConcurrentHashMap
s 相似的行为:
java.util.concurrent.ConcurrentHashMap.get(ConcurrentHashMap.java:994)
Run Code Online (Sandbox Code Playgroud)
这很可能是一个虚假的结果.
当您要求Java转储其所有当前堆栈跟踪时,它会告诉每个线程在到达屈服点时等待,然后它捕获跟踪,然后它恢复所有线程.可以想象,这意味着屈服点在这些痕迹中过度表现; 这些包括同步方法,volatile
访问等ConcurrentSkipListMap.head
,一个volatile
字段,访问doGet
.
有关更详细的分析,请参阅此文章.
Solaris Studio具有一个分析器,可从OS捕获堆栈跟踪并将其转换为Java堆栈跟踪.这消除了对屈服点的偏差,并为您提供更准确的结果; 你可能会发现doGet
几乎完全消失了.我只是运气在Linux上运气,即便如此,它也不是开箱即用的.如果您有兴趣,请在评论中询问我如何设置,我很乐意提供帮助.
作为一种更简单的方法,您可以将您的呼叫包裹起来ConcurrentSkipList.get
,System.nanoTime()
以便检查这是否真的是您的时间.弄清楚你花在这种方法上的时间,并确认这是否与你期望的一致,因为探查者说你在这种方法中花费了这么多的时间.
无耻的自我插件:我创建了一个简单的程序,几个月前在工作中进行演示.如果你对一个分析器运行它,它应该显示SpinWork.work
出很多,但HardWork.work
根本不显示 - 即使后者实际上需要更多的时间.它不包含屈服点.