![](/user_photo/2706_HbeT2.jpg)
GrandM-Patterns_in_Java
.pdf![](/html/2706/346/html_MxkKzTLKJz.Ja4Q/htmlconvd-LkZgZ6521x1.jpg)
Asynchronous Processing - 529
в очередь. Объект очереди является экземпляром класса j ava . awt . EventQueue.
Объект EventQueue имеет связанный с ним поток, который достает объекты
событий из очереди и распределяет их так, чтобы они передавались соответст
вуюшим получателям.
Объект EventQueue, используемый для передачи сообшений клавиатуры или мыши любому из компонент Swing или AWГ, можно получить при помоши
следуюшего кода:
import java . awt . Component; java . awt . EventQueue
Component с ; EventQueue evtQueue ;
evtQueue = c . getToolkit ( ) . getSystemEventQueue ( ) ;
ПРИМЕР КОДА
Пример кода для этого шаблона представляет собой клиентскую программу, асинхронно обрабатываюшую некоторые события пользовательского интер фейса. Этот подкласс класса JFrame из библиотеки Swing создает элемент ин терфейса00, показанный на рис. 9.34. В его выпадаюшем меню File содержится пункт It. Кроме того, в нижней части фрейма находится индикатор выпол нения.
Когда пользователь шелкает на пункт меню 00 It, индикатор отображает ход выполнения процесса на протяжении примерно00четырех секунд. В то время, пока индикатор выполнения изменяется, пункт It в меню File меняется на пункт Stop Ooint It. Если пользователь шелкнет на пункт меню Stop Doing It, то индикатор выполнения перестанет изменяться.
Независимо от того, остановился ли индикатор выполнения из-за того, что он достиг 100 %, или из-за того, что пользователь шелкнул на пункт меню Stop
Doing It, но, когда индикатор перестает показывать изменения, пункт меню |
|||||||
Stop Ooing It заменяется пунктом меню |
00 |
It. |
|
||||
public class CancelFrame extends JFrame |
|
||||||
JМenuItem menuHelpAbout = |
new JМenuItem( ) ; |
|
|||||
JМenu menuHelp = |
new JМenu ( ) ; |
|
|
|
|||
JМenuItem menuFileDoIt = new JМenuItem() ; |
|
||||||
JМenuItem menuFileStopDoingIt = |
new JМenuItem ( ) ; |
||||||
JМenuItem menuFileEx1t = new JМenuItem () ; |
|
||||||
JМenu menuFile = |
new JМenu ( ) ; |
|
|
|
|||
JМenuBar menuBarl |
|
new JМenuBar ( ) ; |
|
||||
BorderLayout |
borderLayoutl |
= |
new BorderLayout () |
i |
|||
|
к |
|
|
|
![](/html/2706/346/html_MxkKzTLKJz.Ja4Q/htmlconvd-LkZgZ6522x1.jpg)
![](/html/2706/346/html_MxkKzTLKJz.Ja4Q/htmlconvd-LkZgZ6523x1.jpg)
![](/html/2706/346/html_MxkKzTLKJz.Ja4Q/htmlconvd-LkZgZ6524x1.jpg)
i3 • Глава 9. Шаблоны проектирования АЛЯ конкурирующих операций
private void installStopItмenuItem( ) { menuFile . remove (menuFileDoIt) ;
menuFile . insert (menuFileStopDoingIt , О) ; menuFile . repaint () ;
//i л st а l lStор ltМепu l tеm ( )
private void installDoItмenuItem ( ) menuFile . remove (menuFileStopDoingIt) ; menuFile . insert (menuFileDoIt, О) ; menuFile . repaint ( ) ;
/ / i л st а llDо l tМеЛ Ul tеm ( )
void fileStopDoingIt_ActionPerformed (ActionEvent е) if (doItТhread != null) {
doItThread. interrupt ( ) ;
} / / i f
// filеStорDОiлgl t_АсtiопРеrfоrmеd (Асt iолЕvелt )
void fileExit_ActionPerformed (ActionEvent е) System . exit (O) ;
} / / fil еЕХi t_Ас tiолРеrfоrmеd (АсtiолЕvеп t)
void helpAbout_ActionPerformed (ActionEvent е)
JPanel aboutPanel = new CancelFrame_AboutвoxPanell ( ) ; JOptionPane . showMessageDialog (this ,
aboutPanel , "About" ,
JOptionPane . PLAIN_МESSAGE) ;
}// hе lрАЬоut_АсtiолРеrfоrmеd;
/ / class Салсеl Frаmе
UАБЛОНЫ ПРОЕКТИРОВАНИЯ, СВЯЗАННЫЕ
: ШАБЛОНОМ ASYNCHRONOUS PROCESSING
'hread Pool. Шаблон Thread Рооl (описанный в книге [Grand2001]) может ис
ользоваться в реализации шаблона Asynchronous Processing.
'roducer-Consumer. Шаблон Producer-Consumer может использоваться в реали
щии шаблона Asynchronous Processing.
cheduler. Шаблон Scheduler может использоваться в реализации шаблона
.synchronous Processing.
'acade. Реализация класса обработки запроса может применять классы, которые вляются продуктами использования шаблонов Thread Pool, Producer-Consumer
Asynchronous Processing • 533
или Scheduler. Классы обработки запросов обычно выступают в роли фасада,
скрывающего эти детали от клиентских классов.
Future. Объект, который выдает запрос, может нуждаться в том, чтобы знать о результате запроса, асинхронно обработанном другимдля объектом. Объект, BblДa
ющий запрос, может использовать шаблон Future согласования результата обработки с любыми другими действиями, в которых участвует этот объект.
Active Object. Шаблон Active Object, рассмотренный в работе [SSRBOO], описы
ваетспособ объединения щаблона Future с щаблоном Asynchronous Processing.
Этот шаблон известен также под названием Prornise.
СИНОПСИС
Используется объект, который инкапсулирует результат вычислений и позво
ляет скрыть от клиентов, синхронно или асинхронно выполняется вычисление.
Этот объект будет содержать метод чтения результатов вычислений. Метод
ожидает получения результата, если вычисления производятся асинхронно, и
продолжает или выполняет вычисление, если оно является синхронным и еще не завершено.
КОНТЕКСТ
Предположим, что проектируется класс, который позволит программе полу
чать текущие данные о погоде для данной местности. Ожидается, что общей сферой применения такого класса является отображение информации о погоде среди некоторой другой информации. Например, такой класс может использо
ваться как часть сервлета, который генерирует код HTML дЛЯ Web-страницы,
показывающей информацию о погоде наряду с новостями.
Время, которое понадобится для получения информации о погоде, будет ме няться в значительной степени. Оно может составлять долю секунды или, воз
можно, несколько минут. Нужно спроектировать этот класс таким образом,
чтобы минимизировать влияние на клиентов этого класса.
Можно создать экземпляры класса погоды, которые будут отправлять события
заинтересованным объектам в том случае, когда этот класс получает затребо
ванную информацию о погоде. Однако такой подход нежелателен, потому что если клиенты класса погоды должны будут получать асинхронный вызов, изве
щающий о наступлении события, то клиенты класса сильно усложнятся. Класс
клиента вынужден будет реализовать метод по получению новой информации
о погоде таким образом, чтобы обеспечить безопасность потока выполнения.
Лучше использовать структуру, показанную на рис. 9.37. Опишем классы, представленные на рис. 9.37.
Weather. Экземпляры этого класса инкапсулируют информацию о текущих по
годных условиях определенной местности.
Client. Экземпляры класса, выступающего в этой роли, используют информа
цию, находящуюся в объектах Wea ther.
WeatherRequester. Когда объект C l i ent хочет получить объект Weather, со
держащий текущую информацию для данной местности, он просит объект
![](/html/2706/346/html_MxkKzTLKJz.Ja4Q/htmlconvd-LkZgZ6527x1.jpg)
![](/html/2706/346/html_MxkKzTLKJz.Ja4Q/htmlconvd-LkZgZ6528x1.jpg)
536 • Глава 9. Шаблоны проектирования дnя конкурирующих операций
Чтобы такой механизм работал надлежащим образом, может возникнуть необходимость в том, чтобы иметь однопоточный доступ к некоторым ме тодам или сегментам кода. В некоторых случаях это может привести к недо пустимым издержкам или чрезмерному усложнению класса.
©Нужно инкапсулировать вычисление таким образом, чтобы его клиенты
ничего не знали о том, является ли это вычисление асинхронным или син
хронным.
РЕШЕНИЕ
Вместо того чтобы заставить метод прямо возвращать результат вычисления,
вынуждаем его возвращать объект, который инкапсулирует это вычисление.
Этот объект будет содержать метод, вызываемый в том случае, когда нужно бу дет получить результат вычисления. Вызывающие этот метод не знают, выпол
няется ли вычисление синхронно или асинхронно по отношению к их потоку.
На рис. 9.38 показаны классы в этом решении. Опишем роли, выполняемые
классами в шаблоне Future.
|
|
|
|
|
Запрашивает вычисление . |
|
|
|
|
|
|
|||
|
|
|
|
|
|
|
Requester |
|
|
|||||
|
|
|
|
|
|
dolt(params):Future |
|
|
||||||
|
|
|
|
|
|
1 |
|
|
|
|
||||
|
|
|
|
|
|
|
|
|
|
|||||
|
|
|
|
|
|
|
|
. . . |
1 |
I |
|
|
|
|
|
|
|
|
|
|
|
|
|
I |
(о]дает.... |
||||
|
|
|
|
|
|
|
|
|
|
|
I |
|||
|
|
|
|
|
|
|
|
|
|
|
I |
|
|
|
|
|
|
|
|
|
|
|
|
|
* |
I |
|
|
|
|
|
* |
|
|
|
|
|
|
|
Future |
|
|
||
I |
Client |
I |
|
|
|
|
getResuLtO:ResuLt |
|
|
|||||
|
|
|
Знает, существуетли объект, инкапсулирующий ....1 |
|
|
|||||||||
|
1 |
|
|
|
|
|||||||||
|
|
|
|
|
|
ре]ультат вычисления |
|
|
|
|
0 |
|
|
|
|
|
|
|
|
Исполь]ует · |
|
|
* |
ResuLt. . 1 |
I |
|
|||
|
|
|
|
|
|
|
|
Рис. 9.38. Шаблон Future
Result. Экземпляры класса в этой роли инкапсулируют результат вычисления.
Client. Экземпляры классов в этой роли используют объекты Resul t. ОбъектЫ
Cl ient инициируют процесс получения объекта Resul t, передавая соответст
вующие параметры методу dol t объекта Requester.
Requester. Класс в этой роли имеет метод, вызываемый для инициирования вы
числения объекта Resul t. На рис 9.38 этот метод показан как метод dol t . Ме
тод dol t возвращает объект Future, который инкапсулирует это вычисление.
Future. Каждый экземпляр класса в этой роли инкапсулирует вычисление объ
екта Resul t. Это вычисление может быть синхронным или асинхронным. Если
![](/html/2706/346/html_MxkKzTLKJz.Ja4Q/htmlconvd-LkZgZ6529x1.jpg)
538 • Глава 9. Шаблоны лроектирования для конкурирующих олераций
Когда ему наконец потребуется результат вычисления, он вызывает метод getResult объекта Future. Если вычисление является асинхронным, макси мально раннее инициирование вычисления и максимально позднее чтение ре зультата позволяют в наибольшей степени воспользоваться преимуществами асинхронной обработки.
В некоторых ситуациях такая схема не действует. Например, когда у клиента есть активное задание, которое он постоянно выполняет. Рассмотрим пример сервлета, который генерирует Web-страницу, содержащую новости и информа цию о погоде. Предположим, что этот сервлет применяет связанные с погодой классы, рассмотренные в разделе «Контекст». После того как он запросил ин формацию о погоде, нельзя рассматривать ни один момент как самое послед нее возможное время получения информации о погоде. Сервлет непрерывно обновляет информацию, используемую им в качестве содержимого Web-cтpa ницы. Нужно, чтобы ни один запрос сервлета, предоставляющего содержимое Web-страницы, не был задержан, так как это приведет к задержке обновления информации о погоде.
Один из способов решения этой проблемы предусматривает применение от дельного потока для каждого запроса на получение информации о погоде. Но использование потока ДЛЯ этой цели не слишком выгодно и, скорее всего, при ведет к расходованию ресурсов.
Более удачное решение состоит в том, чтобы добавить еще один метод в класс Future. Как правило, имя этого метода начинается со слова «check» , например, checkComputation. Назначение метода check в том, чтобы проверять, будет ли объект Cl ient ждать результатов вычислений, если он вызовет метод getResul t объекта Future. Метод check может быть полезен в том случае, ко гда инкапсулированное вычисление является асинхронным. Метод check воз вратит false, если он вызывается до того, как закончилось вычисление, или true,
если он вызывается после завершения вычисления. Если вычисление синхрон
ное, метод check всегда возвращает true.
Использование метода check позволяет объектам C l ient опрашивать объекты
Future. Каждый запрос на получение содержимого может опрашивать объект
Future, вызывая его метод check. Если метод check возвращает true, сервлет обновляет информацию о погоде, которая используется Web-страницеЙ. Если
метод check возвращает false, то сервлет продолжает использовать ту информа .
цию, которая уже имеется.
З а ме с тител ь
Шаблон Future иногда используется вместе с шаблоном Ргоху. Обычно это де
лается так: класс, выступающий в роли Future, реализует интерфейс, который
может использоваться как заместитель дЛя класса, выполняющего вычисление.
При таком подходе объект, инициирующий вычислеот ние и создание оБЪeJ<K:tKта
Future, и объект, который получает результат объекта Future, - это, правило, разные объекты.