compareAndSet() 没有按预期工作
compareAndSet() does not work as expected
我自己编写了 AtomicDouble class 并且我还有一个 BankAccount class 可以执行两个简单的取款和存款操作并且它有一个 AtomicDouble 实例(平衡)。我的代码的问题是,当我在 deposit() 中调用 addAndGet 方法时,程序陷入死循环,并且 compareAndSet()从来没有 returns 真正的价值,但是当我调试这个时, currentValue 和来自 atomic.get () 的值是相等的,但是这个方法不明白。
有趣的是,当我把 if (atomic.get()==currentValue) 而不是 if (atomic.compareAndSet(currentValue, nextValue) ), 程序运行正常
public class AtomicDouble extends Number {
private final AtomicReference<Double> atomic;
public AtomicDouble() {
this(0.0);
}
public AtomicDouble(double initialValue) {
atomic = new AtomicReference<>(initialValue);
}
public final double addAndGet(double delta) {
while (true) {
double currentValue = atomic.get();
double nextValue = currentValue + delta;
if (atomic.compareAndSet(currentValue, nextValue))
return nextValue;
}
}
public final double incrementAndGet() {
return addAndGet(1);
}
public final void set(double newValue) {
atomic.set(newValue);
}
public final double get() {
return atomic.get();
}
public final double getAndSet(double newValue) {
return atomic.getAndSet(newValue);
}
public float floatValue() {
return (float) get();
}
@Override
public double doubleValue() {
return get();
}
public int intValue() {
return (int) get();
}
public long longValue() {
return (long) get();
}
public String toString() {
return Double.toString(get());
}
}
public class BankAccount {
private final AtomicDouble balance;
private String accountNumber;
public BankAccount(double balance, String accountNumber) {
this.balance = new AtomicDouble(balance);
this.accountNumber = accountNumber;
}
public void deposit(double number, String color) {
System.out.println(color + "deposit " + number + " current balance=" + balance.addAndGet(number));
}
public void withdraw(double number, String color) {
if (this.balance.get() - number >= 0) {
System.out.println(color + "Withdraw " + number + " current balance=" + balance.addAndGet(-number));
return;
}
System.out.println(color + "Not enough balance");
}
public static void main(String[] args) {
BankAccount bankAccount = new BankAccount(1000.0, "4234236");
ExecutorService threadsPool = Executors.newFixedThreadPool(2);
threadsPool.execute(new Runnable() {
@Override
public void run() {
bankAccount.deposit(300.0, ThreadColor.ANSI_YELLOW);
bankAccount.withdraw(50.0, ThreadColor.ANSI_YELLOW);
}
});
threadsPool.execute(new Runnable() {
@Override
public void run() {
bankAccount.deposit(203.75, ThreadColor.ANSI_BLUE);
bankAccount.withdraw(100.0, ThreadColor.ANSI_BLUE);
}
});
threadsPool.shutdown();
}
}
输出:没有输出
我想这是因为自动装箱。您不能引用 double
,您可以引用 Double
。
每次循环时操作数都会“重新装箱”,因此引用永远不会相同。也就是说,currentValue
中的引用永远不会与 atomic
中的引用相同。
尝试使用 currentValue
引用类型。
public final double addAndGet(double delta) {
while (true) {
Double currentValue = atomic.get();
Double nextValue = currentValue + delta;
if (atomic.compareAndSet(currentValue, nextValue))
return nextValue;
}
}
(幸运的是,Double 是一个不可变类型,否则会有竞争风险)
我自己编写了 AtomicDouble class 并且我还有一个 BankAccount class 可以执行两个简单的取款和存款操作并且它有一个 AtomicDouble 实例(平衡)。我的代码的问题是,当我在 deposit() 中调用 addAndGet 方法时,程序陷入死循环,并且 compareAndSet()从来没有 returns 真正的价值,但是当我调试这个时, currentValue 和来自 atomic.get () 的值是相等的,但是这个方法不明白。
有趣的是,当我把 if (atomic.get()==currentValue) 而不是 if (atomic.compareAndSet(currentValue, nextValue) ), 程序运行正常
public class AtomicDouble extends Number {
private final AtomicReference<Double> atomic;
public AtomicDouble() {
this(0.0);
}
public AtomicDouble(double initialValue) {
atomic = new AtomicReference<>(initialValue);
}
public final double addAndGet(double delta) {
while (true) {
double currentValue = atomic.get();
double nextValue = currentValue + delta;
if (atomic.compareAndSet(currentValue, nextValue))
return nextValue;
}
}
public final double incrementAndGet() {
return addAndGet(1);
}
public final void set(double newValue) {
atomic.set(newValue);
}
public final double get() {
return atomic.get();
}
public final double getAndSet(double newValue) {
return atomic.getAndSet(newValue);
}
public float floatValue() {
return (float) get();
}
@Override
public double doubleValue() {
return get();
}
public int intValue() {
return (int) get();
}
public long longValue() {
return (long) get();
}
public String toString() {
return Double.toString(get());
}
}
public class BankAccount {
private final AtomicDouble balance;
private String accountNumber;
public BankAccount(double balance, String accountNumber) {
this.balance = new AtomicDouble(balance);
this.accountNumber = accountNumber;
}
public void deposit(double number, String color) {
System.out.println(color + "deposit " + number + " current balance=" + balance.addAndGet(number));
}
public void withdraw(double number, String color) {
if (this.balance.get() - number >= 0) {
System.out.println(color + "Withdraw " + number + " current balance=" + balance.addAndGet(-number));
return;
}
System.out.println(color + "Not enough balance");
}
public static void main(String[] args) {
BankAccount bankAccount = new BankAccount(1000.0, "4234236");
ExecutorService threadsPool = Executors.newFixedThreadPool(2);
threadsPool.execute(new Runnable() {
@Override
public void run() {
bankAccount.deposit(300.0, ThreadColor.ANSI_YELLOW);
bankAccount.withdraw(50.0, ThreadColor.ANSI_YELLOW);
}
});
threadsPool.execute(new Runnable() {
@Override
public void run() {
bankAccount.deposit(203.75, ThreadColor.ANSI_BLUE);
bankAccount.withdraw(100.0, ThreadColor.ANSI_BLUE);
}
});
threadsPool.shutdown();
}
}
输出:没有输出
我想这是因为自动装箱。您不能引用 double
,您可以引用 Double
。
每次循环时操作数都会“重新装箱”,因此引用永远不会相同。也就是说,currentValue
中的引用永远不会与 atomic
中的引用相同。
尝试使用 currentValue
引用类型。
public final double addAndGet(double delta) {
while (true) {
Double currentValue = atomic.get();
Double nextValue = currentValue + delta;
if (atomic.compareAndSet(currentValue, nextValue))
return nextValue;
}
}
(幸运的是,Double 是一个不可变类型,否则会有竞争风险)