我正在用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。从理论上讲,如果我只是在这两种方法之前使用同步词,那么它会不会好起来?我的意思是,一次只有一个线程占用每个方法,并且由于不需要存款,使用布尔值可用的真/假是什么意思?
答案 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中你只能对天平进行分配。 chckBalance方法要么在...之前执行,要么就在......之后执行。你永远不会冒险使用脏值。