Главная » Java » Методы synchronized Java

0

 

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

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

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

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

Класс BankAccount (банковский счет), предназначенный для выполнения в многопоточной среде, мог бы выглядеть следующим образом:

Сass BankAccount {

private long number;

 private long balance;

public BankAccount(long initialDeposit) {

 balance = initialDeposit;

}

public synchronized long getBalance() {

 return balance;

}

public synchronized void deposit(long amount) {

 balance += amount;

}

// … другие методы

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

Поле balance защищено от асинхронных изменений, поскольку доступ к неограничен методами, обозначенными признаком synchronized. Если значение поля изменяется, оно не может быть считано другим потоком до тех пор, а первый не завершит операцию сохранения. Если бы один поток мог читать даннные во время записи их другим потоком, целостность и достоверность считанной информации гарантировать было бы нельзя. Схема синхронизированных действий "запросить-изменить-сохранить данные" предполагает, что значение

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

обращения к полям public или protected: используя методы мы можем cсинхронизировать процессы обращения к данным, отчего никоим образом нельзя достичь, если поля допускают прямое обращение из кода, расположенного за пределами класса.

Используя объявления synchronized, мы можем поручиться, что несколько выполняющихся потоков не будут "пересекаться" друг с другом. Каждый из методов выполняется на правах взаимоисключающего владения объектом – как только стартует один из методов, все другие вызовы любых методов объекта откладываются и могут быть реализованы только после того, как первый завершит работу. Однако система не может предоставить гарантии строгого порядка выполнения операций. Если запрос на чтение содержимого поля balance выдается приблизительно в тот же момент времени, что и вызов метода изменения значения поля, один из них определенно выполнится раньше другого, но мы не можем точно предсказать, какой именно. Если необходимо обеспечить определенный порядок выполнения операций, потоки обязаны координировать свои действия каким-то особым образом, зависящим от назначения и характеристик конкретного приложения.

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

Статические методы synchronized

Модификатор synchronized допускается применять и в объявлениях статических методов. Каждому классу ставится в соответствие объект типа Class. Статические синхронизированные методы класса овладевают блокировкой соответствующего объекта Class. Два потока не могут одновременно вызывать статические synchronized методы одного класса – то же запрещено, как было сказано выше, и в отношении нестатических синхронизированных методов конкретного объекта класса. Если к статическим данным могут обращаться различные потоки, доступ к данным должен предоставляться только через посредничество соответствующих статических synchronized -методов.

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

По теме:

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