Главная страница

Java. Полное руководство. 8-е издание. С. Н. Тригуб Перевод с английского и редакция


Скачать 25.04 Mb.
НазваниеС. Н. Тригуб Перевод с английского и редакция
АнкорJava. Полное руководство. 8-е издание.pdf
Дата28.02.2017
Размер25.04 Mb.
Формат файлаpdf
Имя файлаJava. Полное руководство. 8-е издание.pdf
ТипДокументы
#3236
страница77 из 90
1   ...   73   74   75   76   77   78   79   80   ...   90
for(int x=l; x
int rs = 0;
int gs = 0;
int bs = 0;
for(int k=-l; k<
=
1; k++) {
for(int j=-l; j<=l; j+
+ )
{
int rgb = imgpixels[(y+k)*width+x+j];
int r = (rgb > > 1 6 )
Sc
Oxff;
int g = (rgb > > 8 ) & Oxff;
int b = rgb
Sc
Oxff;
rs += r;
gs += g;
bs += b;
}
}
rs /= 9;
gs /= 9;
bs /= 9;
newimgpixels[y*width+x] = (OxffOOOOOO I
rs << 16 I
gs << 8 I
На рис. 26.10 показан аплет после работы фильтра Класс S h a r p e Фильтр класса
Sharpen тоже является подклассом класса
Convolver ив той или иной степени прямой противоположностью классу
Blur. Он работает с каждым пикселем в массиве исходного изображения imgpixels и вычисляет среднее по окружающей его области размером Sx3. Соответствующий выходной пиксель в массиве newimgpixels отличается от центрального пикселя и окружающего среднего, добавленного в него. По сути, это свидетельствует о том, что если пик­
сель ярче на 30, чем его окружающие пиксели, то остальные пиксели станут ярче на 30. Если же он темнее на 10, то остальные станут темнее на 10. В результате края будут акцентированы, а внутренние участки останутся неизмененными.

8 6 Часть II. Библиотека Java
Filtered: Рис. 26.10. Использование фильтра класса
В1игв в аплете

ImageFilterDemo
public class Sharpen extends Convolver {
private final int clamp(int c) {
return ( c > 2 5 5 ? 2 55 :
(c < 0 ? 0 :
c ) );
}
public void convolve() {
int r0=0,
g0
=
0 ,
b0
=
0 ;
for(int y=l; y
for(int x=l; x
int rs = 0;
m t gs = 0;
int bs = 0;
for(int k=-l; k<=l; k++) {
for(int j=-l; j<=l; j++)
{
m t rgb = imgpixels[(y+k)*width+x+j];
int
r =
(rgb > > 1 6 )
&
Oxff;
int
g =
(rgb > > 8 )
& Oxff;
int
b =
rgb
Sc
Oxff;
if
(j == 0
ScSc
k == 0)
{
rO = r;
Глава 26. Изображения
8 6 5
gO = g;
ЬО = b;
} else {
rs += r;
gs += g;
bs += b;
}
}
}
rs >>= 3;
gs >>= 3;
bs >>= 3;
newimgpixels[y*width+x] = (OxffOOOOOO I
clamp(rO+rO-rs)
<< 16 I
clamp(gO+gO-gs)
<< 8 На рис. 26.11 показан аплет после работы фильтра класса S h a rp e n .
Filtered: Sharpen
Reset | Grayscale | Invert
j
Contrast
j
Blur | Sharpen Рис. 26.11. Использование фильтра класса
Sharpen в аплете
ImageFilterDemo
28 3ak 3030

8 6 6 Часть II. Библиотека Аппликационная анимация
Теперь, когда вы уже знаете об особенностях интерфейсов API для работы с изображениями, можем построить интересный аплет, который будет отображать последовательность анимационных ячеек. Анимационные ячейки берутся из одного изображения, которое может компоновать ячейки в сетке, определяемой параметрами row s и c o l s дескриптора <рагаш>. Каждая ячейка в изображении разделяется подобно тому, как это было использовано ранее в примере аплета
T ile lm a g e . Мы получаем последовательность, в которой будут отображаться ячейки, из параметра s e q u e n c e дескриптора <рагаш>. Она представляет собой список номеров ячеек, разделенных запятыми, которые начинаются с нуля и следуют далее по сетке слева направо и сверху вниз.
После того как аплет проанализирует дескрипторы <рагаш> и загрузит исходное изображение, он расчленит изображение на несколько небольших второстепенных изображений. Затем запускается поток, благодаря которому изображения будут отображаться в порядке, описанном в параметре s e q u e n c e . Поток бездействует достаточно времени, чтобы поддерживать частоту кадров f r a m e r a t e . Ниже показан исходный код Пример анимации
import java.applet.*;
import java.awt.*;
import j a v a .a w t .image.*;
import java.util.*;
public class Animation extends Applet implements Runnable {
Image c e l l [];
final int MAXSEQ = 64;
int sequence[];
int nseq;
int idx;
int framerate;
volatile boolean stopFlag;
private int intDef(String s, int def) {
int n = def;
if (s != null)
try {
n = Integer.parselnt(s);
} catch (NumberFormatException e) {
System.out.println("Number Format Exception");
}
return n;
}
public void init() {
framerate = intDef(getParameter("framerate"), 5);
int tilex = intDef(getParameter("cols"), 1);
int tiley = intDef(getParameter("rows"), 1);
cell = new Image[tilex*tiley];
StringTokenizer st =
new StringTokenizer(getParameter("sequence"), ",");
sequence = new int[MAXSEQ]
nseq = 0;
while(st.hasMoreTokens() && nseq < MAXSEQ) {
sequence[nseq] = intDef(s t .nextToken(), 0);
nseq++;
}
Глава 26. Изображения
8 6 7
try {
Image img = getlmage(getDocumentBase(),
getParameter("img"));
MediaTracker t = new MediaTracker(this);
t .addlmage(i m g ,
0);
t .waitForlD(0);
int iw = i m g .getWidth(null);
int ih = im g .getHeight(null);
int tw = iw / tilex;
int th = ih / tiley;
CropImageFilter f;
FilteredlmageSource fis;
for (int y=0; y
for (int x = 0 ; x
f = new CropImageFilter(tw*x, th*y, tw, th) ;
fis = new FilteredlmageSource(img.getSource(),
f) ;
int i = y*tilex+x;
cell[i] = createlmage(fis);
t .addlmage(cell[i] ,
i) ;
}
}
t .waitForAll();
} catch (InterruptedException e) {
System.out.println("Image Load Interrupted");
}
}
public void update(Graphics g) { }
public void paint(Graphics g) {
g .drawlmage(cell[sequence[idx]], 0, 0, null);
}
Thread t;
public void sta r t () {
t = new Thread(this);
stopFlag = false;
t .start();
}
public void s t o p O {
stopFlag = true;
}
public void run() {
idx = 0;
while (true) {
paint(getGraphics());
idx = (idx + 1 ) % nseq;
try {
Thread.sleep(1000/framerate);
} catch (InterruptedException e) {
System.out.println("Animation Interrupted");
return;
}
if(stopFlag)
return;
}
}

8 6 Часть II. Библиотека Следующий дескриптор аплета иллюстрирует известное учение Эдварда
Майбриджа (Eadweard Muybridge) о движении, которое гласит, что в действительности лошади касаются земли всеми четырьмя копытами. (Естественно, в вашем аплете вы можете использовать другой файл с изображением code=animation width=67 На рис. 26.12 показано выполнение аплета. Обратите внимание на то, что вис ходном изображении, загруженном после аплета, используется обычный дескриптор Дополнительные классы обработки
изображений
Кроме классов обработки изображений, описанных в этой главе, пакет j ava.
awt.
image содержит несколько других классов, которые предлагают расширенные возможности управления процессом визуализации изображений и поддерживают усовершенствованные технологии визуализации. Имеется также пакет визуализации изображений j avax.
image io, поддерживающий дополнения, с помощью которых можно реализовать обработку различных форматов изображений. Если вас интересуют возможности усовершенствованного графического вывода, придется изучить дополнительные классы, которые можно найти в пакетах j avax.awt.image и j avax.imageio.

ГЛАВА
Параллельные
утилиты
В языке Java с самого начала была предусмотрена встроенная поддержка много­
поточности и синхронизации. Например, новые потоки можно создавать за счет реализации интерфейса R u n n a b le или расширения класса T h re a d , синхронизация доступна при использовании ключевого слова s y n c h r o n i z e d , а межпото- ковые коммуникации поддерживаются методами w a i t () и n o t i f y (), которые определены в классе O b j e c t . Вообще говоря, эта встроенная поддержка много­
поточности была одним из наиболее важных новшеств в Java и остается одной из главных ее сильных сторон.
Однако какой бы концептуально чистой ни была поддержка многопоточно­
сти вона не является идеальной для всех приложений, особенно для тех, в которых широко используется множество потоков. Например, первоначальная поддержка многопоточности лишена некоторых высокоуровневых функциональных возможностей (например, семафоров, пулов потоков и диспетчеров, которые способствуют созданию программ, работающих в параллельном режиме.
Необходимо понять с самого начала, что многопоточность используется во многих программах Java, которые в результате становятся параллельными
(concurrent). Например, многопоточность используется во многих аплетах и серв­
летах. Однако что касается настоящей главы, то термин параллельная программа относится к программе, которая в полной мере использует параллельно выполняющиеся потоки, являющиеся ее неотъемлемой частью Примером является программа, где отдельные потоки служат для одновременного вычисления частичных результатов, используемых в более крупных расчетах. Другим примером является программа, координирующая активность нескольких потоков, каждый из которых пытается обратиться к информации в базе данных. В этом случае доступ в режиме только для чтения может обрабатываться отдельно от доступа, при котором необходимо обеспечить чтение и запись.
Вначале для поддержки параллельных программ в комплекте JDK 5 были добавлены параллельные утилиты которые также часто упоминаются как параллельный
API. Исходный набор параллельных утилит предоставлял множество возможностей, о которых уже давно мечтали программисты, занимающиеся разработкой параллельных приложений. Например, они предлагают такие средства синхронизации, как семафоры, циклические барьеры, защелки с обратным отсчетом, пулы потоков, диспетчеры выполнения, блокировки, множество параллельных коллекций, а также элегантный способ использования потоков для получения результатов вычислений.
Хотя первоначально параллельные API были внушительны сами по себе, они были существенно расширены в комплекте JDK 7. Самое важное добавление — это инфраструктура Fork/Join Framework, которая облегчает создание программ, использующих несколько процессоров (таких, как в многоядерных системах. Таким

8 7 Часть II. Библиотека образом, она упрощает разработку программ, в которых две или больше частей на самом деле выполняются одновременно (те. имеет место истинное параллельное выполнение, а не за счет квантования времени. Как вы легко можете представить себе, параллельное выполнение может существенно увеличить скорость определенных операций. Поскольку многоядерные системы распространены уже широко, включение инфраструктуры F o rk /Jo in Framework столь же своевременно, сколь и мощно.
Первоначальные параллельные API были весьма обширны, а инфраструктура
F o rk /Jo in Framework еще увеличивает их размер. Как и следовало ожидать, большинство проблем, связанных с использованием параллельности, весьма сложны. Обсуждение всех их аспектов выходит за рамки этой книги. Несмотря на это, всем программистам имеет смысл иметь общее представление и практические знания о параллельных API. Даже в тех программах, которые не используют параллельность интенсивно, такие средства, как синхронизаторы, вызываемые потоки и исполнители, применимы к различным ситуациям. Возможно, важнее всего то, что в связи с распространением многоядерных компьютеров решения, задействую­
щие инфраструктуру F o rk /Jo in Framework, также станут весьма распространены. Поэтому данная глава представляет краткий обзор утилит параллельности и демонстрирует несколько примеров их использования. Она завершается углубленным исследованием инфраструктуры F o rk /Jo in Пакеты параллельного Параллельные утилиты содержатся в пакете j a v a . u t i l . c o n c u r r e n t и двух его вложенных пакетах, j a v a . u t i l . c o n c u r r e n t . a t o m i c и j a v a . u t i l . c o n ­
c u r r e n t . l o c k s . Далее следует краткий обзор их содержимого.
Пакет
j a v a . u t i l . c o n c u r r e n Пакет j a v a . u t i l . c o n c u r r e n t определяет основные функциональные возможности, которые поддерживают альтернативные варианты встроенных методов синхронизации и межпотоковых коммуникаций. Он определяет следующие ключевые элементы:
• синхронизаторы;
• исполнители;
• параллельные коллекции;
• инфраструктуру F o rk /Jo in Синхронизаторы предлагают высокоуровневые способы синхронизации взаимодействий между несколькими потоками. В пакете j a v a . u t i l . c o n c u r r e n t определен набор классов синхронизаторов, описанных в табл. Обратите внимание на то, что каждый синхронизатор предлагает решение задачи синхронизации определенного рода. Благодаря этому можно оптимизировать работу каждого синхронизатора. Раньше эти типы объектов синхронизации необходимо было создавать вручную. Параллельный API стандартизирует их и делает доступными для всех программистов, работающих с Java.
Глава 27. Параллельные утилиты
8 7 Таблица
2 7 . 1 . Классы синхронизаторовр определенные в пакете
j a v a . u t i l • c o n c u r r e n А £ м к 1
Vt,
" V I '

Описание л' / f
' Реализует классический семафор
CountDownLatch
Ожидание длится до тех пор, пока не произойдет определенное количество событий
CyclicBarrier
Позволяет группе потоков войти в режим ожидания в предварительно заданной точке выполнения
Exchanger
Осуществляет обмен данными между двумя потоками
Phaser
Синхронизирует потоки, проходящие через несколько фаз операций. (Добавлено в JDK Исполнители (executor) управляют выполнением потоков. Первым в иерархии исполнителей является интерфейс
Executor, который служит для запуска потока. Интерфейс расширяет интерфейс
Executor и предлагает методы, управляющие исполнением. Существует три реализации интерфейса
ExecutorService: классы
ThreadPoolExecutor, Scheduled-
ThreadPoolExecutor и класс
ForkJoinPool, добавленный bJDK 7. Пакет j ava.
util.
concurrent также определяет служебный класс
Executors, который содержит несколько статических методов, упрощающих создание разнообразных исполнителей.
С исполнителями связаны интерфейсы
Future и
Callable. Интерфейс
Future содержит значение, возвращаемое потоком после его выполнения. Таким образом, его значение определяется в будущем, когда поток завершит свое выполнение. Интерфейс
Callable определяет поток, возвращающий значение.
Пакет java.util.
concurrent определяет несколько классов параллельных коллекций, включая
ConcurrentHashMap, ConcurrentLinkedQueue и Сору-
OnWriteArrayList. Они предлагают параллельные альтернативные варианты для связанных сними классов, определенных в инфраструктуре Collections Инфраструктура F o rk /Jo in Framework поддерживает параллельное программирование. Ее основные классы —
ForkJoinTask, ForkJoinPool, RecursiveTask и
RecursiveAction. Как упоминалось, инфраструктура F o rk /Jo in Framework была добавлена комплектом JDK Наконец, для улучшенной обработки синхронизации потоков пакет java. util.
concurrent определяет перечисление Пакет t o m i Этот пакет упрощает использование переменных в параллельной среде. Он предлагает средства эффективного обновления значений переменной без применения блокировок. Для этого используются такие классы, как
Atomic
Integer и
AtomicLong, а также методы вроде compareAndSet
( )
,
decrementAndGet
() и getAndSet ()
. Эти методы работают в режиме одной непрерывной операции.
П акет
j a v a . u t i l . c o n c u r r e n t . l o c k Пакет j ava.
util.
concurrent.
locks предлагает альтернативный вариант работы с синхронизированными методами. В его основе лежит интерфейс
Lock,

8 7 Часть II. Библиотека определяющий основной механизм, который используется для получения доступа к объекту и отказав доступе. Ключевыми методами являются lock (), try
Lock () и unlock ()
. Преимущество этих методов состоит в том, что они расширяют возможности управления синхронизацией.
Далее в главе займемся подробным рассмотрением компонентов параллельного Использование объектов синхронизации

Объекты синхронизации представлены классами
Semaphore, CountDownLatch,
CyclicBarrier, Exchanger и
Phaser. Вместе они позволяют без особых сложностей решать некоторые задачи синхронизации, справиться с которыми ранее было довольно непросто. Их также можно применять к широкому диапазону программ — даже к тем, которые поддерживают только ограниченный параллелизм. Поскольку объекты синхронизации могут встречаться практически во всех программах Java, остановимся на них более подробно.
Класс
S e m a p h o r Первым объектом синхронизации, который могут сразу же вспомнить большинство читателей, является класс
Semaphore, реализующий классический семафор. Семафор управляет доступом к общему ресурсу с помощью счетчика. Если счетчик больше нуля, доступ разрешается. Если он равен нулю, в доступе будет отказано. В действительности этот счетчик подсчитывает разрешения, открывающие доступ к общему ресурсу. Следовательно, чтобы получить доступ к ресурсу, поток должен получить разрешение на доступу семафора.
В общем случае, чтобы использовать семафор, поток, которому требуется доступ к общему ресурсу, пытается получить разрешение. Если значение счетчика семафора будет больше нуля, поток получит разрешение, после чего значение счетчика семафора уменьшается на единицу. В противном случае поток будет заблокирован до тех пор, пока не сможет получить разрешение. Если доступ к общему ресурсу потоку больше ненужен, он освобождает разрешение, в результате чего значение счетчика семафора увеличивается на единицу. Если в это время другой поток ожидает разрешения, то он сразу же его получает. Описанный механизм реализуется в Java классом Класс
Semaphore имеет два конструктора, показанных далее число число boolean

как)
Здесь параметр число указывает исходное значение счетчика разрешений. Таким образом, число определяет количество потоков, которым может быть предоставлен доступ к общему ресурсу одновременно. Если параметр число содержит значение 1, только один поток сможет обратиться к ресурсу. По умолчанию ожидающим потокам предоставляется разрешение в неопределенном порядке. Если параметру как присвоить значение true, то вы тем самым определите, что ожидающим потокам будут выдаваться разрешения в том порядке, в каком они запрашивали доступ.
Чтобы получить разрешение, вызовите метод acquire ()
, который имеет следующие две формы acquire() throws InterruptedException

1   ...   73   74   75   76   77   78   79   80   ...   90


написать администратору сайта