![](/user_photo/2706_HbeT2.jpg)
GrandM-Patterns_in_Java
.pdf![](/html/2706/346/html_MxkKzTLKJz.Ja4Q/htmlconvd-LkZgZ6441x1.jpg)
Single Threaded Execution 8 449
ПРИМЕНЕНИЕ В JAVA API
сМногие методы класса j ava . u t i l . Vector являются синхронизированными целью обеспечения последовательного доступа к внутренним структурам дан
ных объектов Vector.
ПРИМЕР КОДА
Приведем код, реализуюший проект для сенсора движения транспорта, рас смотренный в разделе «(Контекст». Сначала приводится код для класса Traf ficSensor. Экземпляры класса Traf ficSensor связаны с сенсором движения транспорта, который фиксирует прохождение машиной некоторого места на полосе движения. В этот момент вызывается метод detect экземпляра, отве чаюший за оповешение всех заинтересованных объектов о прохождении транс портного средства.
public class TrafficSensor implements Runnable ( private TrafficObserver oЬserver;
/ * *
*Constructor
*@param observer
* |
Объект, предназначенный для оповещения о том, что сенсор |
* |
движения транспорта, связанный с этим объектом, |
*обнаруживает проходящую машину.
* / |
|
|
|
public TrafficSensor (TrafficObserver observer) ( |
|||
|
this . observer = observer ; |
|
|
|
new Thread (this) . start ( ) ; |
|
|
|
/ / cons tructor (TrafficObserver) |
|
|
/ * * |
|
|
|
* |
Общая логика для потока этого объекта . |
||
* / |
|
|
|
public void run () |
( |
|
|
} |
monitorSensor () |
; |
|
/ / run ( ) |
|
|
|
|
|
|
|
/ / |
Этот метод вызывает метод detect |
Объекта, когда |
|
/ / |
связанный с ним сенсор движения транспорта фиксирует |
||
/ / |
проходящую машину . |
|
|
private native void monitorSensor () |
; |
||
/ / |
Этот метод вызывается методом monitorSensor , |
||
/ / |
чтобы сообшить о прохождении транспортного средства |
||
/ / |
наблюдателю этого объекта . |
|
![](/html/2706/346/html_MxkKzTLKJz.Ja4Q/htmlconvd-LkZgZ6442x1.jpg)
![](/html/2706/346/html_MxkKzTLKJz.Ja4Q/htmlconvd-LkZgZ6443x1.jpg)
Single Threaded Execution 8 451
public void run () while (true) {
try (
mуТhrеаd . slеер (БО*lООО) ;
transmit (controller . getAndClearCount (» ; catch (InterruptedException е) (
// t ry
// while
// run ( )
// Передает значение счетчика количества машин . private native void transmit (int count) ;
//class Tra fficTransmi tter
инаконец, приведем класс TrafficSensorController. Экземпляры класса
TrafficSensorControl ler хранят текущее общее количество машин, про шедших мимо сенсоров движения транспорта, связанных с экземпляром. Заме тим, что его методы реализованы как синхронизированные.
public class TrafficSensorController
implements TrafficSensor . TrafficObserver
private int vehicleCount = О ;
/ * *
* Этот метод вызывается в том случае , когда сенсор движения
*транспорта фиксирует прохождение машины . Он увеличивает
*значение счетчика машин на единицу .
* /
public synchronized void vehiclePassed () vehicleCount++ ;
}/ / vehiclePassed ( )
/ * * * Сбрасывает счетчик машин в нуль .
* @ return Возвращает последнее значение счетчика .
* /
public synchronized int getAndClearCount () int count = vehicleCount;
vehicleCount - О ; return count;
/ / getAndClearCount ( )
/ / c l a s s TrafficSensorController
СИНОПСИС
Должна выполняться операция, требующая однопоточного доступа к много численным объектам. Чтобы сэкономить время и упростить задачу, при помо ши шаблона Lock Object создается дополнительный объект блокировки, кото рый заменяет все объекты, непосредственно участвующие в операции. Объект,
который предназначен только для того, чтобы быть заблокированным, называ ется объектом блокировки.
КОНТЕКСТ
Предположим, создается программадля игры, которая будет происходить в реаль ном времени и в которой будет участвовать множество игроков. Каждый игрок сможет инициировать операции, которые влияют на состояние мноroчислен
ных игровых объектов. Чтобы гарантировать надлежащее изменение состояния каждого объекта, при разработке необходимо применить шаблон Siпglе Threaded
Ехесutiоп.
ТОВЧтобы игра правильно функционировала, изменения некоторых игровых объек
должны происходить одновременно и не влиять на действия другоro игрока. Для этого нужно гарантировать следующее: поток, отвечающий за изменение состояния объектов, должен иметь монопольный доступ к этим объектам.
С этой целью можно потребовать от потоков блокировать каждый объект перед
тем, как они пытаются изменить его состояние. Рещение такого рода связано с рядом сложностей.
1. Блокирование многочисленных объектов требует дополнительных ресурсов компьютера, но это наименьшая из проблем.
2.Необходимо быть уверенным, что при попытке блокировать несколько объ ектов потоки не окажутся взаимно блокированными. Не должна возник нугь ситуация, при которой один поток блокирует объект, который уже за блокирован другим потоком, и этот объект не будет освобожден до тех пор, пока второй поток не сможет получить доступ к друroму объекту, заблоки рованному первым потоком.
Подобных взаимных блокировок можно избежать, если использовать щаб лон Static Lосkiпg Order, описанный в книге [Grand2001). В таком случае за ставляют потоки сначала сортировать объекты в соответствии с тем значе нием, которое возвращает для них и затем блокируют их в этом порядке.
![](/html/2706/346/html_MxkKzTLKJz.Ja4Q/htmlconvd-LkZgZ6446x1.jpg)
454 • Глава 9. Шаблоны проектирования ,[!,Ля конкурирующих операций
Очевидно, что попытка избежать взаимной блокировки усложняет Про грамму и требует дополнительных затрат.
3.Блокирование коллекции объектов требует больших трудозатрат при коди ровании на языке Java. Чтобы заблокировать произвольное количество объ
ектов, необходимо выполнять манипуляции внутри конструктора s ynchro nized рекурсивного метода. Рассмотрим пример:
public class ObjectLocker (
/* *
* Этот метод блокирует все объекты данного массива
* |
и передает массив |
объекту Obj ectMan ipu l at ionI F . |
* |
|
|
* |
@param obj s |
|
* |
Массив объектов , на который воздействует |
|
* |
данньrn объект |
Obj ectMan ipulation I F . |
*@param ор
*Объект Obj ectManipulation I F .
*/
public void doIt (Object [] |
objs , ObjectмanipulationIF ор) ( |
|||
doItнelper (obj s , |
ор , obj s . lenqth-l) ; |
|||
} / / |
do I t ( Obj ect [ ] , |
Obj ectManipulationIF) |
||
private void doItRelper (Object [] objs , |
||||
|
|
|
ObjectмanipulationIF ор , |
|
|
|
|
int ndx) |
|
synchronized |
(objs [ndx] ) { |
|||
|
if (ndx=O) |
( |
|
|
|
op . doObject (obj s) ; |
|||
|
else ( |
|
|
|
|
doItнelper (objs, |
ор , ndx-l) ; |
||
|
/ / i f |
|
|
|
|
/ / synchron ized |
|
|
|
// |
doI tHelpe r (Object [ ] , |
Obj ectMan ipu lationIF, i n t ) |
// c l a s s Obj ectLocker
Очевидно, длячто желательно найти альтернативное решение этой проблемы:
обеспечить потока монопольный доступ к многочисленным игровым объ
ектам. При этом решение не должно быть таким сложным и требующим боль ших затрат, как решение, предусматривающее блокировку многочисленнЫХ
объектов.
Проблему можно УПРОСТИТЬ, если заставить только один поток в какой-то мо
мент времени получать доступ к любым объектам игры. Это ограничение может
![](/html/2706/346/html_MxkKzTLKJz.Ja4Q/htmlconvd-LkZgZ6447x1.jpg)
![](/html/2706/346/html_MxkKzTLKJz.Ja4Q/htmlconvd-LkZgZ6448x1.jpg)
456 • Глава 9. Шаблоны проектирования дпя конкурирующих операций
киласса вызывают метод getLockObj ect с целью получения объекта блокиров_
для синхронизированных операций. Такой способ управления объектом
блокировки хорошо работает в тех случаях, когда нужно, чтобы все экземпляры
одного или нескольких классов совместно использовали один и тот же объект
блокировки.
Abstract5uperclass 9CtLQ!;kQbiect() ;Q12iC!;t
I |
I |
|
ConcreteClassl I |
I |
I ConcreteClassl |
l |
. . |
||
|
Рис. 9.7. |
Объект блокировки |
|
Другие способы управления объектами блокировки рассматриваются в разделе
« Реализация» . Поскольку существует множество приемлемых способов управ ления доступом к объектам блокирqвки, они на самом деле не являются частью данного шаблона. Этот шаблон посвящен использованию объекта блокировки,
а не управлению доступом к нему.
РЕАЛИЗАЦИЯ
Существует множество различных способов управления доступом к объекту
блокировки. Основным доводом в пользу того или иного способа управления объектом блокировки является разнообразие тех объектов, которые будут ис
пользовать объект блокировки, а также ответ на вопрос, будет нужен один или
несколько объектов блокировки.
Пример управления объектом блокировки, представленный на рис. 9.7, преду
сматривает использование классов, которые получат доступ к объекту блоки
ровки через наследуемый ими статический метод. Такая схема хорошо работает
в тех случаях, когда нужно заблокировать все экземпляры класса или классов
для выполнения некоторой операции.
Если почти все объекты, блокируемые для выполнения операции, не являются
экземплярами одного и того же класса, их, как правило, можно сгруппировать
по другому принципу. В таких случаях способ управления объектом блокиров
ки обычно определяется на основе схемы объектов, участвующих в операциЯХ,
для которых предназначен объект блокировки. В качестве примера рассмотриМ
структуру объектов, имеющую вид дерева (рис. 9.8).
Объекты, организованные в виде дерева, являются экземплярами разных клас
сов. Но все объекты имеют метод getLockObj ect, который возвращает объект
блокировки, используемый операциями, выполняемыми с участием этих объ ектов. Метод getLockObj ect реализован в этих объектах таким образом, что,
![](/html/2706/346/html_MxkKzTLKJz.Ja4Q/htmlconvd-LkZgZ6449x1.jpg)
![](/html/2706/346/html_MxkKzTLKJz.Ja4Q/htmlconvd-LkZgZ6450x1.jpg)