java线程和同步

时间:2014-05-30 09:51:55

标签: java multithreading synchronized

以下是K& B学习指南中的代码

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. Fred完成撤回
  3. 弗雷德将要退出
  4. Fred完成撤回
  5. 弗雷德将要退出
  6. Fred完成撤回
  7. 弗雷德将要退出
  8. Fred完成撤回
  9. 弗雷德将要退出
  10. Fred完成撤回
  11. 还不足以让露西撤回0
  12. 还不足以让Fred撤回0
  13. 还不足以让露西撤回0
  14. 还不足以让Fred撤回0
  15. 还不足以让露西撤回0
  16. 然而,这本书的结果是这样的:

    1. 弗雷德将要退出
    2. Fred完成撤回
    3. 露西将要退出
    4. Lucy完成撤回
    5. 弗雷德将要退出
    6. Fred完成撤回
    7. 露西将要退出
    8. Lucy完成撤回
    9. 弗雷德将要退出
    10. Fred完成撤回
    11. 还不足以让露西撤回0
    12. 还不足以让Fred撤回0
    13. 还不足以让露西撤回0
    14. 还不足以让Fred撤回0
    15. 还不足以让露西撤回0
    16. 任何人都可以帮我解释为什么会有区别。谢谢!

4 个答案:

答案 0 :(得分:3)

它可以以任何顺序发生。我想这本书想要展示的是:
如果有多方当事人。 XY
X is going to withdraw 严格后跟X completes the withdrawal从不 a Y ...,因为这两个语句都在{{1}内} method,保证一个且只有一个线程可以在给定的时间点执行该代码块。

答案 1 :(得分:0)

这是因为您的synchronized块仅适用于函数makeWithdrawal。 首先,Fred调用makeWithdrawal,并在其他线程上阻止对该函数的调用,一旦函数停​​止,队列中的每个线程都会转向调用。这个案子是露西。 为了让Fred在完成其他工作之前完成他的工作,尝试阻止run方法的所有内容,比如这个

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!");
        }
    }
}

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!");
            }
        }
    }
}

答案 2 :(得分:0)

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

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

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

答案 3 :(得分:0)

当我尝试使用您的代码时,NetBeans警告我,我在同步块中使用Thread.sleep。它发生的是同步其他线程无法同时运行,而等待基本上什么也没做。

我试图将睡眠置于循环中并且顺序得到尊重(即使Netbeans警告我sleep in a loop,但这次没有意义)