对于并发/多线程学习的目的,我开发将由多个用户可以同时调用一个小的汇款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);
}
我希望我已经说清楚了关于我的问题。任何帮助,将真正的赞赏。
我不认为这是可以解决这样的任务只是用ConcurrentHashMap的一些原子类型。
试想一个情况下,当从一个账户的钱已经转移到另一个。在这种情况下,你需要同步两个帐户同时没有一个地图元素,但。这就是所谓的交易。所以,你需要做的就是实现交易。交易应该锁定所有受影响的acounts和整理后释放他们。
作为另一种选择,你可以只创建线程安全的队列,交易和做的所有交易sequently,你会不会需要也不ConcurrentHashMap的nither同步,但可能这是不是你正在试图研究的一部分。
Java的内部有并发多种解决方案,以使用正确的,你需要回答一个简单的问题:我的应用程序的大部分时间是什么?读或写操作?
如果它执行写操作(撤/存款)我会建议使用java.util.concurrent.atomic.DoubleAdder
实例,而不是Double
这将保证线程安全和提高你的应用程序吞吐量在写入方面。
在一般情况下,此类应用适合于演员模型。每个帐户可以由一个演员来表示。演员将支持一些消息类型,例如:抽取/存款/总。 AKKA framework是角色模型的一个很好的实施。