Главная » Java » Приемы синхронизации Java

0

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

Схема синхронизации на стороне клиента предполагает, что все клиенты, обладающие совместными правами доступа к объекту, при обращении к нему должны прежде запросить блокировку объекта, используя инструкции или методы synchronized. Подобное соглашение довольно непрочно, поскольку зиждется только на благих намерениях клиентов работать по правилам. Предпочтительно заставить совместно используемые объекты защищать свой код посредством собственных synchronized -методов (либо соответствующих synchronized -инструкций в теле методов). В этом случае клиенты просто не смогут использовать объект какими бы ни было несинхронизированными способами. Такой подход иногда называют Синхронизацией на стороне сервера (server-side synchronization), хотя, по большому счету, это просто расширение объектно-ориентированной концепции, достижение большей степени инкапсуляции характеристик поведения кода За счет сокрытия функций синхронизации.

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

 

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

х применения в практике проектирования программного обеспечения. Техника построения подобных синхронизированных реализаций-оболочек находит применение в классах коллекций (обратитесь к разделу 16.8.1 на странице 457).

Синхронизация, о которой мы говорили до сих пор, – это простейший из способов выражения понятия "безопасности потоков". Если подобные последовательности операций должны выполняться как единое целое, без синхронизации просто не обойтись. В случае многократных обращений к методу их можно поместить внутри другого метода и снабдить последний модификатором synchronized, но, вообще говоря, это не очень эффективно, поскольку нам вряд ли удастся определить все комбинации вызовов методов. Более того, на этапе проектирования класса мы можем и не знать, какие сочетания методов потребуются в дальнейшем. При необходимости выполнения операций над несколькими объектами возникает вопрос, куда именно следует поместить синхронизированный метод. В подобных случаях единственной разумной альтернативой будет синхронизация на стороне клиента, реализованная посредством synchronized -инструкций. Объект может блокироваться и запрещать обращение к любому из своих синхронизированных методов всем, кроме кодавладельца блокировки, выполняющего серию вызовов. Аналогичным образом можно запрашивать блокировку каждого отдельного объекта, участвующего в последовательности операций, а затем вызывать требуемые методы этого объекта, но при таком подходе следует учитывать опасность возникновения взаимоблокировки (deadlock). Если методы объекта уже синхронизированы относительно блокировки текущего объекта, в других фрагментах кода, использующих объект, нет необходимости применять синхронизацию на стороне клиента.

То, каким образом синхронизация осуществляется в пределах конкретного класса, зависит от особенностей реализации. Тот факт, что класс требует синхронизации доступа к его членам, является важной частью контракта класса и должен быть исчерпывающим образом документирован – наличие модификатора synchronized в объявлении метода может оказаться всего лишь частной деталью реализации класса, а не атрибутом контракта. Кроме того, механизм синхронизации, использованный в коде класса, также может быть документирован, если он представляет интерес для пользователей класса или тех программистов, которые займутся расширением последнего. Расширенному классу следует придерживаться политики синхронизации, оговоренной в контракте базового класса, и он сможет выполнить свою задачу только в том случае, если его автор осведомлен о том, что представляет собой такая политика, и обладает доступом к механизмам, которые ее поддерживают. Например, класс, использующий в качестве блокируемого объекта поле ргivate, воспрепятствует применению в расширенном классе того же механизма блокировки – расширенному классу придется определить свой собственный блокируемый объект (возможно, this) и переопределить каждый метод базового класса, чтобы реализовать новый механизм блокировки. Пользователям класса, вероятно, потребуется знать, какая схема синхронизации реализована, чтобы они могли безопасно применять синхронизацию на стороне клиента при многократном вызове методов объекта.

 

Упражнение 10.3. Создайте класс, объекты которого способны сохранять некоторое текущее значение в поле value и обладают методом add, позволяющим увеличивать содержимое value и выводить на экран результат операции. Напишите программу , которая создает объект класса, формирует несколько потоков и вызывает внутри каждого из них метод add. Учтите, что ни один из результатов сложения не должен быть утрачен.

 

Упражнение 10.4. Измените код решения упражнения 10.3 в предположении, что поле value и метод add являются статическими.

 

Упражнение 10.5. Измените код решения упражнения 10.4 в предположении, что Потоки должны быть способны безопасно изменять содержимое value без использования статического синхронизированного метода.

Источник: Арнолд, Кен, Гослинг, Джеймс, Холмс, Дэвид. Язык программирования Java. 3-е изд .. : Пер. с англ. – М. : Издательский дом «Вильяме», 2001. – 624 с. : ил. – Парал. тит. англ.

По теме:

  • Комментарии