14-лекция. Безопастность потока. Синхронизация
ПЛАН:
Безопастность потока
Синхронизация
Блокировка на уровне объекта
При программировании многопоточных приложений с использованием библиотечных классов полезно организовать взаимосвязанные потоки в группы, что позволит управлять ими как единым целым и накладывать ограничения на способность потоков, принадлежащих группе, выполнять те или иные действия.
Потоки объединяются в группы потоков (thread groups) по соображениям улучшения управляемости и безопасности. Одна группа потоков может принадлежать другой группе, составляя иерархию с основной (системной) группой на верхнем уровне. Потоки, относящиеся к группе, могут управляться единовременно – вы вправе прервать работу сразу всех потоков группы либо установить для них единое максимальное значение приоритета выполнения. Группы потоков могут быть использованы также для определения доменов безопасности. Потоки внутри группы обычно наделены возможностями взаимного влияния, распространяемого и на потоки вложенных групп. Говоря о "влиянии", мы подразумеваем, что вызов любого метода способен воздействовать на характеристики Поведения потока, скажем, изменять его приоритет или осуществлять прерывание. В рамках конкретного приложения, однако, бывает необходимо определить политику безопасности, которая, в частности, должна препятствовать влиянию Потоков на потоки, не при надлежащие текущей группе. Потокам внутри отдельных групп могут быть даны различные права на выполнение тех или иных действий в рамках приложения, таких как операции ввода-вывода.
Вообще говоря, методы, затрагивающие функции безопасности, всегда загодя Проверяются соответствующим менеджером безопасности, установленным в системе. Если менеджер запрещает выполнение какого-либо действия, метод выбрасывает исключение типа SecurityException. По умолчанию при старте приложения менеджер безопасности не подключается. Если код выполняется в контексте другого приложения – как, например, аплет в Web-броузере, – вы не можете быть уверены, что некий менеджер безопасности, как правило, установлен и надежно функционирует. К числу действий, затрагивающих безопасность системы, относятся, в частности, операции по созданию потоков, управлению ими, осуществлению ввода-вывода и прерыванию работы приложений. За более подробными сведениями обращайтесь к разделу 18.5 на странице 509.
Каждый поток принадлежит определенной группе потоков. Каждая группа Потоков представляется объектом класса ThreadGroup, ограничивающим параметры Поведения "СВОИХ" потоков и предлагающим посреднические услуги при обращении R ним. Задать признак принадлежности потока группе можно при создании Потока, используя вызов соответствующего конструктора. По умолчанию каждый вновь созданный поток вводится в ту же группу, которой принадлежит поток- "родитель", если только в процесс не вмешается менеджер безопасности. Пусть, например, некоторый код, связанный с обработкой событий в аплете, создает новый поток. Тогда менеджер безопасности способен включить его в группу потоков аплета, но не в системную группу потоков, обрабатывающих события. Когда поток завершает работу, соответствующий объект Thread удаляется из группы и далее может быть передан в распоряжение сборщика мусора, если иные ссылки на него отсутствуют.
Существуют три разновидности конструкторов класса Thread, позволяющих определить принадлежность создаваемого потока тому или иному объекту типа ThreadGroup. Два из них были рассмотрены в разделе 10.2 на странице 247, при обсуждении интерфейса Runnablе, а третий описан ниже.
public Thread(ThreadGroup group, String name)
Создает новый объект потока с заданным именем name, принадлежащий объекту группы потоков group.
Чтобы предотвратить вероятность присваивания созданных потоков произвольным группам (это способно ослабить механизм обеспечения безопасности), указанные конструкторы сами по себе могут выбрасывать исключение типа SecuгityException, если потоку-"родителю" не позволено размещать созданный поток в пределах некоторой группы.
После создания потока признак его принадлежности определенному объекту ThreadGroup изменить уже нельзя. Чтобы получить информацию о том, к какой группе относится поток, следует воспользоваться методом getThreadGroup. Для проверки того, допускает ли поток влияние извне (в том смысле, о котором было сказано выше), может применяться метод checkAccess, который генерирует исключение типа securityException, если делать это запрещено, и просто возвращает управление в противном случае (метод объявлен как void).
Группа потоков может быть группои-демопом (daemon group). Впрочем, это понятие никак не связано с концепцией потоков-демопов. "Демонический" объект ThreadGroup автоматически уничтожается, если он становится пустым. Задание признака принадлежности объекта ThreadGroup к категории группдемонов не имеет отношения к тому, является ли любой из потоков, принадлежащих группе, потоком-демоном. Признак воздействует на поведение группы потоков только в том случае, когда она становится пустой.
Объекты групп могут быть использованы также для задания верхней границы значений приоритетов потоков, относящихся к группе. После вызова метода setMaxpriогity с передачей ему соответствующего наибольшего допустимого значения приоритета любая попытка задания значения, превышающего установленный порог, сводится к повышению приоритета потока только до величины максимального уровня. Вызов метода не воздействует на характеристики существующих потоков. Чтобы обеспечить "господство" одного определенного потока группы над всеми другими (т.е. гарантировать, что его приоритет будет всегда заведомо выше остальных), достаточно вначале задать в качестве Приоритета этого потока наивысшее требуемое значение, а затем с помощью вызова setMaxpriогity установить верхнюю границу приоритетов остальных Потоков группы. Задаваемый предел применяется также к группе потоков как таковой. любая попытка задать новое наибольшее значение, превышающее текущее, будет сведена к повышению приоритета группы потоков только до ранее установленной величины максимального уровня.
static synchronized void maxThread(Thread thr, int priority)
{
ThreadGroup grp = thr.getThreadGroup();
thr.setPriority(priority);
grp.setMaxPriority(thr.getPriority() – 1);
}
Приведенный выше метод предполагает задание требуемого значения приоритета потока, а затем – максимально допустимого приоритета группы потоков, меньшего, нежели установленный приоритет "главного" потока. Новое значение верхней границы приоритетов для группы на единицу меньше фактического приоритета потока; написать просто priority-1 не достаточно, поскольку ранее заданный верхний порог может ограничить наши возможности. Разумеется, в этом примере мы предполагаем, что ни один из потоков группы не обладает предварительно установленным большим приоритетом.
Класс ThreadGroup поддерживает конструкторы и методы, перечисленные ниже.
public ThreadGroup(String name)
Создает новый объект класса ThreadGroup, принадлежащий той группе потоков, к которой относится и поток-"родитель". Как и в случае объектов потоков, имена групп не используются исполняющей системой непосредственно, но в качестве параметра name имени группы может быть передано значение null.
public ThreadGroup(ThreadGroup parent, String name)
Создает новый объект класса ThreadGroup с указанным именем name в составе "родительской" группы потоков parent. Если в качестве parent передано значение null, выбрасывается исключение типа nullРоinterException.
public final String getName()
Возвращает строку имени текущей группы потоков.
public final ThreadGroup getparent()
Возвращает ссылку на объект "родительской" группы потоков либо null l, если такового нет (последнее возможно только для группы потоков верхнего уровня иерархии).
public final void setDaemon(boolean daemon)
Придает текущему объекту группы потоков статус принадлежности к категории групп-демонов.
Public final boolean isDaemon()
Возвращает статус принадлежности текущего объекта группы потоков к категории групп-демонов.
public final void setMaxPriority(int maxpri)
Устанавливает верхнюю границу приоритетов выполнения для текущей
группы потоков.
public final int getMaxPriority()
Возвращает ранее заданное значение верхней границы приоритетов выполнения для текущей группы потоков.
public final boolean parentOf(ThreadGroup g)
Проверяет, является ли текущая группа "родительской" по отношению к группе g либо совпадает с группой g.
public final void checkAccess()
Выбрасывает исключение типа SecurityException, если текущему Потоку не позволено воздействовать на параметры группы потоков; в против_ ном случае просто возвращает управление.
public final void destroy()
Уничтожает объект группы потоков. Группа не должна содержать птоков, иначе метод выбрасывает исключение типа IllegalThreadStateException. Если в составе группы имеются другие группы, они также не должны содержать потоков. Не уничтожает объекты потоков, принадлежащих группе.
Содержимое группы потоков можно проверить с помощью двух наборов методов: одни возвращают информацию о потоках, принадлежащих группе, а другие – о вложенных группах.
public int activeCount()
Возвращает приблизительное количество действующих (активных) потоков группы, включая и те потоки, которые принадлежат вложенным группам. Количество нельзя считать точным, поскольку в момент выполнения метода оно может измениться, – одни потоки "умирают", а другие создаются. Поток считается действующим, если метод isAlive соответствующего объекта Thread возвращает значение true.
public int enumerate(Thread[] threadsInGroup, boolean recurse)
Заполняет массив threadsInGroup ссылками на объекты действующих потоков группы, принимая во внимание размер массива, и возвращает количество сохраненных ссылок. Если значение параметра recurse равно false, учитываются только те потоки, которые принадлежат непосредственно текущей группе, а в противном случае – еще и потоки, относящиеся. ко всем вложенным группам. ThreadGroup.enumerate предоставляет возможность управления процессом рекурсивного просмотра иерархии вложенных групп, а метод ThreadGroup. activeCount – нет. Последний позволяет получить достаточно точную оценку размера массива, необходимого для хранения результатов выполнения рекурсивной версии enumerate; но при задании в качестве параметра recurse значения false оценка размера массива Окажется завышенной.
public int enumerate(Thread[] threadsInGroup)
Метод аналогичен предыдущему при условии enumerate(threadsInGroup, true).
public int activeGroupCount()
Подобен методу activeCount, но подсчитывает количество групп, включая вложенные. Термин активный ("active") в данном случае означает су-
Do'stlaringiz bilan baham: |