更好的解决方案而不是Java中的嵌套同步块? [英] Better solution instead of nested synchronized blocks in Java?

查看:110
本文介绍了更好的解决方案而不是Java中的嵌套同步块?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有银行类,其中包含帐户列表。银行有一个 transfer()方法,用于将值从一个帐户转移到另一个帐户。我们的想法是在转移中将锁定到帐户。

I have a Bank class with a list of Account. The bank has a transfer() method to transfer a value from one account to another. The idea is to lock both the from and to accounts within a transfer.

要解决这个问题,我有以下代码(请记住,这是一个非常简单的例子,因为它只是一个例子):

To solve this issue I have the following code (please bear in mind that this is a very trivial example because it's just that, an example):

public class Account {
    private int mBalance;

    public Account() {
        mBalance = 0;
    }

    public void withdraw(int value) {
        mBalance -= value;
    }

    public void deposit(int value) {
        mBalance += value;
    }
}

public class Bank {
    private List<Account> mAccounts;
    private int mSlots;

    public Bank(int slots) {
        mAccounts = new ArrayList<Account>(Collections.nCopies(slots, new Account()));
        mSlots = slots;
    }

    public void transfer(int fromId, int toId, int value) {
        synchronized(mAccounts.get(fromId, toId)) {
            synchronized(mAccounts.get(toId)) {
                mAccounts.get(fromId).withdraw(value);
                mAccounts.get(toId).deposit(value);
            }
        }
    }
}

这个有效,但不能阻止死锁。要解决此问题,我们需要将同步更改为以下内容:

This works, but does not prevent deadlocks. To fix that, we need to change the synchronization to the following:

synchronized(mAccounts.get(Math.min(fromId, toId))) {
    synchronized(mAccounts.get(Math.max(fromId, toId))) {
        mAccounts.get(fromId).withdraw(value);
        mAccounts.get(toId).deposit(value);
    }
}

但编译器警告我嵌套同步阻止,我相信这是一件坏事吗?此外,我不是非常喜欢最大/最小解决方案(我不是那个提出这个想法的人),如果可能的话我想避免这种情况。

But the compiler warns me about nested synchronization blocks and I trust that that is a bad thing to do? Also, I'm not very fond of the max/min solution (I was not the one who came up with that idea) and I would like to avoid that if possible.

如何解决上述2个问题?如果我们可以锁定多个对象,我们会将锁定到帐户,但我们可以'这样做(据我所知)。那么解决方案是什么?

How would one fix those 2 problems above? If we could lock on more than one object, we would lock both the from and to account, but we can't do that (as far as I know). What's the solution then?

推荐答案

锁定顺序确实是解决方案,所以你是对的。编译器警告你,因为它无法确保所有你的锁被命令 - 它不够聪明,无法检查你的代码,而且足够聪明,知道可能还有更多。

Lock ordering is indeed the solution, so you're right. The compiler warns you because it cannot make sure all your locking is ordered—it's not smart enough to check your code, and smart enough to know there may be more.

另一种解决方案可能是锁定封闭物体,例如对于一个用户帐户内的转帐,您可以锁定用户。用户之间的转移不是这样。

An alternative solution could be locking on an enclosing object, e.g. for transfers within one user's account you could lock on user. Not so with transfers between users.

话虽如此,您可能不会依赖Java锁定来进行传输:您需要一些数据存储,通常是数据库。在使用数据库的情况下,锁定移动到存储。但是,同样的原则仍然适用:您订购锁以避免死锁;你升级锁以使锁定更简单。

Having said that, you are not probably going to rely on Java locking in order to make a transfer: you need some data storage, usually a database. In case of using a database, the locking moves to the storage. Still, the same principles apply: you order locks to avoid deadlocks; you escalate locks to make locking simpler.

这篇关于更好的解决方案而不是Java中的嵌套同步块?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