Java,转账服务和并发问题

时间:2017-07-20 07:00:22

标签: java concurrency transactions synchronized

我有这样的代码:

@Transactional(rollbackOn = RuntimeException.class)
    synchronized public void transfer(@NonNull final TransferModel transferModel) {
        log.info("Start processing money transfer from user: {} to receiver: {}. Transfer amount: {}", transferModel.getOwnerId(), transferModel
                .getReceiverId(), transferModel.getAmount());

        final AccountEntity ownerAccount = findByOwner(transferModel.getOwnerId());
        final AccountEntity receiverAccount = findByOwner(transferModel.getReceiverId());

        log.info("Owner balancer before transfer: {}. Receiver balance before transfer {}", ownerAccount.getBalance(), receiverAccount.getBalance());

        if (ownerAccount.getBalance().compareTo(transferModel.getAmount()) < 0) {
            throw new IllegalArgumentException("Owner has insufficient amount of money");
        }

        withdrawFromOwnerAccount(ownerAccount, transferModel.getAmount());
        depositToReceiverAccount(receiverAccount, transferModel.getAmount());

        log.info("Transfer money finished successful");
        log.info("Owner balancer after transfer: {}. Receiver balance after transfer {}", ownerAccount.getBalance(), receiverAccount.getBalance());
    }

简单的方法,从所有者采取moeny并传递给接收者。这种解决方案很幼稚,因为它不能同时处理多个转移。如何确保此方法可以处理多个请求并在并发环境中安全?

1 个答案:

答案 0 :(得分:2)

正如ghostCat所说,我们对你的环境并不熟悉,所以如果任何“看起来天真”的方法都有副作用,我们就不会知道了。

那就是说,假设这是一个非常简单直接的代码,方法名称反映了他们正在做的事情,我认为我们不必同步所有方法,而只是关键部分:

withdrawFromOwnerAccount(ownerAccount, transferModel.getAmount());
depositToReceiverAccount(receiverAccount, transferModel.getAmount());

我们可以使用帐户同步此部分:

synchronized (ownerAccount) {
    withdrawFromOwnerAccount(ownerAccount, transferModel.getAmount());
}
synchronized (receiverAccount) {
    depositToReceiverAccount(receiverAccount, transferModel.getAmount());
}

通过这样做,我们可以并行执行此方法,并仅在给予者/接收者已经处于执行另一个事务的过程中时锁定线程。

注意:为了应用这种方法,您必须确保同一帐户没有两个对象!