![](/user_photo/2706_HbeT2.jpg)
GrandM-Patterns_in_Java
.pdf![](/html/2706/346/html_MxkKzTLKJz.Ja4Q/htmlconvd-LkZgZ6511x1.jpg)
DoubIe Buffering • 519
/ * *
*Это общая логика для предваритель ного
*заполнения резервных буферов .
*/
public synchronized void run ( ) try (
while ( ! myThread . isInterrupted ( ) " ! exhausted) (
synchronized (this) (
while ( ! outstandingFillRequest) wait () ;
)/ / whi l e
}/ / synchronized
fill () ;
outstandingFillRequest = false ;
/ / while
catch (InterruptedException е) {
/ / Ничего не делает . Это нормально .
catch (ThreadDeath е)
throw е ;
catch (Throwable е ) (
exception = е ;
finally {
exhausted = true ;
/ / |
Оповещает любой поток, |
// |
ожидающий окончания заполнения . |
synchronized (lockObject) (
lockObject . notifyAll ( ) ;
} / / synchronized
try (
in . close () ;
catch (IOException е)
if (exception==null)
exception = е ;
} / / i f / / try
in = null ;
// try
// run ( )
![](/html/2706/346/html_MxkKzTLKJz.Ja4Q/htmlconvd-LkZgZ6512x1.jpg)
520 • Глава 9. Шаблоны проектирования для конкурирующих операций
/* *
* Запрашивает асинхронное заполнение всех резервных буферов . * Если операция асинхронного заполнения уже приведена
* в действие , то вызов этого метода не принесет
*никакого эффе кта .
*/
synchronized void fillReserve ( ) { outstandingFillRequest = true i notify ( ) i
} / / f i l l Reserve
/ * *
*Завершает асинхронное заполнение буфера .
*/
void close ( )
myThread . interrupt ( ) i
}/ / close ( )
} / / class BufferFiller
/ / class DoubleBufferedl nputStream
Что касается класса DoubleBu fferedInputStream, то, поскольку его экземп ляры имеют связанные с ними потоки, они никогда не будут удалены при сборке мусорадо тех пор, пока не будут закрыты. Поток закрывается методом c lose.
ШАБЛОНЫ ПРОЕКТИРОВАНИЯ, СВЯЗАННЫЕ
С ШАБЛОНОМ DOUBLE BUFFERING
Producer-Consumer. Шаблон DоиЫе Butтering представляет собой спеuиальную
форму шаблона Producer-Consumer.
Guarded Suspension. Шаблон Guarded Suspension используется при реализаuии
шаблона DоиЫе Butтering для координации действий потоков, запрашивающих
данные, с потоком, выполняющим опережающее чтение.
Two-Phase Termination. Шаблон Two-Phase Terminationдля может быть использо
ван при реализации шаблона DоиЫе Buffering надлежащего завершения по
тока, выполняющего опережающее чтение.
СИНОПСИС
Объект получает запросы на выполнение каких-либодействий. Шаблон Asynchro nous Processing не позволяет асинхронно обрабатывать процессы. Вместо этого они ставятся в очередь и затем обрабатываются асинхронно.
КОНТЕКСТ
Поскольку запросы на выполнение действий над объектами бывают разными, описание этого шаблона включает два разных сценария, которые позволяют охватить всю широту проблемы, решаемой с помошью этого шаблона: сцена рий для сервера и сценарий для клиента. Сначала рассмотрим сценарий, пред назначенный для сервера.
Предположим, что проектируется сервер, который будет создавать стандартные письма от имени приложений. Ожидается, что приложения будут передавать объект серверу, который содержит информацию, необходимую для создания стандартного письма. Если сервер определяет, что объект содержит правиль ные данные, он возврашает идентификационный номер в приложение. Позже идентификационный номер может быть использован приложением для полу чения созданного письма и его отправки.
Самый простой способ работы такой программы предполагает синхронное соз дание стандартного письма. Это означало бы, что сервер имеет поток, полу чаюший запрос, создает стандартное письмо, возврашает ID этого письма в то приложение, которое выдало запрос, а затем ожидает следуюшего запроса. Такие взаимодействия представлены на рис. 9.32. Однако в этом проекте сушествуют некоторые проблемы, которые вынуждают искать альтернативный вариант ре шения.
|
|
|
-+ |
|
|
|
|
|
1.1: ;d:-сrеаtеIDО |
|
|
|
-+ |
1.2: generateFormLetter(;d, content) |
|
|
|
1: |
|
.------ |
'------ |
'---, |
|
;d:..generateFormLetter(content) |
|
|
|
Рис. 9.32. Синхронная версия создания письма
Первая проблема связана с производительностью. С точки зрения клиентов,
самый простой способ работы с сервером писем заключается в том, чтобы
![](/html/2706/346/html_MxkKzTLKJz.Ja4Q/htmlconvd-LkZgZ6515x1.jpg)
![](/html/2706/346/html_MxkKzTLKJz.Ja4Q/htmlconvd-LkZgZ6517x1.jpg)
Asynchronous Processing - 52!
модальное диалоговое окно. Когда диалоговое окно прекращает свою раБО1)
команда, инициировавшая диалог, продолжает выполнение и завершается.
Но это исключение кажущееся. Swing реализует модальные диалоги таким об разом, что во время работы модальных диалогов для обработки событий поль зовательского интерфейса запускается новый поток.
МОТИВЫ
©Предполагается, что объект должен отвечать на запросы с целью их обра ботки.
©Клиенты объекта, возможно, не должны ждать, пока он ответит на запрос. @) Запросы поступают асинхронно по отношению друг к другу. н
©Объект может получать запрос в то время, когда он все еще занят ответом
предыдущий запрос.
©Может не быть фактического оrpаничения на количество запросов, посту паюших примерно в одно и то же время.
®Объект должен отвечать на запрос в течение определенного промежутк,
времени, начиная с момента, когда он получил запрос.
РЕШЕНИЕ
Проектируем объекты таким образом, чтобы обработка запросов происходил: асинхронно по отношению к их получению. Общая схема такого решеНИJ представлена на рис. 9.35.
1.1:
---+
1А: request(info)
Рис. 9.35. Асинхронная обработка
с концептуальной точки зрения этот шаблон является самым простым сред! всех шаблонов, описанных в этой книге. Однако, подобно многим другим кон цептуально простым идеям, он включает многочисленные реализационные де тали, которые должны быть тщательно разработаны.
526 • Глава 9. Шаблоны проектирования для конкурирующих операций
РЕАЛИЗАЦИЯ
При проектировании и реализации шаблона Asynchronous Processing следует учитывать два основных вопроса. Первый вопрос, как будут управляться запро
сы и как будут распределены обрабатывающие их потоки. Второй вопрос воз
никает тогда, когда другие объекты должны знать о том, что запрос был обрабо тан, или о том, каков результат обработки запроса.
У п р а вл е н и е з а п р о с а м и и ра с п р едел е н и е п ото ко в
Существует множество способов, позволяюших управлять запросами и распре
делять потоки, которые их обрабатывают. Под управлением запросов здесь по
нимается определение того, когда запрос не может быть обработан. Возможны |
|
следуюшие варианты: |
|
• |
запрос немедленно может быть направлен на обработку; |
• |
обработка запроса откладывается на некоторое определенное время; |
• |
обработка откладывается до тех пор, пока не будет выполнено некоторое |
• |
условие; |
запрос отклоняется и поэтому никогда не будет обработан. |
Под распределением потока для обработки запроса здесьпонимается определение
того, когда запрос может быть обработан, что предусматривает выделение потока для обработки процесса и можеттакже включать задание приоритета этого потока.
Самый простой способ согласования запросов с потоками состоит в том, чтобы запускать новый поток каждый раз, когда должен быть обработан запрос. Ос новное преимущество такого подхода - его простота. Недостатком является то,
что этот способ обеспечивает минимальный контроль над управлением запро
сами и выделением потоков. Такой подход позволяет отбрасывать запрос, но не
способен отложить его обработку. Он не обеспечивает никакой реальной поли
тики распределения потоков или ограничения количества потоков. Возникнет
проблема, если существует такая возможность, когда многочисленные извеше
ния о событиях поступят примерно в одно и то же время. Если слишком боль
шое количество событий обрабатывается одновременно, то общее количество
потоков может привести к замедлению обработки запросов или прервать ее
ввиду недостатка ресурсов.
Простая политика распределения потоков заключается в том, чтобы иметь
постоянное количество потоков, пригодных для обработки событий, и про
извольным образом назначать события потокам, по мере того как один из них становится доступным. Это, по сути, является применением шаблона Produ cer-Consumer. Поток, ответственный за получение запросов и помещение их
в очередь, является производителем, а потоки, обрабатывающие запросы, явля
ются потребителями.
Более сложная политика распределения потоков может быть реализована с по мощью шаблона Thread Pool (описанного в книге [Grand2001). Передача за-
![](/html/2706/346/html_MxkKzTLKJz.Ja4Q/htmlconvd-LkZgZ6519x1.jpg)
528 • Глава 9. Шаблоны проектирования дпя конкурирующих операций
У п р а вл е н и е р е зул ьтатом
В некоторых случаях после окончания обработки запроса другой объект может
обнаружить, что обработка запроса завершена. Чаще всего объект, КОТОРыйЭТО,
как полагают, должен быть осведомлен об окончании обработки запроса, -
тот объект, который выдал запрос. Существуют два самых распространенных
способа, позволяющих другим объектам узнать о том, что обработка некоторо
го запроса завершена.
1 . Объект, отвечающий за окончание обработки запроса, может отправлять
событие тем объектам, которые были зарегистрированы как получатели таких событий.
2.Результат обработки события может быть сохранен в таком месте, в которое заинтересованные объекты могут отправлять запросы с целью обнаружения запросов и их результатов.
Если считается, что объект, который выдал запрос, узнал о результате обработ
ки запроса, он может использовать шаблон Future для согласования результата обработки запроса с любыми другими действиями, в которых он принимает участие.
СЛЕДСТВИЯ
©Объект, являющийся источником запроса, не должен ждать окончания об работки этого запроса, поэтому он может выполнять другие действия, на пример, отправлять следующие события.
©Запрос может быть поставлен в очередь при отсутствии выделенного для него потока. Это большая экономия ресурсов, поскольку каждый поток ис пользует значительный объем памяти, даже если он ничего не делает.
©Шаблон Asynchronous Processing позволяет проводить явную политику опре
деления того, когда запрос будет обработан или будетли он обработан вообше.
®Шаблон Asynchronous Processing не позволяет с уверенностью гарантиро
вать, что запрос будет обработан в течение некоторого определенного вре
мени.
ПРИМЕНЕНИЕ В JAVA API
Полыовательские интерфейсы, основанные на Swing и Аwr, используют шаб
лон Asynchronous Processing. Они управляют событиями клавиатуры и мыши,
применяя шаблон Producer-Consumer, и осуществляют их последовательное
управление, используя единственный поток.
Процесс работает следуюшим образом. Когда пользователь делает что-нибудь
с клавиатурой или мышью, платформно-зависимый механизм создает соответ ствующий объект, который описывает это событие. Затем он помещает событие