Безпека потоків і ThreadGroup

При програмуванні роботи декількох потоків (частина яких створюється бібліотечними викликами) буває корисно частково обмежити їх можливості, щоб потоки не заважали один одному

Потоки діляться на групи потоків в цілях безпеки Група потоків може входити до складу іншої групи, що дозволяє створювати певну ієрархію Потоки всередині групи можуть змінювати інші потоки, що входять в ту ж групу, а також в усі групи, розташовані нижче в ієрархії Потік не може модифікувати потоки за межами своєї власної та всіх підлеглих груп

Ці обмеження використовуються для захисту потоків від свавілля з боку інших потоків Якщо нові потоки поміщаються в окрему групу всередині вже існуючої групи, то пріоритети породжених потоків можуть змінюватися, проте нові потоки не зможуть вплинути на пріоритети існуючих потоків або будь-яких потоків за межами своєї групи

Кожен потік належить до певної групи Обмеження, що накладаються на потоки, що входять до групи, описуються обєктом ThreadGroup Група може здаватися в конструкторі потоку за замовчуванням кожен новий потік поміщається в ту ж групу, в

яку входить його потік-творець Після завершення потоку відповідний обєкт віддаляється з групи

public Thread(ThreadGroup group, String name)

Конструює новий потік із заданим імям name (може дорівнювати null),

що належить конкретній групі

Після того як обєкт буде створений, ви вже не зможете змінити повязаний з ним обєкт ThreadGroup Щоб дізнатися, якої групи належить деякий потік, слід викликати його метод getThreadGroup Крім того, можна перевірити, чи припустима модифікація потоку, – для цього викличте його метод checkAccess Цей метод збуджує виняток SecurityException, якщо ви не можете модифікувати потік, і просто завершується в іншому випадку (метод має тип void)

Групи потоків можуть бути групами-демонами Такі групи автоматично знищуються, коли в них не залишається ні одного потоку Те, що група є групою-демоном, ніяк не впливає на демонізм належать їй потоків або груп Статус групи-демона визначає лише те, що відбувається з нею, коли група стає порожньою

Групи потоків також можуть використовуватися для завдання максимального пріоритету потоків, що входять до неї Після виклику методу setMaxPriority, що задає максимальний пріоритет групи, при будь-якій спробі підняти пріоритет потоку вище вказаного значення відбувається його непомітне зниження до оголошеного максимуму Виклик цього методу не впливає на існуючі потоки Щоб бути впевненим у тому, що пріоритет деякого потоку завжди буде перевищувати пріоритет всіх інших потоків групи, слід встановити для нього пріоритет MAX_PRIORITY, після чого встановити максимальний пріоритет групи рівним MAX_PRIORITY-1 Обмеження відноситься і до самій групі потоків – при спробі встановити для неї максимальний пріоритет, що перевищує поточне значення, станеться непомітне зниження затребуваного пріоритету:

static public void maxThread(Thread thr) { ThreadGroup grp = thrgetThreadGroup() thrsetPriority(ThreadMAX_PRIORITY) grpsetMaxPriority(thrgetPriority()  – 1)

}

Даний метод спочатку встановлює для потоку найвищий пріоритет, після чого опускає максимально допустимий пріоритет групи нижче пріоритету цього потоку Новий максимальний пріоритет групи встановлюється на одиницю меншим пріоритету групи, а не ThreadMAX_PRIORITY-1, оскільки чинний максимум групи може обмежити ваше право задавати для потоку пріоритет MAX_PRIORITY Вам потрібно, щоб пріоритет потоку був найвищим з можливих в даній групі, а максимальний пріоритет групи був нижче нього, і при цьому неважливо, якими будуть конкретні

значення

ThreadGroup містить наступні конструктори і методи:

public ThreadGroup(String name)

Створює нову групу ThreadGroup, приналежну групі ThreadGroup поточного потоку Імена груп, як і імена потоків, не використовуються runtime-системою Якщо імя одно null, збуджується виключення Null PointerException Цим обєкти ThreadGroup відрізняються від обєктів Thread, у яких наявність імені необовязково

public ThreadGroup(ThreadGroup parent, String name)

Створює нову групу ThreadGroup із заданим імям, що належить зазначеній групі ThreadGroup Як і в інших конструкторах, наявність імені є обовязковим

public final String getName() Повертає імя групи ThreadGroup public final ThreadGroup getParent()

Повертає батьківську групу ThreadGroup або null, якщо її не існує

public final void setParent(boolean daemon) Встановлює демонічний статус групи public final boolean isDaemon()

Повертає демонічний статус групи

public final synchronized void setMaxPriority(int  maxPri)

Встановлює максимальний пріоритет групи public final int getMaxPriority()

Повертає поточний максимальний пріоритет групи public final boolean parentOf(ThreadGroup g)

Перевіряє, чи є поточна група батьком групи g або ж збігається з нею Краще уявляти собі цей метод в термінах є частиною, так як група є частиною самої себе

public final void checkAccess()

Збуджує виняток SecurityException, якщо поточний потік не має права на модифікацію групи В іншому випадку метод просто завершується

public final synchronized void destroy()

Знищує поточну групу типу ThreadGroup Група, в якій містяться потоки, не може бути знищена при спробі зробити це збуджується виключення IllegalThreadStateException Це означає, що метод destroy не може застосовуватися для знищення всіх потоків групи – це необхідно зробити вручну, скориставшись описаними нижче методами перерахування Якщо до групи входять інші групи, то вони також повинні бути порожніми

Для перегляду вмісту групи використовуються два паралельних набору методів: один з них служить для отримання інформації про потоках, а інший – про групи потоків, що належать даній групі Приклад використання цих методів можна знайти в методі safeExit

public synchronized int activeCount()

Повертає приблизну кількість активних потоків в групі, включаючи потоки, що містяться в підгрупах Значення буде лише зразковим, оскільки до моменту його одержання кількість активних потоків може змінитися під час виклику activeCount одні потоки можуть завершитися, а інші – почати роботу

public int enumerate(Thread[]  threadsInGroup, boolean recurse)

Заповнює масив threadsInGroup посиланнями на всі активні потоки в групі до заповнення масиву Якщо значення recurse одно false, то перераховуються лише потоки, що безпосередньо входять в групу якщо ж воно дорівнює true, то перераховуються всі потоки в ієрархії Thread Groupenumerate, на відміну від ThreadGroupactiveCount, дозволяє визначити, включаєте ви потоки в підгрупах чи ні Це означає, що ви можете отримати розумну оцінку для розміру масиву, необхідного для зберігання результатів рекурсивного перерахування, однак для перерахування, що не враховує підгруп, така оцінка виявиться завищеною

public int enumerate(Thread[] threadsInGroup) Еквівалентно enumerate (threadsInGroup, true) public synchronized int activeGroupCount()

Аналогічний методу activeCount, однак підраховує НЕ потоки, а групи, в тому числі і

у всіх підгрупах Активний (active) в даному випадку означає існуючий. Неактивних груп не буває термін використовується лише для дотримання єдиного стилю з activeCount

public int enumerate(ThreadGroup[] groupsInGroup,   boolean       recurse)

Аналогічний методу enumerate для потоків, однак заповнює масив посиланнями на обєкти-групи типу ThreadGroup замість обєктів-потоків Thread

public int enumerate(ThreadGroup[] groupsInGroup)

Еквівалентно enumerate (groupsInGroup, true)

Обєкти ThreadGroup можуть також використовуватися для управління потоками, що входять до групи Перераховані нижче методи впливають на всі потоки, що входять в групу і у всі її підгрупи:

public final synchronized void stop()

Завершує всі потоки в групі і у всіх її підгрупах public final synchronized void suspend()

Призупиняє всі потоки в групі і у всіх її підгрупах public final synchronized void resume()

Відновлює всі потоки в групі і у всіх її підгрупах

Ці методи надають єдину можливість прямого використання обєкта

ThreadGroup для завдання параметрів потоків

У класі Thread також є два статичних методу для роботи з групою, в яку входить поточний потік Вони являють собою скорочений запис для послідовного виклику getCurrentThread, getThread Group і виклику методу для знайденої групи:

public static int activeCount()

Повертає кількість активних потоків в групі, до якої входить поточний потік public static int enumerate(Thread[] tarray)

Повертає кількість потоків в групі, до якої входить поточний потік

Клас ThreadGroup також містить метод, що викликається при завершенні потоку, через неперехваченного переривання:

public void uncaughtException(Thread[] thr, Throwable exc)

