[英]Under which circumstances can toSet throw an java.lang.IllegalArgumentException?
根据我们的 Crashlytics 日志,我们似乎不时遇到以下异常:
Fatal Exception: java.lang.IllegalArgumentException
Illegal initial capacity: -1
...
java.util.HashMap.<init> (HashMap.java:448)
java.util.LinkedHashMap.<init> (LinkedHashMap.java:371)
java.util.HashSet.<init> (HashSet.java:161)
java.util.LinkedHashSet.<init> (LinkedHashSet.java:146)
kotlin.collections.CollectionsKt___CollectionsKt.toSet (CollectionsKt___CollectionsKt.java:1316)
但我们不确定何时可能真正抛出此异常。 该语句的相关代码如下所示:
private val markersMap = mutableMapOf<Any, Marker>()
...
synchronized(markersMap) {
val currentMarkers = markersMap.values.toSet() //it crashes here
// performing some operation on the markers
}
现在我们怀疑多线程会导致这个问题,因为在多个地方修改了markersMap
映射,但是由于映射已经默认初始化,我们不确定它如何最终达到小于空的状态。 我们还查看了toSet
实现:
if (this is Collection) {
return when (size) {
0 -> emptySet()
1 -> setOf(if (this is List) this[0] else iterator().next())
else -> toCollection(LinkedHashSet<T>(mapCapacity(size)))
}
}
基于此,我们假设mapCapacity(size)
返回-1
,但我们无法找到mapCapacity
的实际实现来验证何时会发生这种情况。
有人知道这里什么时候返回-1
,这又会导致构造函数失败吗?
Java 集合不是synchronized
,如果您需要从多个线程访问Map
或任何集合,则需要处理同步。 如LinkedHashMap
的标题中所述
注意这个实现不是同步的。如果多个线程同时访问一个链接的哈希映射,并且至少有一个线程在结构上修改了映射,它必须在外部同步。
我的猜测是您可能在没有同步的情况下在Map
上执行结构修改( put
和remove
混合),这可能会导致此问题。 例如
fun main(){
val markersMap = mutableMapOf<Any, Any>()
(1..1000).forEach { markersMap.put(it, "$it") }
val t1 = Thread{
(1..1000).forEach { markersMap.remove(it)
if(markersMap.size < 0){
print("SIZE IS ${markersMap.size}")
}
}
}
val t2 = Thread{
(1..1000).forEach {
markersMap.remove(it)
if(markersMap.size < 0){
print("SIZE IS ${markersMap.size}")
}
}
}
t1.start()
t2.start()
}
在我的机器上,此代码打印SIZE IS -128
、 SIZE IS -127
以及许多其他负值,当我在其中一个 if 块中添加markersMap.values.toSet()
,发生了这种情况
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.