首页 > 解决方案 > LongAdder:try 块怎么会失败?

问题描述

我正在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] 

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

标签: javaalgorithmtry-catchfinally

解决方案


Thread.stop由于从另一个线程调用不推荐使用的方法,此代码 - 以及版本 11 之前的任何其他 Java 代码 - 可能会失败。这会导致在ThreadDeath目标线程中抛出错误,可能随时发生。但是,线程至少可以存活足够长的时间以使finally块执行。

Thread.stop方法已被弃用,因为这种行为使其“本质上不安全”

为什么不推荐使用 Thread.stop?

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

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


推荐阅读