首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >java线程和同步化

java线程和同步化
EN

Stack Overflow用户
提问于 2014-05-30 09:51:55
回答 4查看 124关注 0票数 1

这是K&B学习指南的代码

代码语言:javascript
复制
class Account {
private int balance = 50;
public int getBalance() {
  return balance;
}
public void withdraw(int amount) {
  balance = balance - amount;
}
}

public class AccountDanger implements Runnable {
private Account acct = new Account();
public static void main (String [] args) {
  AccountDanger r = new AccountDanger();
  Thread one = new Thread(r);
  Thread two = new Thread(r);
  one.setName("Fred");
  two.setName("Lucy");
  one.start();
  two.start();
 }
 public void run() {
 for (int x = 0; x < 5; x++) {
  makeWithdrawal(10);
  if (acct.getBalance() < 0) {
    System.out.println("account is overdrawn!");
  }
  }
  }
 private synchronized void makeWithdrawal(int amt) {
 if (acct.getBalance() >= amt) {
    System.out.println(Thread.currentThread().getName() 
                 + " is going to withdraw");
    try {
      Thread.sleep(500);
    } catch(InterruptedException ex) { }
    acct.withdraw(amt);
    System.out.println(Thread.currentThread().getName() 
                 + " completes the withdrawal");
 } else {
    System.out.println("Not enough in account for " 
                 + Thread.currentThread().getName() 
                 + " to withdraw " + acct.getBalance());
 }
 }
 }

我得到的结果就像

  1. 弗雷德要撤退了
  2. 佛瑞德完成了撤退
  3. 弗雷德要撤退了
  4. 佛瑞德完成了撤退
  5. 弗雷德要撤退了
  6. 佛瑞德完成了撤退
  7. 弗雷德要撤退了
  8. 佛瑞德完成了撤退
  9. 弗雷德要撤退了
  10. 佛瑞德完成了撤退
  11. 没有足够的帐户让露西提取0
  12. 没有足够的帐户让弗雷德提取0
  13. 没有足够的帐户让露西提取0
  14. 没有足够的帐户让弗雷德提取0
  15. 没有足够的帐户让露西提取0

然而,这本书的结果如下:

  1. 弗雷德要撤退了
  2. 佛瑞德完成了撤退
  3. 露西要撤退了
  4. 露西完成了撤回
  5. 弗雷德要撤退了
  6. 佛瑞德完成了撤退
  7. 露西要撤退了
  8. 露西完成了撤回
  9. 弗雷德要撤退了
  10. 佛瑞德完成了撤退
  11. 没有足够的帐户让露西提取0
  12. 没有足够的帐户让弗雷德提取0
  13. 没有足够的帐户让露西提取0
  14. 没有足够的帐户让弗雷德提取0
  15. 没有足够的帐户让露西提取0

任何人都可以帮我解释为什么会有这种区别。谢谢!

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2014-05-30 10:08:49

它可以按任何顺序发生。我想这本书想要展示的是:

如果有多方参与,即。XY

X is going to withdraw将严格地称为,后面是X completes the withdrawal,而绝不是Y ...,因为这两条语句都在synchronized方法中,这保证了一个和唯一一个< code >E 211线程可以在给定的时间点执行该代码块。

票数 3
EN

Stack Overflow用户

发布于 2014-05-30 10:10:06

这是因为您的同步块仅用于函数makeWithdrawal。首先,Fred调用makeWithdrawal,并在其他线程上阻止对该函数的调用,一旦函数停止,队列中的每个线程都会调用。这个案子是露西。要让弗雷德在其他人之前完成他的工作,请尝试阻止run方法的所有内容,如下所示

代码语言:javascript
复制
public synchronized void run() {
    for (int x = 0; x < 5; x++) {
        System.out.println(Thread.currentThread().getName()
                + " Start calling");
        makeWithdrawal(10);
        if (acct.getBalance() < 0) {
            System.out.println("account is overdrawn!");
        }
    }
}

代码语言:javascript
复制
public void run() {
    synchronized (this) {
        for (int x = 0; x < 5; x++) {
            System.out.println(Thread.currentThread().getName()+ " Start calling");
            makeWithdrawal(10);
            if (acct.getBalance() < 0) {
                System.out.println("account is overdrawn!");
            }
        }
    }
}
票数 0
EN

Stack Overflow用户

发布于 2014-05-30 10:20:11

我已经执行了你提供的代码。结果是:

代码语言:javascript
复制
Fred is going to withdraw
Fred completes the withdrawal
Lucy is going to withdraw
Lucy completes the withdrawal
Fred is going to withdraw
Fred completes the withdrawal
Lucy is going to withdraw
Lucy completes the withdrawal
Lucy is going to withdraw
Lucy completes the withdrawal
Not enough in account for Fred to withdraw 0
Not enough in account for Fred to withdraw 0
Not enough in account for Fred to withdraw 0
Not enough in account for Lucy to withdraw 0
Not enough in account for Lucy to withdraw 0

这是完全不同的结果,你上面提到的。当一个线程为一个对象执行同步方法时,调用同一对象同步方法的所有其他线程都会被阻塞,直到完成第一个线程为止。与同步方法退出时一样,它会自动建立发生关系,然后再与对同一对象的同步方法的任何后续调用建立关系。因此,每次输出都是不同的。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/23951667

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档