Java和同步问题

Java和同步问题,java,multithreading,class,concurrency,Java,Multithreading,Class,Concurrency,我正在用Java编写一个程序,我有点担心同步问题 这个场景非常“简单”,我们有一个简单的银行账户类,在这个类中,多人可以从账户中取款(尽管他们不能存款),他们还可以检查账户余额。问题是,余额一直在变化,因此我们希望客户查看正确的余额 到目前为止,这是我的班级 class Account implements Serializable { private boolean available = false; String ac_id; String name;

我正在用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();
    }

}
正如您可以看到的,通过这个实现,我可以确保有人可以从一个account对象获得资金,但是这个account对象被阻止了,然后一个解决方案出现了

public synchronized int chkBalance()   
添加
available=false的方法
这似乎解决了我的问题,但我真的不能说这是否正确,我的意思是它们是否确实同步,客户是否看到了正确的平衡

提前谢谢


理论上,如果我只是在这两种方法之前使用同步词,那不是很好吗?我的意思是,一次只有一个线程会占用每个方法,而且因为不需要存款,所以使用布尔值可用的true/false有什么意义呢?

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

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

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

不同步
chkBalance()
也很有用,因为您可能有许多来自不同线程的对
chkBalance()
的同时调用,并且这些调用没有必要互相等待


以确保您从共享内存中获得 BLNC <代码>的最新值,而不是本地缓存值,考虑生成<代码> BLNC < /C>变量Value.< /P> < P>我认为您在这里混合了:

  • getMoney是同步的,因此每次只有一个线程进入
  • 当available标志为true时,您将线程置于等待状态,直到有人调用notify(您自己在同步的同一线程中这样做)
为什么要混合等待/通知和同步?由于该方法已同步,因此不会有其他线程处于等待状态。。他们将阻止该方法的输入


老实说,除非您添加更多的逻辑,否则同步在这里并没有真正的用处:在getMoney中,您只对余额进行赋值。chckBalance方法要么在…之前执行,要么在…之后执行。。。无论如何,您永远不会有脏值的风险。

您根本不需要可用的布尔值。只同步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();
}
}
。。。多人可以从账户中取款[而且]他们还可以检查余额…[但是],余额一直在变化,因此我们希望客户查看正确的余额

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

问题出在这里。某些函数fubar()调用checkBalance()。为什么?为什么它关心平衡是什么?一旦checkBalance()返回,调用线程就不再同步。任何其他线程都可能在checkBalance()返回和fubar()处理信息之间进行取款


如果fubar()需要知道平衡才能处理信息,那么fubar()也需要同步。

我基本同意。在这条线周围需要某种同步
blnc-=money。否则,如果两个线程同时执行该行,则其中一个线程将无效。在getMoney中,您只对余额进行赋值:一点也不:代码检查余额,然后在授权的情况下将其递减。这是一个典型的先检查后执行操作,它不是原子操作,因此需要同步。如果没有同步,两个并发线程可能会从一个有1500个线程的帐户中各提取1000个,这正是该方法试图避免的。@JBNizet嘿,感谢您的输入,您是否同意在getMoney()之前使用简单的同步字就够了?关于chkBalance(),我们不需要同步,只需要对值进行volatile。这是我最初的想法,但如果可以的话,我需要某种形式的确认:染料,我同意,尽管使用volatile而不是同步
checkBalance()
方法看起来像是一种脆弱的、过早的优化。如果
getMoney()
方法修改余额两次,您将有一个错误:
checkBalance()
将返回一个中间余额值。@JBNizet谢谢。因此,解决这个可能的bug的方法是使用synchronized with volatile for checkBalance(),或者不可能使用bot