[英]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.