繁体   English   中英

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

[英]How to make a ConcurrentHashMap based method thread safe?

出于并发/多线程学习的目的,我正在开发一个小额转账API,该API将由多个用户同时调用。 我的“数据库”是ConcurrentHashMap<String, Double> ,其中的键/值对表示一个帐户ID及其当前余额。

我知道ConcurrentHashMap的单个操作( get()put()等)是线程安全的,但是withdraw / deposit方法将具有多个方法调用,这些调用最终将使其变为线程安全的。

我的问题:如何设计我的提现/存款方法是线程安全的? 最初,我考虑过使它们synchronized ,但这没有任何意义,因为我将丢弃ConcurrentHashMap细粒度内置同步机制。

这些都是我的提款和存款方法(在这里不必担心Double for money,在这种情况下这无关紧要):

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);
}

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

我认为仅通过使用具有某些原子类型的ConcurrentHashMap来解决此类任务是不可能的。

想象一下一种情况,将一个帐户中的钱转移到另一个帐户中。 在这种情况下,您不需要同时在一个Map元素上同步,而是在两个帐户上同步。 这称为交易。 因此,您需要做的是实现事务。 交易应锁定所有受影响的帐户,并在完成后释放它们。

作为另一种选择,您可以只创建带有事务的线程安全队列,然后依次执行所有事务,并且不需要ConcurrentHashMap nither同步,但是这可能与您要研究的部分无关。

Java内部有许多并发解决方案,为了使用正确的并发解决方案,您需要回答一个简单的问题:我的应用程序大部分时间都在做什么? 读或写操作?

如果它执行写入(撤回/存款),我建议使用java.util.concurrent.atomic.DoubleAdder实例而不是Double这将确保线程安全并在写入方面增加您的应用程序吞吐量。

通常,此类应用适合Actors模型。 每个帐户都可以由一个演员代表。 参与者将支持一些消息类型,例如:提款/存款/总计。 AKKA框架是actor模型的出色实现。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM