Java поток и синхронизированы

1

Вот код из K & B Study Guide

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

Любой может помочь мне объяснить, почему существует разница. Спасибо!

  • 0
    Вы получаете одинаковые результаты каждый раз?
  • 0
    Я думаю, что ваш результат должен быть 5 раз в конце Люси, а не Люси и Фред.
Показать ещё 2 комментария
Теги:
multithreading
synchronized

4 ответа

3
Лучший ответ

Это может произойти в любом порядке. Я предполагаю, что книга хочет показать:
Если есть несколько сторон, а именно. X и Y
X is going to withdraw, будет строго следовать X completes the withdrawal и никогда не Y... потому что оба эти утверждения находятся в synchronized методе, который гарантирует, что один и только один поток может выполнять этот блок кода на данный момент времени.

0

Это из-за вашего синхронизированного блока только для функции makeWithdrawal. Сначала Fred вызывает makeWithdrawal и блокирует вызов этой функции в другом потоке, как только функция останавливается, каждый поток в очереди обращается к вызову. Это дело Люси. Чтобы Фред закончил свою работу, прежде чем позволить другому сделать, попытайтесь заблокировать все содержимое метода 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!");
            }
        }
    }
}
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

Это совершенно другой результат, который вы упомянули выше. Когда один поток выполняет синхронизированный метод для объекта, все остальные потоки, которые вызывают синхронизированный метод для одного и того же объекта, блокируются до тех пор, пока не будет выполнен первый поток. так как когда синхронизированный метод завершается, он автоматически устанавливает связь между событиями и последующим вызовом синхронизированного метода для одного и того же объекта. Таким образом, выход различается каждый раз.

0

Когда я попробовал ваш код, NetBeans предупредил меня, что я использовал Thread.sleep в синхронизированном блоке. Что происходит с ним, так это то, что, поскольку он синхронизирован, другой поток не может работать в то же время, и ожидание в основном ничего.

Я попытался поставить сон в цикле, и порядок соблюден (даже если Netbeans предупреждает меня о sleep in a loop но на этот раз это бессмысленно)

Ещё вопросы

Сообщество Overcoder
Наверх
Меню