首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >LongAdder:尝试块怎么会失败?

LongAdder:尝试块怎么会失败?
EN

Stack Overflow用户
提问于 2018-11-07 18:39:45
回答 2查看 124关注 0票数 5

我正在详细分析LongAdder算法。LongAdder扩展了类Striped64,在该类中,基本的方法是retryUpdate。以下代码取自此方法;在链接源代码中,它占据第212至222行:

代码语言:javascript
复制
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块怎么会失败?

注意,数组访问

代码语言:javascript
复制
rs[j = (m - 1) & h] 

不应该抛出IndexOutOfBoundsException,因为按位操作的结果总是小于或等于其整数参数的最小值,因此0 <= j <= m-1在数组的范围内。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-01-22 21:36:07

这很像jdk代码本身中任何地方与ReentrantLock一起使用的模式。这里的“模式”是您应该始终释放锁,即使发生了异常,所以通常将代码编写为:

代码语言:javascript
复制
Lock someLock...

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

由于cellsBusy(从busy重命名)实际上是一个繁忙的自旋锁,这里的模式也是一样的。因此:

代码语言:javascript
复制
cellsBusy = 0;

实际上是“释放锁”。因此,这实际上不是关于失败,而是关于显式地释放锁。我发现这要容易得多,并对代码进行推理。

票数 2
EN

Stack Overflow用户

发布于 2020-01-22 22:29:25

该代码--以及版本11之前的任何其他Java代码--可能会因为从另一个线程调用不推荐的Thread.stop方法而失败。这将导致在目标线程中引发ThreadDeath错误,可能在任何时候都是如此。但是,线程至少还活着吧足够长,足以执行finally块。

Thread.stop方法被废弃为因为这种行为使它“本质上不安全”

为什么不推荐Thread.stop? 因为它本身就是不安全的。停止线程会使其解锁其锁定的所有监视器。(当ThreadDeath异常在堆栈上传播时,监视器将被解锁。)如果以前受这些监视器保护的任何对象处于不一致状态,其他线程现在可能会以不一致的状态查看这些对象。据说这些物品被损坏了。当线程对损坏的对象进行操作时,可能会导致任意行为。这种行为可能是微妙的,很难发现,也可能是被宣布的。与其他未经检查的异常不同,ThreadDeath无声地杀死线程;因此,用户没有警告他的程序可能已损坏。腐败在实际损害发生后的任何时候都会显现出来,甚至在未来的几个小时或几天内。

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

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/53195759

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档