AtomicReference的getAndSet的一些疑问

场景:多线程对银行账户的金额进行扣款操作。
金额的数据类型为BigDecimal,我利用AtomicReference来处理这个并发场景。

public static void test(DecimalAccount account) {

List<Thread> ts = new ArrayList<>();

// 定义了1000个线程

for (int i = 0; i < 1000; i++) {

ts.add(new Thread(() -> {

// 每个线程会对对帐户余额做减10操作

account.withDraw(BigDecimal.TEN);

}));

}

ts.forEach(Thread::start);

}

class DecimalAccount {

private AtomicReference<BigDecimal> balance; // 账户余额

public DecimalAccount(BigDecimal balance) {

this.balance = new AtomicReference<>(balance);

}

public BigDecimal getBalance() {

return balance.get(); // 获取账户余额

}

/**

* 扣款操作

* @param amount 扣款金额

*/

public void withDraw(BigDecimal amount) {

balance.getAndSet(this.balance.get().subtract(amount));

}

}

测试:账户余额: 10000,调用test方法,test(new DecimalAccount(new BigDecimal(10000))); 期待的结果: 0,但是最后的结果并不是0。这是什么原因呢?是我getAndSet方法用的不对吗?
AtomicReference的getAndSet的一些疑问
如果我把withDraw()方法改为下面的形式,最后的结果就是0, 但是下面的代码实现方式不就是类似getAndSet源码的写法吗?

public void withDraw(BigDecimal amount) {

while(true) {

BigDecimal prev = balance.get();

BigDecimal next = balance.get().subtract(amount);

if (balance.compareAndSet(prev, next)) {

break;

}

}

}

可能是小的哪里理解有问题,希望大佬们能帮我指点一下。跪谢!!

回答

第一种写法拆开

    BigDecimal b = balance.get();

BigDecimal newBalance = b.subtract(amount);

balance.getAndSet(newBalance);

每一行都是原子操作,三行放在一起不是原子操作,又没有锁,于是线程不安全
第二种写法是解决方法之一,加锁也可以

以上是 AtomicReference的getAndSet的一些疑问 的全部内容, 来源链接: utcz.com/a/64251.html

回到顶部