java LongAdder:try块如何失败?

时间:2018-11-07 18:39:46

标签: java algorithm

我正在详细分析Java 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阻止如何失败?

N.b .:访问权限

rs[j = (m - 1) & h] 

不应抛出IndexOutOfBoundsException异常,因为按位与运算的结果始终小于或等于其整数参数的最小值,因此0 <= j <= m-1在数组的范围内。

2 个答案:

答案 0 :(得分:2)

这看起来非常像jdk代码本身中其他任何地方与ReentrantLock一起使用的模式。这里的“模式”是即使发生异常,也应该始终释放锁,因此通常将代码编写为:

Lock someLock...

try {
    // use someLock
} finally {
    someLock.unlock();
}

由于cellsBusy(从busy重命名)实际上是忙碌的,因此这里的模式是相同的。因此:

cellsBusy = 0;

实际上是“释放锁”。因此,这并不是真正的失败,而是显式释放锁定。我发现这很容易阅读,并能很好地理解代码。

答案 1 :(得分:2)

由于不推荐使用的Thread.stop方法是从另一个线程中调用的,因此该代码-以及版本11之前的任何其他Java代码-都可能失败。这可能会随时在目标线程中引发ThreadDeath错误。但是,线程does at least stay alive足够长,足以执行finally块。

不推荐使用Thread.stop方法because this behaviour makes it "inherently unsafe"

为什么不赞成使用Thread.stop?

因为它本质上是不安全的。停止线程会使它解锁它已锁定的所有监视器。 (当ThreadDeath异常在堆栈中传播时,监视器将被解锁。)如果以前由这些监视器保护的任何对象处于不一致状态,则其他线程现在可能会以不一致状态查看这些对象。据说这些物体已损坏。当线程对损坏的对象进行操作时,可能会导致任意行为。此行为可能是微妙的,难以检测,或者可能是明显的。与其他未检查的异常不同,ThreadDeath会无声地杀死线程。因此,用户没有警告其程序可能已损坏。在实际损坏发生后的任何时间,甚至未来数小时或数天,腐败都会显现出来。

从理论上讲,如果在另一个线程中停止了执行该对象的线程,则可以以此方式尝试编写代码来防止将对象置于无效状态。就是说,如果可以随时调用Thread.stop,则很难保证有效状态,即使尝试这样做也不是很常见的事情,因此这并非作者的意图。 (如果是,则代码中可能会有注释来解释它。)