Java和同步问题
我正在用Java编写一个程序,我有点担心同步问题 这个场景非常“简单”,我们有一个简单的银行账户类,在这个类中,多人可以从账户中取款(尽管他们不能存款),他们还可以检查账户余额。问题是,余额一直在变化,因此我们希望客户查看正确的余额 到目前为止,这是我的班级Java和同步问题,java,multithreading,class,concurrency,Java,Multithreading,Class,Concurrency,我正在用Java编写一个程序,我有点担心同步问题 这个场景非常“简单”,我们有一个简单的银行账户类,在这个类中,多人可以从账户中取款(尽管他们不能存款),他们还可以检查账户余额。问题是,余额一直在变化,因此我们希望客户查看正确的余额 到目前为止,这是我的班级 class Account implements Serializable { private boolean available = false; String ac_id; String name;
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()
的同时调用,并且这些调用没有必要互相等待
以确保您从共享内存中获得
- 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