编辑: 我添加了下面使用的实现并且...
...我明白我做错了什么:而 AtomicInteger 平衡对象 (我认为)线程安全,涉及两个操作,即获取 当前余额,然后更新它。所以平衡可能会改变 在获取和更新之间。
尽管如此,我仍然想知道最好的解决方案是什么 他们在寻找什么。
(此外,就可扩展性而言,例如传输的潜力 余额,我故意不解决这个问题。似乎超出了 任务的范围。如果不是我就不好了)
<小时/>我刚刚在在家编程测试中得到了第二次负面回应 涉及潜在雇主提供的线索。
我不知道我给出的解决方案是否一定是错误的 - 可能只是没有 成为他们想要的人。但此时我很困惑并且没有 知道那是什么。
这基本上就是您遇到的 Java 问题:
public interface BalanceManagementSystem { //Edit: Changed name
/**
* Deduct 'amountToWithdraw' of the given 'accountId' from account.
* @param accountId The ID of the account to withdraw from
* @param amountToWithdraw The quantity to withdraw
* @return TODO: to be implemented
*/
WithdrawalResult withdrawFromAccount(String accountId, int amountToWithdraw);
/**
* Add 'amountToDeposit' of the given accountId to inventory.
* @param accountId The ID of the account to deposit to
* @param amountToDeposit The quantity to deposit
* @return TODO: to be implemented
*/
DepositResult depositToAccount(String accountId, int amountToDeposit);
}
...所以你必须使用线程安全的方法来实现接口(interface) 以上两个。我知道。
不能使用标准 JDK 包之外的外部依赖项。
其余的要求有点模糊。我结束了,在 缺少数据库,使用:
- 作为包含(我自己的)帐户的数据结构的 HashMap 对象。
- 一个 AtomicInteger,用于将余额存储在 Account 对象中,以 强制线程安全。
显然这不是他们想要的答案。我很确定 线程安全问题就是出错的地方。
因此,对于进行并评估线程测试的雇主或经理 像这样或通过了一项的员工,正在采取什么解决方案 要求?
<小时/>注意
用于存储的HashMap使用accountId作为key。
AtomicInteger不包含subtractAndGet(),所以我对它进行了子类化,创建了包含subtractAndGet()的AtomicIntegerPlus。 subtractAndGet() 只是对原生 addAndGet() 进行了轻微修改。
class Account {
private String accountId;
private AtomicIntegerPlus balance; //Thread-safe object subclassed from AtomicInteger
Account(String acctId, String loc, AtomicIntegerPlus amt) {
this.accountId = acctId;
this.balance = amt;
}
public void addToBalance(int amt) {
balance.addAndGet(amt);
}
public void subtractFromBalance(int amt) {
balance.subtractAndGet(amt);
}
}
class BMS implements BalanceManagementSystem {
private HashMap<String, Account> hashMap;
-
-
/**
* Deduct 'amountToWithdraw' of the given 'accountId' from account.
* @param accountId The ID of the account to withdraw from
* @param amountToWithdraw The quantity to withdraw
* @return withdrawalResult
*/
public WithdrawalResult withdrawFromAccount(String accountId, int amountToWithdraw) {
if (hashMap.containsKey(accountId)) {
Account tmpAccount = (Account)hashMap.get(accountId);
int balance = tmpAccount.getBalance();
if (balance >= amountToWithdraw) {
tmpAccount.subtractFromBalance(amountToWithdraw);
hashMap.put(tmpAccount.getAccountId(), tmpAccount); //Updatebalance with new amount
withdrawalResult.setMessage("Withdrawn. You now have " + tmpAccount.getBalance() + " left");
} else {
withdrawalResult.setMessage("Don't have the balance for your request. Only " + balance + " left");
}
} else {
withdrawalResult.setMessage("Sorry: account id " + accountId + " does not exist");
}
return withdrawalResult;
}
/**
* Add 'amountToDeposit' of the given accountId to inventory.
* @param accountId The ID of the account to deposit to
* @param amountToDeposit The quantity to deposit
* @return depositResult
*/
public DepositResult depositToAccount(String accountId, int amountToDeposit) {
if (hashMap.containsKey(accountId)) {
Account tmpAccount = (Account)hashMap.get(accountId);
tmpAccount.addToBalance(amountToDeposit);
hashMap.put(tmpAccount.getAccountId(), tmpAccount);// Update Balance with new amount
depositResult.setMessage("Deposited. You now have " + tmpAccount.getBalance() + " left");
} else {
depositResult.setMessage("Sorry: account id " + accountId + " does not exist");
}
return depositResult;
}
}
最佳答案
假设您的特定帐户有 1000 个。正在同时进行两次 900 的提款。您的基于 AtomicInteger 的解决方案是否确保您最终不会得到负数?它可以完成(例如通过循环中的compareAndSet),但与同步相比可能稍微过于复杂。
根据我的经验,实际问题(可能是您实现的后续)不仅仅是以线程安全的方式实现提款或存款,而是以线程安全的方式在两个帐户之间进行转账方式。您需要确保在并发交易的情况下不会 overdraw 帐户,并且如果您使用简单的同步方案并最终出现交叉转账,则不会陷入死锁。基于 AtomicInteger 的解决方案使得实现和推理变得相当困难(我仍然接受它,但你需要 100% 确定捍卫你的 CAS 逻辑)
关于Java 面试线程编程测试。他们想要什么答案?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42487619/