我正在详细分析LongAdder算法。LongAdder扩展了类Striped64,在该类中,基本的方法是retryUpdate。以下代码取自此方法;在链接源代码中,它占据第212至222行:
try { // Recheck under lock
Cell[] rs; int m, j;
if ( (rs = cells) != null &&
(m = rs.length) > 0 &&
rs[j = (m - 1) & h] == null) {
rs[j] = r;
created = true;
}
} finally {
busy = 0;
}问题:这个try块怎么会失败?
注意,数组访问
rs[j = (m - 1) & h] 不应该抛出IndexOutOfBoundsException,因为按位操作的结果总是小于或等于其整数参数的最小值,因此0 <= j <= m-1在数组的范围内。
发布于 2020-01-22 21:36:07
这很像jdk代码本身中任何地方与ReentrantLock一起使用的模式。这里的“模式”是您应该始终释放锁,即使发生了异常,所以通常将代码编写为:
Lock someLock...
try {
// use someLock
} finally {
someLock.unlock();
}由于cellsBusy(从busy重命名)实际上是一个繁忙的自旋锁,这里的模式也是一样的。因此:
cellsBusy = 0;实际上是“释放锁”。因此,这实际上不是关于失败,而是关于显式地释放锁。我发现这要容易得多,并对代码进行推理。
发布于 2020-01-22 22:29:25
该代码--以及版本11之前的任何其他Java代码--可能会因为从另一个线程调用不推荐的Thread.stop方法而失败。这将导致在目标线程中引发ThreadDeath错误,可能在任何时候都是如此。但是,线程至少还活着吧足够长,足以执行finally块。
Thread.stop方法被废弃为因为这种行为使它“本质上不安全”
为什么不推荐Thread.stop? 因为它本身就是不安全的。停止线程会使其解锁其锁定的所有监视器。(当ThreadDeath异常在堆栈上传播时,监视器将被解锁。)如果以前受这些监视器保护的任何对象处于不一致状态,其他线程现在可能会以不一致的状态查看这些对象。据说这些物品被损坏了。当线程对损坏的对象进行操作时,可能会导致任意行为。这种行为可能是微妙的,很难发现,也可能是被宣布的。与其他未经检查的异常不同,ThreadDeath无声地杀死线程;因此,用户没有警告他的程序可能已损坏。腐败在实际损害发生后的任何时候都会显现出来,甚至在未来的几个小时或几天内。
理论上,如果从另一个线程停止执行执行的线程,代码可以以这种方式编写,以防止对象处于无效状态。也就是说,如果可以在任何时候调用Thread.stop,那么很难保证一个有效的状态,甚至尝试这样做也不太常见,所以这不太可能是作者的意图。(如果是的话,代码可能会有一个注释来解释它。)
https://stackoverflow.com/questions/53195759
复制相似问题