使用同步时不需要原子引用
Atomic references are unnecessary when using synchronized
此代码来自 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);
}
}
我说得对吗?
您需要将 first
和 second
字段设为私有并将这些值公开为同步方法。否则直接读取字段可能会导致来自 BigInteger
对象的数据过时或部分过时(非易失性字段读取不是线程安全的)。那么你的 class 将是线程安全的。
您可能会尝试使这些字段可变,但它不能保证您的 update
或 add
方法的原子性,因为一个线程可能会在您的 [=14] 中间更新一个字段=] 或 add
方法在另一个线程中执行。
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);
}
}
此代码来自 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);
}
}
我说得对吗?
您需要将 first
和 second
字段设为私有并将这些值公开为同步方法。否则直接读取字段可能会导致来自 BigInteger
对象的数据过时或部分过时(非易失性字段读取不是线程安全的)。那么你的 class 将是线程安全的。
您可能会尝试使这些字段可变,但它不能保证您的 update
或 add
方法的原子性,因为一个线程可能会在您的 [=14] 中间更新一个字段=] 或 add
方法在另一个线程中执行。
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);
}
}