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方法用的不对吗?
如果我把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;
}
}
}
可能是小的哪里理解有问题,希望大佬们能帮我指点一下。跪谢!!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
第一种写法拆开比较容易发现问题
每一行都是原子操作,三行放在一起不是原子操作,又没有锁,于是线程不安全,多线程下会有问题
第二种写法是解决方法之一,加锁也可以