访问两个 AtomicIntegers 作为一个操作线程安全吗?

在 Brian Goetz 的Java Concurrency in Practice 中,有一个例子如下:


public class NumberRange {

  // INVARIANT: lower <= upper

  private final AtomicInteger lower = new AtomicInteger(0);

  private final AtomicInteger upper = new AtomicInteger(0);


  public void setLower(int i) {

    // Warning -- unsafe check-then-act

    if (i > upper.get())

    throw new IllegalArgumentException(

    "can't set lower to " + i + " > upper");

    lower.set(i);

  }


  public void setUpper(int i) {

    // Warning -- unsafe check-then-act

    if (i < lower.get())

      throw new IllegalArgumentException(

      "can't set upper to " + i + " < lower");

    upper.set(i);

  }


  public boolean isInRange(int i) {

    return (i >= lower.get() && i <= upper.get());

  }

}

我知道上面的代码容易出现竞争条件。


然后他解释如下:


像这样的多变量不变量创建了原子性要求:必须在单个原子操作中获取或更新相关变量。您不能更新一个,释放并重新获取锁,然后更新其他的,因为这可能涉及在释放锁时使对象处于无效状态。


我从这一段中了解到,如果我们创建setUpper和setLower函数synchronized,那么也会有对象可能达到无效状态的情况。但是,我认为如果两个函数都是同步的,那么只有一个线程可以执行其中一个函数,并且每个函数都必须检查不变量。我们怎么可能处于无效状态。任何人都可以用一个例子来演示。我在这里缺少什么?


如果我理解正确,那么这条线的意义是什么:


您不能更新一个,释放并重新获取锁,然后更新其他的,因为这可能涉及在释放锁时使对象处于无效状态。


慕桂英4014372
浏览 164回答 1
1回答

Helenr

来自“Java并发实践”一书:NumberRange 可以通过使用锁定来保持其不变性来实现线程安全,例如使用公共锁保护下层和上层。它还必须避免发布 lower 和 upper 以防止客户端破坏其不变量。这意味着以下代码是线程安全的:@ThreadSafepublic class NumberRange {&nbsp; &nbsp; @GuardedBy("this") private int lower, upper;&nbsp; &nbsp; public synchronized void setLower(int i) {&nbsp; &nbsp; &nbsp; &nbsp; if (i > upper) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; throw new IllegalArgumentException("can't set lower to " + i + " > upper");&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; lower = i;&nbsp; &nbsp; }&nbsp; &nbsp; public synchronized void setUpper(int i) {&nbsp; &nbsp; &nbsp; &nbsp; if (i < lower) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; throw new IllegalArgumentException("can't set upper to " + i + " < lower");&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; upper = i;&nbsp; &nbsp; }&nbsp; &nbsp; public synchronized boolean isInRange(int i) {&nbsp; &nbsp; &nbsp; &nbsp; return (i >= lower && i <= upper);&nbsp; &nbsp; }}在这种情况下,NumberRange提供自己的锁定以确保复合操作是原子的。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java