"синхронизировано (это)" против "синхронизировано ((BaseClass) это)" в Java? - PullRequest
10 голосов
/ 05 января 2012

Это преемник моего предыдущего вопроса, Безопасно ли получить доступ к этой переменной с помощью синхронизации?

Для следующей программы,

Class SubClassB extends SuperClassA {
     protected int c;

     public void inc() {
          synchronized (this) {
               c++;
          }
     }

     public void dec() {
          synchronized ( (SuperClassA) this) {
               c--;
          }
     }
}

Будет ли доступ к счетчику "с" безопасным для потоков? Я не уверен, что в методе "dec ()" ли ссылка SuperClassA на "this" является допустимым объектом для синхронизированного блока? Если да, блокируют ли два синхронизированных блока один и тот же объект "this"? (Как мне кажется, «(SuperClassA) this» не равно «this»)

Этот странный смоделированный код взят из следующего примера из реальной жизни, где SuperClassA является базовым классом, который не должен изменяться,

Class SuperClassA {
     protected int c;

     public void dec() {
          synchronized (this) {
               c--;
          }
     }
}

Class SubClassB extends SuperClassA {

     public void inc() {
          synchronized (this) {
               c++;
          }
     }

     public void dec() {
          super.dec();
     }
}

В этом примере метод dec () в SubClassB вызывает метод dec () своего суперкласса, который выполняет блокировку для объекта this, который я предполагаю, чтобы он был SuperClassA.this. Если заблокированный объект в методе "inc ()" в SubClassB не совсем совпадает с заблокированным объектом в методе "dec ()" в SubClassB, то мне интересно, что разные потоки НЕ могут безопасно получить доступ к унаследованному счетчику "c" в различных потоках , Я чувствую, что есть некоторая неопределенность в использовании ссылки "this" в синхронизированных блоках.

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

Class SubClassB extends SuperClassA {

     public void inc() {
          synchronized (this) {
               c++;
          }
     }

     public void dec() {
          synchronized (this) {
               super.dec();
          }
     }
}

Но кажется, что такой добавленный блок не элегантен и может быть избыточным!

Есть ли у кого-нибудь идеи по этим вопросам? Заранее спасибо.

Лоуренс

Ответы [ 4 ]

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

Код является поточно-ориентированным, поскольку (SomeObject) this adn this - это один и тот же объект.Приведение не преобразует объект в другой объект.

Однако в коде отсутствует инкапсуляция, поскольку он позволяет любому подклассу обращаться к защищенному полю c несинхронизированным способом.Таким образом, любой подкласс может использовать c++ или c-- без какой-либо синхронизации.Поле должно быть приватным.

5 голосов
/ 05 января 2012

Будет ли доступ к счетчику "c" потокобезопасным?

Да, он использует тот же объект блокировки.

Я не уверен, что вметод "dec ()", является ли приведенная в SuperClassA ссылка "this" действительным объектом для синхронизированного блока?

Да.

Если да, будут ли двасинхронизированные блоки блокируют один и тот же «этот» объект?(Как мне кажется, «(SuperClassA) this» не равно «this»)

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

[...] Но, похоже, такой добавленный блокне элегантно и может быть избыточным!

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

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

мне кажется, что "(SuperClassA) this" не равно "this"

Wrong;синхронизация выполняется для объектов, и приведение приводит только к изменению типа времени компиляции, это не влияет на идентичность объекта.

Таким образом, вам не нужно добавлять дополнительную синхронизацию в подкласс.

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

Все три примера верны с точки зрения синхронизации.

  1. С одним объектом связан только один монитор.
  2. Приведение this к базовому классу внутри synchronized не имеет значения.
  3. Для одного и того же объекта не имеет значения, вызывается ли synchronized(this) в контексте производного класса или базового класса: в обоих случаях используется одна и та же блокировка.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...