繁体   English   中英

LongAdder:try 块怎么会失败?

[英]LongAdder: How can the try block fail?

我正在详细分析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 在数组的边界内。

这很像在 jdk 代码本身的其他地方与ReentrantLock使用的模式。 这里的“模式”是你应该总是释放锁,即使发生了异常,所以通常代码写成:

Lock someLock...

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

由于cellsBusy (它从busy重命名)实际上是一个busy-spin lock ,所以这里的模式有点相同。 像这样:

cellsBusy = 0;

实际上是“释放锁”。 所以这并不是真正的失败,因为它是关于显式释放锁。 我发现这更容易阅读和推理代码。

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

不推荐使用Thread.stop方法, 因为此行为使其“本质上不安全”

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

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM