Синхронизированный блок Java при доступе к полю класса A в классе B - PullRequest
0 голосов
/ 29 декабря 2018

Я хочу задать вопрос, связанный с синхронизацией в Java, и прояснить мои сомнения. Я написал простой код следующим образом:

class A {
 public int variable;
 public int secondVariable;
 public Object variableLock = new Object();
 public Object secondVariableLock = new Object();

 public void doingSthWithVariable() {
  synchronized (variableLock) {
  .... } } 

 public void doingSthWithVariableInOtherMethod() {
  synchronized (variableLock) {
  .... } }

 public void doingSthWithSecondVariable() {
  synchronized (secondVariableLock) {
  .... } }

 public void doingSthWithSecondVariableInOtherMethod() {
  synchronized (secondVariableLock) {
  .... } }

}

class B {
 public A instanceOfA;

 public void doingSthWithAVariables() {
  synchronized (instanceofA.variableLock) {
    synchronized (instanceofA.secondVariableLock) {
      ....} } }
 }

Мой вопрос: безопасен ли и является ли хорошей практикой использование variableLock?/ secondVariableLock из класса A в классе B?Я имею в виду, мне нужно заблокировать любое изменение этих двух переменных в случае класса B, и мне интересно, если это хороший способ сделать это.И еще вопрос: что если у меня один и тот же instanceOfA в нескольких объектах B?

Мне кажется, что ответ - да (это не небезопасно), но я просто хочу убедиться и спросить о лучших способах сделать это.

Ответы [ 2 ]

0 голосов
/ 29 декабря 2018

Вся конструкция должна быть переработана.

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

Концепция «действительного состояния» зависит от домена, но обычно включает в себя комбинации значений полей, например, при (упрощенном) пересечении улиц не все зеленые светофоры должны быть зелеными.Если такая ситуация временно возникает внутри метода изменения состояния, она не должна быть видна внешнему миру.

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

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

Еще один момент: если вы позволяете другим классам изменять поля, которые являются критическимидля действительности экземпляра вы полностью нарушаете любую инкапсуляцию.Тогда вы больше не занимаетесь объектно-ориентированным программированием, а рассматриваете экземпляры как структуры, как в PASCAL в 1970-х и 1980-х годах.

Посмотрите на поточно-ориентированные классы из библиотеки Java, например, java.util.Vector.Этот класс следует простому шаблону, чтобы позволить только одному потоку одновременно получать доступ к критическому коду, просто объявив некоторые базовые методы synchronized, т.е. используя сам экземпляр в качестве объекта блокировки.

0 голосов
/ 29 декабря 2018

Более распространенным способом было бы создать экземпляр ReadWriteLock и создать из него две блокировки записи и использовать их как в A, так и в B. И один и тот же экземпляр A будет использовать одни и те же блокировки

...