【问题标题】:Java, Transfer money service and concurrency issueJava,转账服务和并发问题
【发布时间】:2017-07-20 07:00:22
【问题描述】:

我有这样的代码:

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

简单的方法,从所有者那里获取金钱并传递给接收者。这种解决方案很幼稚,因为它一次不能处理多个传输。如何确保此方法可以处理多个请求并在并发环境中安全?

【问题讨论】:

  • 方法不能处理多个请求。方法被调用。在您的情况下,由于方法是同步的,这会按顺序发生。正如我们对您的环境的确切了解 - 应该如何理解当您并行执行此方法时究竟会发生什么?抱歉,这个问题太笼统了。

标签: java concurrency transactions synchronized


【解决方案1】:

正如 ghostCat 提到的,我们不熟悉您的环境,所以如果任何“看起来很幼稚”的方法有副作用,我们不会知道。

也就是说,假设这是一个非常简单明了的代码,并且方法名称反映了它们正在做什么,我认为我们不必同步 所有 方法,而只是关键部分:

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

我们可以使用账号同步这部分:

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

通过这样做,我们能够并行执行此方法,并且仅当发送方/接收方已经在执行另一个事务时才锁定线程。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-05-15
    • 1970-01-01
    • 2012-11-10
    • 2014-02-11
    • 1970-01-01
    • 2013-12-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多