这是我第一次在多线程
中使用java.util.concurrent.atomic
包进行同步。我试图通过 java.util.concurrent.atomic
处理 Kathy Sierra 书中为 OCP 提供的 AccountDanger
类的经典示例。但我无法保护 balance
变量,即 AtomicInteger
不被过度撤回。下面是我的代码:
帐户类别
package p1;
import java.util.concurrent.atomic.AtomicInteger;
public class Account {
private AtomicInteger balance = new AtomicInteger(100);
public int getBalance() {
return balance.get();
}
public void withdraw(int amount) {
balance.addAndGet(-amount);
System.out.println("~~~~~~ " + balance);
}
}
AccountDanger 类
package p1;
public class AccountDanger implements Runnable {
private Account account = new Account();
private int amt = 10;
public void run() {
for (int i = 0; i < 10; i++) {
if (account.getBalance() >= amt) {
System.out.println(Thread.currentThread().getName() + " is going to withdraw..");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
account.withdraw(amt);
} else {
System.out.println("not enough balance");
}
if (account.getBalance() < 0) {
System.out.println("account is over withdrawn!!!");
}
}
}
public static void main(String[] args) throws InterruptedException {
AccountDanger ad = new AccountDanger();
Thread t1 = new Thread(ad, "Mark");
Thread t2 = new Thread(ad, "Phew");
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("final balance left is : " + ad.account.getBalance());
}
}
我知道,我肯定有哪里错了。任何人都可以纠正我的解决方案..
最佳答案
您没有以原子方式使用 AtomicInteger
(或者更确切地说,Account
)。
if(account.getBalance()>=amt){
// Other stuff
account.withdraw(amt);
其他线程可以改变“其他东西”内部的平衡。
在Account
中,您需要一个像这样的方法,使用 AtomicInteger.compareAndSet
:
boolean withdrawIfBalanceEquals(int balance, int amt) {
return this.balance.compareAndSet(balance, balance - amt);
}
仅当 AtomicInteger
的值仍等于 balance
时,才将其设置为 balance-amt
,并且然后返回true
。如果自从您读取其值后它已更改,compareAndSet
将返回 false
。
然后,在 AccountDanger
中,您可以像这样使用它:
int balance = account.getBalance();
if (balance >= amt) {
// Other stuff.
account.withdrawIfBalanceEquals(balance, amt);
}
我让您决定如何最好地处理 withdrawIfBalanceEquals
返回 false
的情况;一种方法是:
while (true) {
int balance = account.getBalance();
if (balance >= amt) {
// Other stuff.
if (account.withdrawIfBalanceEquals(balance, amt)) {
// If true, we don't have to keep looping: we withdrew the
// balance.
break;
}
// If false, keep going: you'll read the balance again,
// check if it's still greater than balance etc.
} else {
System.out.println("Not enough balance");
break;
}
}
关于java - 在减去值时无法控制 AtomicInteger 的原子行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48093529/