ksm*_*001 6 java multithreading synchronized
我有一个名为"帐户"的班级
public class Account {
public double balance = 1500;
public synchronized double withDrawFromPrivateBalance(double a) {
balance -= a;
return balance;
}
}
Run Code Online (Sandbox Code Playgroud)
还有一个名为ATMThread的类
public class ATMThread extends Thread {
double localBalance = 0;
Account myTargetAccount;
public ATMThread(Account a) {
this.myTargetAccount = a;
}
public void run() {
find();
}
private synchronized void find() {
localBalance = myTargetAccount.balance;
System.out.println(getName() + ": local balance = " + localBalance);
localBalance -= 100;
myTargetAccount.balance = localBalance;
}
public static void main(String[] args) {
Account account = new Account();
System.out.println("START: Account balance = " + account.balance);
ATMThread a = new ATMThread(account);
ATMThread b = new ATMThread(account);
a.start();
b.start();
try {
a.join();
b.join();
} catch (InterruptedException ex) {
ex.printStackTrace();
}
System.out.println("END: Account balance = " + account.balance);
}
}
Run Code Online (Sandbox Code Playgroud)
我创建了两个主题,我们假设银行账户中有一个初始余额(1500美元)
第一个线程尝试撤销100 $和第二个线程.
我预计最终余额为1300,但有时候是1400.有人可以解释一下为什么吗?我正在使用同步方法......
Tom*_*icz 15
此方法是正确的,应该使用:
public synchronized double withDrawFromPrivateBalance(double a)
{
balance -= a;
return balance;
}
Run Code Online (Sandbox Code Playgroud)
它正确地将对帐户内部状态的访问限制为一次只有一个线程.但是你的balance领域是public(所以不是真正的内部),这是你所有问题的根本原因:
public double balance = 1500;
Run Code Online (Sandbox Code Playgroud)
利用public修饰符,您可以从两个线程访问它:
private synchronized void find(){
localBalance = myTargetAccount.balance;
System.out.println(getName() + ": local balance = " + localBalance);
localBalance -= 100;
myTargetAccount.balance = localBalance;
}
Run Code Online (Sandbox Code Playgroud)
这种方法,即使用synchronized关键字看起来正确,也不是.你正在创建两个线程,synchronized线程基本上是一个绑定到对象的锁.这意味着这两个线程具有单独的锁,每个都可以访问自己的锁.
想想你的withDrawFromPrivateBalance()方法.如果您有两个Account类实例,则可以安全地从两个不同对象上的两个线程调用该方法.但是,withDrawFromPrivateBalance()由于synchronized关键字,您无法从多个线程调用同一个对象.这有点类似.
您可以通过两种方式修复它:withDrawFromPrivateBalance()直接使用(注意synchronized这里不再需要):
private void find(){
myTargetAccount.withDrawFromPrivateBalance(100);
}
Run Code Online (Sandbox Code Playgroud)
或者锁定两个线程中的同一个对象,而不是锁定两个独立的Thread对象实例:
private void find(){
synchronized(myTargetAccount) {
localBalance = myTargetAccount.balance;
System.out.println(getName() + ": local balance = " + localBalance);
localBalance -= 100;
myTargetAccount.balance = localBalance;
}
}
Run Code Online (Sandbox Code Playgroud)
后一种解决方案明显不如前者,因为很容易忘记某处的外部同步.你也不应该使用公共领域.
您的private synchronized void find()方法正在同步不同的锁.尝试在相同的对象上同步它
private void find(){
synchronized(myTargetAccount){
localBalance = myTargetAccount.balance;
System.out.println(getName() + ": local balance = " + localBalance);
localBalance -= 100;
myTargetAccount.balance = localBalance;
}
}
Run Code Online (Sandbox Code Playgroud)
您还可以通过将其字段synchronized设为私有并将修饰符添加到其所有 getter和setter,然后仅使用此方法更改字段值来使您的Account类更安全.
| 归档时间: |
|
| 查看次数: |
12998 次 |
| 最近记录: |