Викликається при завершенні потоку, викликаному неперехваченним перериванням

Даний метод є відкритим, так що ви можете перевизначити його для обробки неперехваченних переривань за своїм бажанням Реалізація, прийнята за замовчуванням, викликає метод uncaughtException групи-батька, якщо така є, або метод ThrowableprintStackTrace в іншому випадку Наприклад, при розробці графічної оболонки було б бажано відобразити вміст стека у вікні, замість того щоб просто вивести його в Systemout, як це робить метод printSt a ckTrace Ви можете перевизначити uncaughtException в своїй групі, щоб створити потрібне вікно і перенаправити в нього вміст стека

914 Налагодження потоків

Кілька методів класу Thread призначені для полегшення налагодження багатопоточних додатків Ці кошти використовуються для виведення інформації про стан програми Нижче наведено список методів класу Thread, що допомагають у процесі налагодження:

public String toString()

Повертає строкове опис потоку, що включає його імя, пріоритет і імя групи public String countStackFrames()

Повертає кількість кадрів стека в потоці

public static void dumpStack()

Виводить в Systemout зміст стека для поточного потоку

Також існує ряд налагоджувальних засобів для відстеження стану групи потоків Наступні методи викликаються для обєктів ThreadGroup і видають інформацію про їх стан:

public String toString()

Повертає строкове опис групи, що включає її імя і пріоритет public synchronized void list()

Виводить в Systemout список вмісту групи та її підгруп

Глава 10

ПАКЕТИ

Бібліотека – це арсенал волі

Джерело невідомий

Під поняттям пакет мається на увазі обєднання взаємозалежних класів, інтерфейсів і підпакету Концепція пакета виявляється корисною з кількох причин:

Пакети дозволяють групувати споріднені інтерфейси і класи

У інтерфейсах і класах, що входять в пакет, можуть використовуватися популярні імена (на кшталт get або put), які мають сенс у даному контексті, але конфліктують з тими ж іменами в інших пакетах

Пакет може включати типи і члени, з якими можна працювати тільки в межах даного пакета Відповідні ідентифікатори доступні для програм пакета, але закриті для зовнішніх методів

Давайте розглянемо приклад пакета для нашого класу атрибутів, використаного в попередніх розділах Назвемо пакет attr Кожен вихідний файл, класи та інтерфейси якого належать пакету attr, повинен вказувати на свою приналежність до пакету оголошенням package:

package attr

Тим самим оголошується, що всі класи та інтерфейси, визначені в цьому вихідному файлі, є частиною пакету attr Оголошення package повинно знаходитися на самому початку файлу, до будь-яких оголошень класів або інтерфейсів у файлі може бути присутнім всього одне оголошення package Імя пакету є неявним префіксом для всіх імен типів, включених в пакет

Якщо фрагменту програми поза пакета знадобиться звернутися до типів, що входять в пакет, у нього є дві можливості Перша – вказувати перед кожним імям типу префікс (імя пакета) Такий варіант буде цілком розумний, якщо вам доводиться мати справу все з кількома членами пакета

Інша можливість доступу до типів пакета полягає в частковому або повному імпортуванні пакета Програміст, який захоче скористатися пакетом attr, може вставити наступний рядок в початок свого вихідного файлу (після свого оголошення package, але перед усім іншим):

import attr*

Після цього він може звертатися до типів пакета просто по імені – наприклад, Attributed Пакет неявно імпортує сам себе, так що все, що визначено в ньому, стає доступним для всіх інших типів пакета

Механізми package і import допомагають програмісту запобігати потенційні конфлікти імен Якщо в пакеті, призначеному для інших цілей (скажімо, лінгвістичних), теж зустрінеться клас з імям Attributed, призначений для зберігання мовних атрибутів, то у програміста, який побажав використовувати обидва пакети в одному файлі, є кілька варіантів:

Звертатися до типів по їх повним іменах – наприклад, attrAttributed і

linguaAttributed

Імпортувати attrAttributed або attr *, Після чого використовувати просте імя

Attributed замість attrAttributed і повне імя linguaAttributed

Зробити зворотне – імпортувати linguaAttributed або lingua *, Після чого використовувати просте імя Attributed замість lingua Attributed і повне імя attrAttributed

Джерело: Арнольд К, Гослінг Д – Мова програмування Java (1997)

Схожі статті:


Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*