1

假设您有以下课程

public class AccessStatistics {
  private final int noPages, noErrors;
  public AccessStatistics(int noPages, int noErrors) {
    this.noPages = noPages;
    this.noErrors = noErrors;
  }
  public int getNoPages() { return noPages; }
  public int getNoErrors() { return noErrors; }
}

然后执行以下代码

private AtomicReference<AccessStatistics> stats =
  new AtomicReference<AccessStatistics>(new AccessStatistics(0, 0));

public void incrementPageCount(boolean wasError) {
  AccessStatistics prev, newValue;
  do {
    prev = stats.get();
    int noPages = prev.getNoPages() + 1;
    int noErrors = prev.getNoErrors;
    if (wasError) {
      noErrors++;
    }
    newValue = new AccessStatistics(noPages, noErrors);
  } while (!stats.compareAndSet(prev, newValue));
}

在最后两行

newValue = new AccessStatistics(noPages, noErrors);
while (!stats.compareAndSet(prev, newValue)) 

这是否意味着新创建的 AccessStatistics 实例与当前的 AccessStatistics 实例具有相同的引用。怎么会这样 ?谁能解释一下。非常感谢。

4

2 回答 2

3

stats.compareAndSet(prev, newValue)如果持有的当前引用stats不是,将失败并返回 false prev

通常,在多线程环境中,很有可能在prev = stats.get();stats.compareAndSet(prev, newValue);另一个线程之间修改了stats.

stats.compareAndSet(prev, newValue);真的说:

  • 如果stats仍然持有对 的引用prev,就像之前的 5 行一样,则更新它以持有对 的引用newValue
  • 但是,如果另一个线程已经更改了stats自我上次检查 5 行以来所持有的引用,则丢弃我的计算并循环以重新计算一个新的newValue.
于 2012-07-15T15:56:50.287 回答
0

新创建的对象是新的。在它被创建的那一行之后,唯一引用它的是newValue. 没有别的可以——​​它怎么可能?如果在此期间没有其他任何设置,则唯一的compareAndSet()设置将其设置为第三个值,除了您知道的旧值prev和您制作的新值newValue

于 2012-07-15T15:57:25.880 回答