我有一个在Apache Tomcat 9上运行的Java 8 Web应用程序。ConcurrentHashMap
的{{1}}方法的调用未返回或返回时间太长。
在下面给出的代码中,打印了“ 添加到地图”行,而在某些情况下,根本不打印“ Map:”行,就像执行线程被困在方法中。一旦陷入陷阱,使用相同的computeIfAbsent()
对同一方法的任何后续调用也将卡住,并且永不返回,而使用不同的id
的调用将立即返回。在另一个具有不同id
的实例上进行测试,id
方法在2分钟后返回。在测试时,执行代码的最大并发调用数仅为20个左右。据我了解,computeIfAbsent()
是线程安全的。怎么了?
computeIfAbsent()
private Map<String, Map<String, SomeClass>> aMap = new ConcurrentHashMap<>();
答案 0 :(得分:1)
随后对具有相同ID的相同方法的任何调用也会卡住,并且永远不会返回,而立即返回具有不同ID的调用?
是的,如果计算正在进行中,该ID的所有后续计算调用将被阻止
如果指定的键尚未与某个值关联,则尝试使用给定的映射函数计算其值,并将其输入此映射中,除非为null。整个方法调用是原子执行的,,因此每个键最多可应用一次该功能。在计算进行期间,可能会阻止其他线程对该映射进行的某些尝试的更新操作,因此计算应简短而简单,并且不得尝试更新此映射的任何其他映射。
在测试时执行代码的最大并发调用次数大约只有20个。根据我的理解?
否,这完全取决于该地图中有多少个存储桶
在ConcurrentHashMap中,一次任何数量的线程都可以执行检索操作,但要在对象中进行更新,线程必须锁定要在其中操作线程的特定段。这种锁定机制称为段锁定。或存储桶锁定。一次可以执行16次更新操作
computeIfAbsent()是否是线程安全的?
是的,它是线程安全的ConcurrentHashMap
一个哈希表,它支持检索的完全并发性和更新的高期望并发性。此类遵循与Hashtable相同的功能规范,并且包括与Hashtable的每个方法相对应的方法的版本。 但是,尽管所有操作都是线程安全的,但检索操作并不需要进行锁定,并且不支持以阻止所有访问的方式锁定整个表。依赖于线程安全性而不依赖于同步细节的程序中的哈希表。
老实说,我不是设计和实施ConcurrentHashMap
的人,但是通过互联网我发现了java 8 ConcurrentHashMap improvements的一篇文章,我认为这可能会导致首次通话的延迟。
惰性表格初始化,可最大程度地减少占用空间,直到首次使用为止