В чем разница между синхронизированным (этим) и синхронизированным (ClassName.class)? - PullRequest
13 голосов
/ 29 января 2012

Я где-то читал, что synchronized(this) следует избегать по различным причинам . И все же некоторый респектабельный код, с которым я столкнулся, использует в конструкторе следующее:

public SomeClass(Context context) {
  if (double_checked_lock == null) {
    synchronized (SomeClass.class) {
      if (double_checked_lock == null) {
        // some code here
      }
    }
  }
}

Есть ли разница между synchronized(this) и synchronized(SomeClass.class)?

Ответы [ 6 ]

26 голосов
/ 29 января 2012

synchronized(this) синхронизируется с текущим объектом, поэтому только один поток может получить доступ к каждому экземпляру, но разные потоки могут получить доступ к различным экземплярам.Например, у вас может быть один экземпляр на поток.

Это обычно полезно для предотвращения одновременного обновления объекта несколькими потоками, что может создать несогласованное состояние.

synchronized(SomeClass.class) синхронизируется при класс текущего объекта (или другого класса, если он того пожелает), поэтому только один поток может одновременно получить доступ к любым экземплярам этого класса.

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

6 голосов
/ 29 января 2012

this отличается для каждого экземпляра.
ClassName.class нет.

Следовательно, synchronized(this) позволит одновременно запускать несколько экземпляров.

3 голосов
/ 29 января 2012

Ключевое слово synchronized при применении к class блокировкам класса и при применении к this блокировкам текущего экземпляра объекта. Из спецификации языка Java, раздел 8.4.3.6, «синхронизированные методы» :

Синхронизированный метод получает монитор (§17.1) до его выполнения. Для метода класса (статического) используется монитор, связанный с объектом Class для класса метода. Для метода экземпляра используется монитор, связанный с этим (объект, для которого был вызван метод).

2 голосов
/ 30 января 2012

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

  • synchronized(this) получает блокировку экземпляра this для текущего потока.Метод может работать параллельно в разных экземплярах (разные значения для этого и, следовательно, разные блокировки)

  • synchronized(SomeClass.class) получает блокировку объекта глобального класса SomeClass.Только один экземпляр метода может быть запущен, так как все экземпляры объекта заблокированы для одного и того же глобального объекта (одна и та же блокировка).

1 голос
/ 29 января 2012

synchronized(this) синхронизируется на экземпляре объекта.

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

Таким образом, это разные конструкции с разной семантикой.

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

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

class MySharedResourceClass {

    private SomeClass lock = new SomeClass();

    public doSomething() {
        synchronized (lock) {
            // Do something here
        }
    }
}
1 голос
/ 29 января 2012

Это два разных объекта, которые нужно заблокировать: «this» относится к контексту текущего экземпляра, поэтому создание нескольких экземпляров не будет иметь эффекта, если, например, каждый поток использует другой экземпляр и блокирует его.«this» может упоминаться только в нестатическом контексте.
«class» является статическим членом класса Java, и существует только один его экземпляр.Вы можете заблокировать его как в статическом, так и в нестатическом контексте.

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