Java 面试线程编程测试。他们想要什么答案?

标签 java multithreading

编辑: 我添加了下面使用的实现并且...

...我明白我做错了什么:而 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 包之外的外部依赖项。

其余的要求有点模糊。我结束了,在 缺少数据库,使用:

  1. 作为包含(我自己的)帐户的数据结构的 HashMap 对象。
  2. 一个 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/

相关文章:

java - 如何按频率而不是按字母顺序对字符串数组进行排序

java - 如何在 AEM 中以编程方式获取复制代理?

java.lang.ClassCastException 接口(interface)在 android java 上

java - 在Java中,可以发现当前执行的方法是什么?

multithreading - Haskell 中 ConcurrentHashMap 的类比是什么?

java - 线程会降低 PC 速度并导致 java.lang.OutOfMemoryError

c - 同一台机器相同的程序不同的cpu时间。为什么?

java - 关于Java泛型,如何获取类

java - 未从 Intent 接收数据

multithreading - 当线程数翻倍时,我的矩阵乘法程序需要四倍的时间