如何解决Java并发Hashmap initTable为什么try / finally块?
/**
* Initializes table,using the size recorded in sizeCtl.
*/
private final Node<K,V>[] initTable() {
Node<K,V>[] tab; int sc;
while ((tab = table) == null || tab.length == 0) {
if ((sc = sizeCtl) < 0)
Thread.yield(); // lost initialization race; just spin
else if (U.compareAndSetInt(this,SIZECTL,sc,-1)) {
try {
if ((tab = table) == null || tab.length == 0) {
int n = (sc > 0) ? sc : DEFAULT_CAPACITY;
@SuppressWarnings("unchecked")
Node<K,V>[] nt = (Node<K,V>[])new Node<?,?>[n];
table = tab = nt;
sc = n - (n >>> 2);
}
} finally {
sizeCtl = sc;
}
break;
}
}
return tab;
}
有人可以解释为什么需要try块吗?
解决方法
未经检查的异常和错误作为一个概念存在。如果您在ConcurrentHashMap上调用.put()
,而您的内存确实紧缺,则该映射可能会尝试创建一个数组,并且该调用可能会失败,并显示OutOfMemoryError。代码仍将继续(可能在捕获该代码的catch块处),并且对该映射的引用仍然存在。如果在此之后发生地图崩溃并由于sizeCtl值损坏而完全失效的情况,那会有点遗憾。
关键是finally块将恢复sizeCtl
的值。这用于各种用途,值得注意的包括管理哪个线程获得访问权限。如果没有,其他任何看跌期权将永远旋转。
与此相关(例如,在这里多久发生一次可抛出事件,而不是删除“ try”和“ finally”并仅以sizeCtl = sc;
结尾,而没有try / final的额外开销)较低,但如果相关,则非常相关。
这是一种互斥锁-并具有双重检查锁。
首先
if ((sc = sizeCtl) < 0)
Thread.yield(); // lost initialization race; just spin
检查sizeCtl
互斥。如果该值小于零,则说明有人已将其抓住,因此我们只需要稍等片刻即可。
如果它为零(或更大),则有机会获得锁。因此,执行了“比较并交换”操作:
if (U.compareAndSetInt(this,SIZECTL,sc,-1)
这是一个原子操作-如果在第一次检查和第二次检查之间另一个线程抓住了它,则不会执行if
。
如果CAS成功,则该方法将负责释放互斥量。因此,无论是否发生异常(例如,内存不足分配新节点-或是否存在异常),都使用try-finally
确保互斥体被释放(sizeCtl
重置为其原始值)。是否适用于地图)。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。