Понимание синхронизированного блока в Java - PullRequest
2 голосов
/ 22 июня 2011

Я пытаюсь понять концепцию синхронизации на объекте. Используя этот пример из Java Cert Book, вы можете помочь мне понять разницу в поведении между следующими 2 частями кода (один, где мы синхронизируемся с объектом, методы / операции которого мы хотим защитить от состояния гонки, и другой, где мы используем вспомогательный объект как замок для достижения той же цели):

1.

class Client {
  BankAccount account;

  public void updateTransaction() {
    synchronized (account) {     
      account.update();          // update is safe because of lock on account obj
    }
  }

  public double withdrawFunds() {
     double amt;
     synchronized (account) {
       account.calculateInterest();
       amt= account.withdraw();
     }
     return amt;
  }
}

2.

class Client {
  BankAccount account;
  Object lock = new Object();

  public void updateTransaction() {
    synchronized (lock) {     
      account.update();          // update is safe because of a lock        
    }
  }

  public double withdrawFunds() {
     double amt;
     synchronized (lock) {
       account.calculateInterest();
       amt= account.withdraw();
     }
     return amt;
  }
}

Ответы [ 6 ]

3 голосов
/ 22 июня 2011

Оба они будут генерировать исключения NullPointerException, но только в разных местах.

Вы всегда должны синхронизироваться по неизменной ссылке, которая никогда не будет нулевой (окончательной).

Полагаю, ответ на ваш вопрос заключается в том, что учетная запись потенциально может измениться для данного клиента (при условии, что есть установщик), но блокировка никогда не должна. Опять же, единственный способ гарантировать это - пометить его как окончательный.

2 голосов
/ 22 июня 2011

Лучший подход - избегать блокировки, когда она может быть заключена в капсулу.

class Client {
  final BankAccount account;

  public void updateTransaction() {
      account.update();          // update is synchonized.
  }

  public double withdrawFunds() {
     return account.calculateInterestAndWithdraw();
  }
}
1 голос
/ 22 июня 2011

Разница заключается в том, что другие потоки делают в вашей системе.В первом случае, если есть какие-либо причины, по которым некоторая другая логика (определенная в некотором другом коде) не должна использоваться одновременно с методом updateTransaction, эта логика также может быть синхронизирована с объектом account.И наоборот, у вас может быть ложная синхронизация, если какой-то не связанный код также использует учетную запись в качестве блокировки, когда он не имеет никакого отношения к updateTransaction.

Во втором случае объект блокировки виден только классу Client, поэтомувам гарантируется, что единственная синхронизация, которую вы выполняете, - это то, что вы указали в этом классе.

Я согласен с Питером Лоури, что лучший подход заключается в инкапсуляции логики синхронизации в одном месте, где это имеет смысл, ииспользуйте для этого закрытые / защищенные объекты блокировки видимости.

1 голос
/ 22 июня 2011

Разница в том, кто держит Замок.

Первый случай лучше, потому что та же ссылка на учетную запись может также использоваться в другом потоке, например, в классе Manager, и если этому менеджеру требуется доступ к учетной записи, следует попытаться удержать блокировку Сам в любом случае, что поток Client пытается получить доступ к учетной записи одновременно.

Во втором коде Manager необходимо заблокировать объект lock, чтобы предотвратить повреждение данных, поэтому необходимо получить учетную запись и блокировку.

Лучший подход заключается в инкапсуляции блокировки внутри учетной записи.

1 голос
/ 22 июня 2011

В этих двух случаях нет никакой разницы, но есть стилистическая разница.

Если учетная запись может быть изменена, существует потенциальная проблема, которая может быть синхронизирована с неправильным объектом.Сделайте это свойство окончательным, и вы готовы.

0 голосов
/ 22 июня 2011

Я бы использовал вариант 2, просто сделайте объект блокировки окончательным.Возможно, объект учетной записи можно изменить, особенно если клиент может иметь более одной учетной записи.Если вы используете последний объект блокировки, вы убедитесь, что любое изменение в учетной записи синхронизировано, даже если объект учетной записи изменяется на другой экземпляр.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...