Java和同步问题

时间:2014-04-12 13:00:33

标签: java multithreading class concurrency

我正在用Java编写程序,我有点担心同步。

场景非常简单"我们有一个简单的银行帐户类,其中多人可以从帐户中提款(他们不能存款)他们也可以查看帐户的余额。问题是平衡总是在变化,所以我们希望客户查看正确的平衡!

到目前为止,这是我的班级。

    class Account implements Serializable {

    private boolean available = false;

    String ac_id;
    String name;
    int balance;

    public Account(String ac_id, String name, int blnc)

    {
        this.ac_id = ac_id;
        this.name = name;
        this.blnc = blnc;

    }

    public synchronized int getMoney(int money) {
        if (money > blnc) {
            return -1;
        }
        while (available == true) {
            try {
                wait();
            } catch (InterruptedException e) {
            }
        }

        blnc -= money;
        available = true;
        notifyAll();
        return 1;
    }

    public synchronized int chkBalance() {

        return blnc;
    }

    @Override
    public String toString()

    {
        return "Balance: " + chkBalance();
    }

}

正如您在此实现中所看到的,我可以确保某人可以从一个帐户对象获取资金,但此帐户对象被阻止,然后有一个解决方案

public synchronized int chkBalance()   

添加available = false;的方法似乎可以解决我的问题,但我真的不能说这是否正确,我的意思是如果它们确实是同步的并且客户看到了正确的平衡。

提前致谢!!

P.S。从理论上讲,如果我只是在这两种方法之前使用同步词,那么它会不会好起来?我的意思是,一次只有一个线程占用每个方法,并且由于不需要存款,使用布尔值可用的真/假是什么意思?

4 个答案:

答案 0 :(得分:2)

根本不需要可用的布尔值。仅仅同步getMoney方法并使blnc变为易失性就足够了,因此检查更改的其他线程将能够看到它们。尝试类似:

class Account implements Serializable {

final String ac_id;
final String name;
volatile int blnc;

public Account(String ac_id, String name, int blnc) {
    this.ac_id = ac_id;
    this.name = name;
    this.blnc = blnc;
}

public synchronized int getMoney(int money) {
    if (money > blnc) {
        return -1;
    }
    blnc -= money;
    return 1;
}

public int chkBalance() {
    return blnc;
}

@Override
public String toString() {
    return "Balance: " + chkBalance();
}
}

答案 1 :(得分:1)

如果您不关心执行速度,那么您需要做的就是使方法同步。这将保证一个特定帐户对象的每个方法一次只能由一个线程访问。您的available标记在您的实施中似乎没有用处。将wait()置于同步方法中也没有意义;这只会减慢等待对象锁定的其他线程。

同步getMoney()尤为重要,因为此方法会更改blnc的值,并且无法同步它可能导致两个线程同时覆盖该值,在这种情况下,一个线程会未能生效。

在您的实施中,如果chkBalance()被同步,那么它并不重要,因为它不会写入blnc。如果此方法与getMoney()同时调用,它将在更改blnc之前或之后返回blnc的值,并且此调度超出了程序员控制。

同步chkBalance()也很有用,因为您可能会有多个来自不同线程的chkBalance()同时调用,并且这些调用中没有任何一点等待。

要确保从共享内存中获取blnc的最新值,而不是本地缓存的值,请考虑将blnc变量设置为volatile。

答案 2 :(得分:0)

  

...多人可以从账户中提取资金[和]他们也可以查看余额...... [但],余额一直在变化,所以我们希望客户查看正确的余额!

你不能。如果其他人(线程)可以随时取款,那么就没有 正确的余额。您可以保证的最好的是 正确的余额。也就是说,通过适当的同步,您可以确保checkBalance()返回的数字在过去的某个时间点是正确的。

这就是问题所在。一些函数fubar()调用checkBalance()。为什么?为什么它关心平衡是什么?只要checkBalance()返回,调用线程就不再同步。任何其他线程都可能在checkBalance()返回的时间和fubar()对信息执行某些操作的时间之间进行撤销。

如果fubar()需要知道余额以便某些信息,那么fubar()也需要同步。

答案 3 :(得分:-1)

我认为你在这里混合:

  • getMoney已同步,因此每次只有1个线程进入
  • 当可用标志为真时,你将线程置于等待状态,直到某人调用notify(你自己做,在同步的同一个线程中)

为什么要混合等待/通知和同步?由于该方法是同步的,因此没有其他线程在等待......它们将在方法的条目上阻塞。

老实说,除非你为它添加更多逻辑,否则同步在这里并不实用:在你的getMoney中你只能对天平进行分配。 chckBalance方法要么在...之前执行,要么就在......之后执行。你永远不会冒险使用脏值。