1

这段代码来自Fred Long的Java Concurrency Guidelines一书。我了解一组原子操作不是原子操作。所以下面的代码是不合规的。要查找代码,请查看第 23 页。

public class Adder {

    private AtomicReference<BigInteger> first;
    private AtomicReference<BigInteger> second;

    public Foo(BigInteger f, BigInteger s) {
        first = new AtomicReference<BigInteger>(f);
        second = new AtomicReference<BigInteger>(s);
    }

    public void update(BigInteger f, BigInteger s) {
        first.set(f);
        second.set(s);
    }

    public BigInteger add() {
        return first.get().add(second.get());
    }
}

正确的解决方案如下所示:

final class Adder {
    // ...
    public synchronized void update(BigInteger f, BigInteger s){
        first.set(f);
        second.set(s);
    }

    public synchronized BigInteger add() {
        return first.get().add(second.get());
    }
}

但我认为正确解决方案中的原子引用是多余的,因为synchronized它保证了可见性和原子性。

所以我的解决方案看起来像这样:

public class Addrer {

    private BigInteger first;
    private BigInteger second;

    public Addrer(BigInteger f, BigInteger s) {
        first = f;
        second = s;
    }

    public synchronized void update(BigInteger f, BigInteger s) {
        first = f;
        second = s;
    }

    public synchronized BigInteger add() {
        return first.add(second);
    }
}

我对吗?

4

1 回答 1

0

您需要将您的firstsecond字段设为私有,并将这些值公开为同步方法。否则直接读取字段可能会导致来自对象的过时或部分过时的数据BigInteger(非易失性字段读取不是线程安全的)。然后你的类将是线程安全的。

您可能会尝试使这些字段可变,但它不能保证您的update或方法的原子性,因为一个线程可能会在您的或方法在另一个线程中执行add的中间更新一个字段。updateadd

public class Adder {
    private BigInteger first;
    private BigInteger second;

    public Adder(BigInteger f, BigInteger s) {
        first = f;
        second = s;
    }

    public synchronized BigInteger getFirst() {
        return first;
    }

    public synchronized BigInteger getSecond() {
        return second;
    }

    public synchronized void update(BigInteger f, BigInteger s) {
        first = f;
        second = s;
    }

    public synchronized BigInteger add() {
        return first.add(second);
    }
}
于 2015-05-02T19:20:02.577 回答