Вся конструкция должна быть переработана.
Класс должен инкапсулировать как можно больше своих внутренних объектов.В идеальном мире ни один другой класс не должен видеть поля или знать, когда и что синхронизировать / блокировать.Класс должен предоставлять осмысленные методы, которые отвечают на вопросы относительно этого экземпляра или изменяют состояние этого экземпляра из одного допустимого состояния в другое.
Концепция «действительного состояния» зависит от домена, но обычно включает в себя комбинации значений полей, например, при (упрощенном) пересечении улиц не все зеленые светофоры должны быть зелеными.Если такая ситуация временно возникает внутри метода изменения состояния, она не должна быть видна внешнему миру.
И использование ключевого слова synchronized
является одним (традиционным) способом достижения этого.Вы должны объявить synchronized
средство изменения состояния, а также все методы, на которые может повлиять недопустимое состояние.
Вам нужно только несколько объектов блокировки для одного экземпляра, если состояние разлагается на несколько независимых частей,части, которые могут быть изменены, не влияя друг на друга.Но тогда, если группы полей так слабо связаны, почему вы смоделировали это как один большой экземпляр вместо множества меньших?
Еще один момент: если вы позволяете другим классам изменять поля, которые являются критическимидля действительности экземпляра вы полностью нарушаете любую инкапсуляцию.Тогда вы больше не занимаетесь объектно-ориентированным программированием, а рассматриваете экземпляры как структуры, как в PASCAL в 1970-х и 1980-х годах.
Посмотрите на поточно-ориентированные классы из библиотеки Java, например, java.util.Vector
.Этот класс следует простому шаблону, чтобы позволить только одному потоку одновременно получать доступ к критическому коду, просто объявив некоторые базовые методы synchronized
, т.е. используя сам экземпляр в качестве объекта блокировки.