Суббота, 2025-07-19, 07:43:09
Главная Регистрация RSS
Приветствую Вас, Гость
Форма входа
Мини-чат
Главная » 2011 » Октябрь » 24 » Многопоточность JAVA (очень понятная русская статья)
14:30:21
Многопоточность JAVA (очень понятная русская статья)
МНОГОПОТОЧНОЕ
ПРОГРАММИРОВАНИЕ
Гончаров Сергей Леонидович
Старший преподаватель кафедры МИОЭС
Понятие многопоточности
— Java обеспечивает встроенную поддержку для
многопоточного программирования.
— Многопоточная программа содержит две и более
частей, которые могут выполняться
одновременно, конкурируя друг с другом.
— Каждая часть такой программы называется
потоком, а каждый поток определяет отдельный
путь выполнения (в последовательности
операторов программы).
— Многопоточность — это специализированная
форма многозадачности.
Понятие многопоточности
— Существуют две различные формы многозадачности. Одна основана на
процессах, а другая — на потоках.
— Процесс — это, по существу, выполняющаяся программа.
— Основанная на процессах многозадачность — это свойство, которое позволяет
вашему компьютеру выполнять несколько программ одновременно. Такая
многозадачность дает, например, возможность выполнять компилятор Java
одновременно с использованием текстового редактора. В многозадачности,
основанной на процессах, самой мелкой единицей диспетчеризации
планировщика является программа.
— В многозадачной среде, основанной на потоках, самой мелкой единицей
диспетчеризации является поток. Это означает, что отдельная программа
может исполнять несколько задач одновременно. Например, текстовый
редактор может форматировать текст одновременно с печатью документа,
поскольку эти два действия выполняются двумя отдельными потоками. Таким
образом, многозадачность, основанная на процессах, имеет дело со всей
картиной, а поточная многозадачность обрабатывает детали.
Понятие многопоточности
— Многозадачные потоки требуют меньших накладных
расходов по сравнению с многозадачными процессами.
Процессы — это тяжеловесные задачи, которым
требуются отдельные адресные пространства. Связи
между процессами ограничены и стоят не дешево.
Переключение контекста от одного процесса к другому
также весьма дорогостоящая задача.
— С другой стороны, потоки достаточно легковесны. Они
совместно используют одно и то же адресное
пространство и кооперативно оперируют с одним и тем
же тяжеловесным процессом, межпоточные связи
недороги, а переключение контекста от одного потока к
другому имеет низкую стоимость.
Понятие многопоточности
— Многопоточность дает возможность писать очень эффективные
программы, которые максимально используют CPU, потому что
время его простоя можно свести к минимуму.
— Это особенно важно для интерактивной сетевой среды, в
которой работает Java, потому что время простоя является
общим.
— Скорость передачи данных по сети намного меньше, чем
скорость, с которой компьютер может их обрабатывать.
— В традиционной однопоточной среде ваша программа должна
ждать окончания каждой своей задачи, прежде чем она сможет
перейти к следующей (даже при том, что большую часть
времени CPU простаивает).
— Многопоточность позволяет получить доступ к этому времени
простоя и лучше его использовать.
Поточная модель Java
— Исполнительная система Java во многом зависит от потоков, и
все библиотеки классов разработаны с учетом
многопоточности.
— Java использует потоки для обеспечения асинхронности во
всей среде.
— Ценность многопоточной среды лучше понимается по
контрасту с ее аналогом.
— Однопоточные системы используют подход, называемый
циклом событий с опросом (event loop with polling). В этой
модели, единственный поток управления выполняется в
бесконечном цикле, опрашивая единственную очередь
событий, чтобы решить, что делать дальше. Как только этот
механизм опроса возвращает сигнал готовности сетевого
файла готов для чтения, цикл событий передает управление
соответствующему обработчику событий. До возврата из этого
обработчика в системе ничего больше случиться не может.
Поточная модель Java
— Выгода от многопоточности Java заключается в том, что
устраняется механизм "главный цикл/опрос". Один поток
может делать паузу без остановки других частей
программы. Например, время простоя, образующееся,
когда поток читает данные из сети или ждет ввод
пользователя, может использоваться в другом месте.
— Многопоточность позволяет циклам мультипликации
бездействовать в течение секунды между каждым
фреймом без принуждения делать паузу целой системы.
Когда потоки блокируются в Java-программе, паузу
"держит" только один поток — тот, который блокирован.
Остальные продолжают выполняться.
Поточная модель Java
— Потоки существуют в нескольких состояниях.
Ø Поток может быть в состоянии выполнения.
Ø Может находиться в состоянии готовности к
выполнению, как только он получит время CPU.
Ø Выполняющийся поток может быть приостановлен,
что временно притормаживает его действие.
Ø Затем приостановленный поток может быть
продолжен (возобновлен) с того места, где он был
остановлен.
Ø Поток может быть блокирован в ожидании ресурса.
В любой момент выполнение потока может быть
завершено, что немедленно останавливает его
выполнение.
Приоритеты потоков
— Java назначает каждому потоку приоритет, который
определяет порядок обработки этого потока
относительно других потоков.
— Приоритеты потоков — это целые числа, которые
определяют относительный приоритет одного потока
над другим.
— Высокоприоритетный поток не выполняется
быстрее, чем низкоприоритетный.
— Приоритет потока используется для того, чтобы
решить, когда переключаться от одного
выполняющегося потока к следующему. Это
называется переключением контекста.
Приоритеты потоков
— Правила, которые определяют, когда переключение контекста
имеет место.
Ø Поток может добровольно отказаться от управления. Это
делается явно, переходом в режим ожидания или
блокированием на ожидающем вводе/выводе. В этом сценарии
просматриваются все потоки, и CPU передается самому
высокоприоритетному потоку, который готов к выполнению.
Ø Поток может быть приостановлен более приоритетным
потоком. В этом случае занимающий процессор
низкоприоритетный поток временно останавливается
(независимо от того, что он делает) потоком с более высоким
приоритетом. Данный механизм называется упреждающей
многозадачностью (preemptive multitasking).
Синхронизация
— Поскольку многопоточность обеспечивает асинхронное поведение ваших
программ, должен существовать способ добиться синхронности, когда в этом
возникает необходимость.
— Например, если вы хотите, чтобы два потока взаимодействовали и совместно
использовали сложную структуру данных типа связного списка, нужно каким-то
образом гарантировать отсутствие между ними конфликтов.
— Вы должны удержать один поток от записи данных, пока другой поток
находится в процессе их чтения.
— Для этой цели Java эксплуатирует модель синхронизации процессов —
монитор.
— Монитор — это механизм управления связью между процессами. Вы можете
представлять монитор, как очень маленький блок, который содержит только
один поток. Как только поток входит в монитор, все другие потоки должны
ждать, пока данный не выйдет из монитора. Таким образом, монитор можно
использовать для защиты совместно используемого (разделяемого) ресурса от
управления несколькими потоками одновременно.
Синхронизация
— Большинство многопоточных систем создает
мониторы как объекты, которые ваша программа
должна явно получить и использовать.
— В Java-системе нет класса с именем Monitor.
Вместо этого, каждый объект имеет свой
собственный неявный монитор, который
вводится автоматически при вызове одного из
методов объекта.
— Как только поток оказывается внутри
синхронизированного метода, никакой другой
поток не может вызывать иной
синхронизированный метод того же объекта.
Передача сообщений
— После того как вы разделите свою программу на
отдельные потоки, нужно определить, как они
будут взаимодействовать друг с другом.
— Java обеспечивает ясный, дешевый путь для
взаимного общения двух (или нескольких)
потоков через вызовы предопределенных
методов, которыми обладают все объекты.
— Система передачи сообщений Java позволяет
потоку войти в синхронизированный метод на
объекте и затем ждать там, пока некоторый
другой поток явно не уведомит его о выходе.
Класс Thread и интерфейс Runnable
— Многопоточная система Java построена на
классе Thread, его методах и связанном с ним
интерфейсе Runnable.
— Thread инкапсулирует поток выполнения. Так как
вы не можете непосредственно обращаться к
внутреннему состоянию потока выполнения, то
будете иметь с ним дело через его
полномочного представителя — экземпляр
(объект) класса Thread, который его породил.
— Чтобы создать новый поток, ваша программа
должна будет или расширять класс Thread или
реализовывать интерфейс Runnable.
Класс Thread и интерфейс Runnable
Некоторые методы класса Thread
Метод Значение
GetName () Получить имя потока
GetPriority () Получить приоритет потока
IsAlive () Определить, выполняется ли еще поток
Join () Ждать завершения потока
Run () Указать точку входа в поток
Sleep () Приостановить поток на определенный период времени
Start () Запустить поток с помощью вызова его метода run ()
Главный поток
— Когда Java-программа запускается, один
поток начинает выполняться немедленно.
— Он обычно называется главным потоком.
— Главный поток важен по двум причинам:
Ø Это поток, из которого будут порождены все
другие "дочерние" потоки.
Ø Это должен быть последний поток, в котором
заканчивается выполнение. Когда главный
поток останавливается, программа
завершается.
Главный поток
— Хотя главный поток создается автоматически
после запуска программы, он может управляться
через Thread-объект. Для организации
управления нужно получить ссылку на него,
вызывая метод Currentrhread (), который
является public static членом класса Thread. Вот
его общая форма:
static Thread currentThread()
— Этот метод возвращает ссылку на поток, в
котором он вызывается. Как только вы
получаете ссылку на главный поток, то можете
управлять им точно так же, как любым другим
потоком.
Главный поток
// Управление главным потоком,
class CurrentThreadDemo {
public static void main(String args[])
{
Thread t = Thread.currentThread();
System.out.println("Текущий поток: "+t);
// изменить имя потока
t.setName("My Thread");
System.out.println("После изменения
имени: "+t);
try
{
for(int n = 5; n > 0; n--)
{ System.out.println(n);
Thread.sleep(1000); } }
catch (InterruptedException e)
{
System.out.println("Главный поток
завершен"); } } }
— Вывод,
сгенерированный этой
программой:
Текущий поток:
Thread[main,5,main]
После изменения имени:
Thread[My Thread,5,main]
54321
Главный поток
— Обратите внимание на выводы, использующие t в
качестве аргумента printin().
— По умолчанию имя главного потока — main. Его
приоритет равен 5, что тоже является значением по
умолчанию и последний идентификатор main — имя
группы потоков, которой принадлежит данный поток.
— Группа потоков — структура данных,
контролирующая состояние совокупности потоков в
целом. Этот процесс управляется специальной
исполнительной (run-time) средой и подробно здесь
не обсуждается. После изменения имени потока
переменная t снова выводится на экран.
Главный поток
— Методы класса Thread, которые используются в программе.
— Метод sleep () заставляет поток, из которого он вызывается,
приостановить выполнение на указанное (в аргументе вызова)
число миллисекунд. Его общая форма имеет вид:
static void sleep(long milliseconds) throws InterruptedException
— Число миллисекунд интервала приостановки определяется в
параметре milliseconds. Кроме того, данный метод может
выбросить исключение типа InterruptedException.
— Метод sleep() имеет вторую форму, которая позволяет
определять период приостановки в долях миллисекунд и
наносекунд:
static void sleep(long milliseconds, int nanoseconds) throws
InterruptedException
— Эта вторая форма полезна только в средах, где допускаются
короткие периоды времени, измеряемые в наносекундах.
Создание потока
— В самом общем случае для создания
потока строят объект типа Thread. В
Java это можно выполнить двумя
способами:
Øреализовать интерфейс Runnable;
Øрасширить класс Thread, определив его
подкласс.
Реализация интерфейса Runnable
— В Runnable определен некоторый абстрактный (без тела)
модуль выполняемого кода. Создавать поток можно на любом
объекте, который реализует интерфейс Runnable. Для
реализации Runnabie в классе нужно определить только один
метод с именем run().
public void run()
— Внутри run () нужно определить код, образующий новый поток.
— run() может вызывать другие методы, использовать другие
классы и объявлять переменные точно так же, как это делает
главный (main) поток.
— Единственное различие состоит в том, что run о устанавливает
в данной программе точку входа для запуска другого,
конкурирующего потока выполнения.
— Этот поток завершит свое выполнение при возврате из run ().
Реализация интерфейса Runnable
— После создания класса, который реализует Runnable,
нужно организовать объект типа Thread внутри этого
класса.
— В классе Thread определено несколько конструкторов.
— Мы будем использовать конструктор следующей формы:
Thread(Runnable thxeadOb, String threadName)
— Здесь threadOb — экземпляр (объект) класса, который
реализует интерфейс Runnable. Он определяет, где
начнется выполнение нового потока.
— Имя нового потока определяет параметр threadName.
— После того как новый поток создан, он не начнет
выполняться, пока вы не вызываете его методом start (),
который объявлен в Thread.
void start()
Реализация интерфейса Runnable
// Создание второго потока,
class NewThread implements Runnable
{ Thread t;
NewThread() {
// Создать новый, второй поток.
t = new Threadfthis ( "Demo Thread");
System.out.println("Дочерний поток: " + t);
t.startO; // стартовать поток
}
// Это точка входа во второй поток, public void run() {
try {
for(int i = 5; i > 0; i--
{System.out.println("Дочерний Поток: " + i);
Thread.sleep(500);
} }
catch (InterruptedException e) {
System.out.println("Прерывание дочернего потока."); }
System.out.println("Завершение дочернего потока."); } }
class ThreadDemo {
public static void main(String args[])
{new NewThreadO; // создать новый поток
try {
for(int i = 5; i > 0; i--) {
System.out.println("Главный поток: " + i);
Thread.sleep(1000); } }
catch (InterruptedException e) {
System.out.println("Прерывание главного потока."); }
System.out.println("Завершение главного потока. ") ; }}
— Вывод этой программы следующий:
Дочерний поток: Thread[Demo Thread,5,main]
Главный поток: 5
Дочерний Поток 5
Дочерний Поток 4
Главный поток: 4
Дочерний Поток 3
Дочерний Поток 2
Главный поток: 3
Дочерний Поток 1
Завершение дочернего потока.
Главный поток: 2
Главный поток: 1
Завершение главного потока.
Расширение Thread
— Для генерации потока вторым способом
необходимо создать новый класс, который
расширяет Thread, а затем — экземпляр
этого класса.
— Расширяющий класс должен переопределять
метод run (), который является точкой входа
для нового потока.
— Он должен также вызывать start (), чтобы
начать выполнение нового потока.
Расширение Thread
// Создает второй поток расширением класса
// Thread,
class NewThread extends Thread { \
NewThread() {
// Создать новый, второй поток
super("Demo Thread");
System.out.println("Дочерний поток: " + this);
start(); // стартовать поток
}
// Это точка входа для второго потока,
public void run() ( try {
for(int i = 5; i > 0; i--)
{
System.out.println("Дочерний поток: " + i);
Thread.sleep(500); } }. catch
(InterruptedException e)
{
System.out.println("Прерывание дочернего
потока."); }
System.out.println("Завершение дочернего
потока."); } }
class ExtendThread {
public static void main(String args[]) {
new NewThread(); // создать новый поток
try {
for(int i = 5; i > 0; i—) {
System.out.println("Главный поток: " + i);
Thread.sleep(1000); } }
catch (InterruptedException e)
{
System.out.println("Прерывание главного потока.");
}
System.out.println("Завершение главного потока.");
}
}
Выбор подхода
— Какой подход лучше?
— Класс Thread определяет несколько методов,
которые могут быть переопределены производным
классом. Из них только один должен быть
переопределен обязательно — метод run (). Это,
конечно, тот же самый метод, который требовался
для реализации интерфейса Runnable.
— Классы должны расширяться только тогда, когда они
каким-то образом улучшаются или изменяются.
— Так, если вы не будете переопределять никакого
другого метода класса Thread, то, вероятно, лучше
всего просто реализовать интерфейс Runnable
напрямую.
Создание множественных потоков
— До сих пор использовали только два потока
— главный и один дочерний.
— Однако ваша программа может порождать
столько потоков, сколько необходимо.
— Не забывайте использовать метод sleep().
Использование методов isAlive() и
join()
— Существуют два способа определения,
закончился ли поток.
— Один из них позволяет вызывать метод
isAlive() на потоке. Этот метод определен в
Thread и его общая форма выглядит так:
final boolean isAlive()
— Метод isAlive() возвращает true, если поток,
на котором он вызывается — все еще
выполняется. В противном случае
возвращается false.
Использование методов isAlive() и
join()
— В то время как isAlive() полезен только иногда,
чаще для ожидания завершения потока
вызывается метод join() следующего формата:
final void join() throws InterruptedException
— Этот метод ждет завершения потока, на котором
он вызван. Его имя происходит из концепции
перевода потока в состояние ожидания, пока
указанный поток не присоединит его.
— Дополнительные формы join() позволяют
определять максимальное время ожидания
завершения указанного потока.
Приоритеты потоков
— Планировщик потоков использует их приоритеты для принятия
решений о том, когда нужно разрешать выполнение тому или иному
потоку.
— Теоретически высокоприоритетные потоки получают больше времени
CPU, чем низкоприоритетные.
— На практике, однако, количество времени CPU, которое поток
получает, часто зависит от нескольких факторов помимо его
приоритета. (Например, относительная доступность времени CPU
может зависеть от того, как операционная система реализует
многозадачный режим.)
— Высокоприоритетный поток может также упреждать
низкоприоритетный (т. е. перехватывать у него управление
процессором).
— Скажем, когда низкоприоритетный поток выполняется, а
высокоприоритетный поток возобновляется (от ожидания на
вводе/выводе, к примеру), высокоприоритетный поток будет
упреждать низкоприоритетный.
Приоритеты потоков
— Теоретически, потоки равного приоритета должны
получить равный доступ к CPU.
— Для безопасности потоки, которые совместно используют
один и тот же приоритет, должны время от времени
уступать друг другу управление.
— Это гарантирует, что все потоки имеют шанс
выполниться под неприоритетной операционной
системой.
— Практически, даже в неприоритетных средах,
большинство потоков все еще получают шанс
выполняться, потому что большинство из них неизбежно
сталкивается с некоторыми блокирующими ситуациями,
типа ожидания ввода/вывода.
— Когда это случается, блокированный поток
приостанавливается, а другие могут продолжаться.
Приоритеты потоков
— Для установки приоритета потока используйте метод
setPriority(), который является членом класса Thread. Вот
его общая форма:
final void setPriority(int level)
— где level определяет новую установку приоритета для
вызывающего потока.
— Значение параметра level должно быть в пределах
диапазона MIN_PRIORITY И MAX_PRIORITY. В
настоящее время эти значения равны 1 и 10,
соответственно.
— Чтобы вернуть потоку приоритет, заданный по
умолчанию, определите NORM_PRIORITY, который в
настоящее время равен 5.
— Эти приоритеты определены в Thread как final-
переменные.
Приоритеты потоков
— Вы можете получить текущую установку
приоритета, вызывая метод getPriority()
класса Thread, чей формат имеет следующий
вид:
final int getPriority()
— Реализации Java могут иметь радикально
различное поведение, когда они переходят к
планированию.
Синхронизация
— Когда несколько потоков нуждаются в доступе к
разделяемому ресурсу, им необходим некоторый
способ гарантии того, что ресурс будет
использоваться одновременно только одним
потоком.
— Процесс, с помощью которого это достигается,
называется синхронизацией.
— Ключом к синхронизации является концепция
монитора (также называемая семафором).
— Монитор — это объект, который используется для
взаимоисключающей блокировки (mutually exclusive
lock), или mutex.
Синхронизация
— Только один поток может иметь собственный
монитор в заданный момент.
— Когда поток получает блокировку, говорят, что он
вошел в монитор. Все другие потоки пытающиеся
вводить блокированный монитор, будут
приостановлены, пока первый не вышел из
монитора.
— Говорят, что другие потоки ожидают монитор.
— При желании поток, владеющий монитором, может
повторно вводить тот же самый монитор.
— Синхронизировать код можно двумя способами. Оба
используют ключевое слово synchronized.
Использование синхронизированных
методов
— Синхронизация в Java проста потому, что каждый объект
имеет свой собственный неявный связанный с ним
монитор.
— Чтобы ввести монитор объекта, просто вызывают метод,
который был модифицирован ключевым словом
synchronized.
— Пока поток находится внутри синхронизированного
метода, все другие потоки, пытающиеся вызвать его (или
любой другой синхронизированный метод) на том же
самом экземпляре, должны ждать.
— Чтобы выйти из монитора и оставить управление
объектом следующему ожидающему потоку, владелец
монитора просто возвращается из синхронизированного
метода.
Оператор synchronized
— Хотя определения синхронизированных методов внутри
классов — это простые и эффективные средства достижения
синхронизации, они не будут работать во всех случаях.
— Например, вы хотите синхронизировать доступ к объектам
класса, который не был разработан для многопоточного
доступа.
— То есть класс не использует синхронизированные методы.
— Кроме того, этот класс был создан не вами, а третьим лицом, и
вы не имеете доступа к исходному коду.
— Таким образом, вы не можете добавлять спецификатор
synchronized к соответствующим методам в классе.
— Решение данной проблемы весьма просто. Нужно поместить
вызовы методов, определенных этим классом внутрь
синхронизированного блока.
Оператор synchronized
— Вот общая форма оператора synchronized:
synchronized(object) {
// операторы для синхронизации
}
— где object — ссылка на объект, который нужно
синхронизировать.
— Если нужно синхронизировать одиночный
оператор, то фигурные скобки можно опустить.
— Блок гарантирует, что вызов метода, который
является членом объекта object, происходит
только после того, как текущий поток успешно
ввел монитор объекта.
Межпоточные связи
— Вы можете достичь более тонкого уровня управления через связь между
процессами.
— Многопоточность заменяет программирование цикла событий, делением задач на
дискретные и логические модули.
— Потоки также обеспечивают и второе преимущество — они отменяют опрос. Опрос
обычно реализуется циклом, который используется для повторяющейся проверки
некоторого условия.
— Как только условие становится истинным, предпринимается соответствующее
действие. На этом теряется время CPU.
— Например, рассмотрим классическую проблему организации очереди, где один
поток производит некоторые данные, а другой — их потребляет.
— Предположим, что, прежде чем генерировать большее количество данных,
производитель должен ждать, пока потребитель не закончит свою работу.
— В системе же опроса, потребитель тратил бы впустую много циклов CPU на
ожидание конца работы производителя. Как только производитель закончил свою
работу, он вынужден начать опрос, затрачивая много циклов CPU на ожидание
конца работы потребителя. Ясно, что такая ситуация нежелательна.
— Чтобы устранить опросы, Java содержит изящный механизм межпроцессовой связи
через методы wait(), notify() и notifyAll(). Они реализованы как final-методы в классе
object, поэтому доступны всем классам
Межпоточные связи
Ø wait () сообщает вызывающему потоку, что нужно уступить
монитор и переходить в режим ожидания ("спячки"), пока
некоторый другой поток не введет тот же монитор и не вызовет
notify ();
Ø notify () "пробуждает" первый поток (который вызвал wait ()) на
том же самом объекте;
Ø notifyAll() пробуждает все потоки, которые вызывали wait () на
том же самом объекте. Первым будет выполняться самый
высокоприоритетный поток.
— Эти методы объявляются в классе Object в следующей форме:
final void wait() throws XnterruptedException
final void notify()
final void notifyAll()
Блокировка
— Специальный тип ошибки, которую вам нужно избегать и
которая специально относится к многозадачности, это —
(взаимная) блокировка.
— Она происходит, когда два потока имеют циклическую
зависимость от пары синхронизированных объектов.
— Например, предположим, что один поток вводит монитор в
объект х, а другой поток вводит монитор в объект у. Если поток
в х пробует вызвать любой синхронизированный метод объекта
у, это приведет к блокировке, как и ожидается.
— Однако если поток в у, в свою очередь, пробует вызвать любой
синхронизированный метод объекта х, то он будет всегда
ждать, т. к. для получения доступа к х, он был бы должен снять
свою собственную блокировку с У, чтобы первый поток мог
завершиться.
Блокировка
— Взаимоблокировка — трудная ошибка для
отладки по двум причинам:
Ø Вообще говоря, она происходит очень редко,
когда интервалы временного квантования двух
потоков находятся в определенном
соотношении.
Ø Она может включать больше двух потоков и
синхронизированных объектов. (То есть
блокировка может происходить через более
замысловатую последовательность событий,
чем только что описано.)
Приостановка, возобновление и
остановка потоков в Java
— Приостановка выполнения потока иногда
полезна.
— Например, отдельные потоки могут
использоваться, чтобы отображать время дня.
Если пользователь не хочет видеть
отображения часов, то их поток может быть
приостановлен. В любом случае приостановка
потока — простое дело. После приостановки
перезапуск потока также не сложен.
— Механизмы приостановки, остановки и
возобновления потоков различны для Java 2 и
более ранних версий Java.
Приостановка, возобновление и
остановка потоков в Java
— До Java 2 для приостановки и перезапуска
выполнения потока программа использовала методы
suspend () и resume (), которые определены в классе
Thread. Они имеют такую форму:
final void suspend()
final void resume()
— Класс Thread также определяет метод с именем
stop(), который останавливает поток. Его сигнатура
имеет следующий вид:
void stop()
— Если поток был остановлен, то его нельзя
перезапускать с помощью метода resume().
Приостановка, возобновление и
остановка потоков в Java
— В Java 2 запрещено использовать методы suspend(),
resume() или stop() для управления потоком.
— Поток должен быть спроектирован так, чтобы метод run()
периодически проверял, должен ли этот поток
приостанавливать, возобновлять или останавливать свое
собственное выполнение.
— Это, как правило, выполняется применением флажковой
переменной, которая указывает состояние выполнения
потока.
— Пока флажок установлен на "выполнение", метод run()
должен продолжать позволять потоку выполняться.
— Если эта переменная установлена на "приостановить",
поток должен сделать паузу. Если она установлена на
"стоп", поток должен завершиться.
Использование многопоточности
— Ключом к эффективному использованию указанной поддержки
является скорее параллельное (одновременное), чем
последовательное мышление.
— Например, когда вы имеете две подсистемы внутри программы,
которые могут выполняться одновременно, организуйте их
индивидуальными потоками.
— С осторожным использованием многопоточности вы можете создавать
очень эффективные программы.
— Однако необходимы и предостережения.
— Если вы создадите слишком много потоков, то, напротив, ухудшите
эффективность программы.
— Помните, что с контекстным переключением связаны некоторые
издержки.
— Если вы создаете слишком много потоков, больше времени CPU будет
потрачено на изменения контекстов, чем на выполнение вашей
программы.
Спасибо за внимание!
Просмотров: 11059 | Добавил: MINIsha
Всего комментариев: 0
Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]