如何使基于concurrenthashmap的方法线程安全?

zi8p0yeb  于 2021-07-12  发布在  Java
关注(0)|答案(2)|浏览(380)

出于并发/多线程学习的目的,我正在开发一个小型的资金转移api,它将由多个用户并发调用。我的“数据库”是一个 ConcurrentHashMap<String, Double> ,哪个键/值对表示帐户id及其当前余额。
我知道concurrenthashmap的单个操作( get() , put() 等等)是线程安全的,但是一个取款/存款方法会有几个方法调用,这些调用最终会使它不是线程安全的。
我的问题是:如何将取款/存款方法设计成线程安全的?一开始,我想做它们 synchronized ,但这没有任何意义,因为我将抛弃 ConcurrentHashMap .
这些都是我取钱和存款的方法(不用担心) Double 对于这里的钱,这在这里是无关紧要的):

private void deposit(ConcurrentHashMap<String, Double> myDatabase, String fromAccountId, String toAccountId, double amount) {
    if(myDatabase.get(fromAccountId) < amount) {
        throw new MonetaryOperationViolation("Insufficient funds to perform this operation");
    }

    //Add the amount to the receiver's account
    myDatabase.replace(toAccountId, myDatabase.get(toAccountId), c.get(toAccountId) + amount); //key, oldValue, newValue

    //Withdraw it from the sender's account
    withdraw(myDatabase, fromAccountId, amount);
}

private void withdraw(ConcurrentHashMap<String, Double> myDatabase, String accountId, double amount) {
    if(myDatabase.get(accountId) < amount) {
        throw new MonetaryOperationViolation("Insufficient funds to perform this operation");
    }

    myDatabase.replace(accountId, myDatabase.get(accountId), myDatabase.get(accountId) - amount);
}

我希望我已经把我的问题说清楚了。任何帮助都将不胜感激。

jaxagkaj

jaxagkaj1#

我不认为仅仅使用某种原子类型的concurrenthashmap就可以解决这样的任务。
想象一下,当一个账户的钱被转到另一个账户时。在这种情况下,您需要同步的不是一个Map元素,而是两个帐户同时进行。这就是所谓的交易。所以您需要做的是实现事务。事务应该锁定所有受影响的帐户,并在完成后释放它们。
作为另一种选择,您可以创建线程安全的事务队列,然后依次执行所有事务,您不需要concurrenthashmap或其他同步,但是这可能不是您要研究的部分。

wz1wpwve

wz1wpwve2#

java内部有许多并发解决方案,为了使用正确的解决方案,您需要回答一个简单的问题:我的应用程序大部分时间做什么?读或写操作?
如果它执行写操作(取款/存款),我建议使用 java.util.concurrent.atomic.DoubleAdder 示例而不是 Double 这将确保线程安全,并在写操作方面提高应用程序吞吐量。
一般来说,这类应用程序适合于actors模型。每个帐户可以由一个参与者来代表。actor将支持几种消息类型,例如:draw/deposit/total。akka框架是actor模型的优秀实现。

相关问题