【问题标题】:Atomic references are unnecessary when using synchronized使用同步时不需要原子引用
【发布时间】:2015-05-02 17:35:04
【问题描述】:

此代码来自 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);
    }
}

我说的对吗?

【问题讨论】:

  • 如果您使 Adder 类不可变(如 BigInteger 或 String),则根本不需要任何同步,也不需要 volatile 或 AtomicReference。
  • @maraca 两种方法都是同步的。

标签: java multithreading atomicreference


【解决方案1】:

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

您可能会尝试使这些字段可变,但它不能保证您的 updateadd 方法的原子性,因为一个线程可能会在您的 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);
    }
}

【讨论】:

  • 我将它们设为私有。是的,如果我需要 getter,它们会被同步。
  • @maraca 我认为问题作者在我写完答案时或之后更新了问题。
  • @maraca Here 您可以检查问题的更改时间和内容,并与我的答案进行比较。让问题的作者和社区的其他人决定哪个答案是最好的。
  • @maraca 您能否详细说明我的回答有什么问题?什么是不正确的(尤其是在线程安全方面)?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-15
  • 1970-01-01
相关资源
最近更新 更多