webprogr.ru Новости

RSS

{{toodo.preview}}

...
{{toodo.name}}

{{toodo.preview}}

далее..

{{toodo.preview}}

{{toodo.name}}

{{toodo.preview}}

смотреть..

toodo.name

{{toodo.preview}}

{{toodo.name}}

{{toodo.preview}}

перейти...

{{toodo.preview}}

...
{{toodo.name}}

{{toodo.preview}}

далее..

{{toodo.preview}}

{{toodo.name}}

{{toodo.preview}}

смотреть..

toodo.name

{{toodo.preview}}

{{toodo.name}}

{{toodo.preview}}

перейти...


Последние новости

Основные методы класса Thread


start() – запускает новый поток, передав управление методу run() в этом потоке.

run() – код, выполняемый в потоке; определяется в классе Thread (можно переопределить) или в переданном объекте Runnable.

sleep(ms) – приостанавливает текущий поток на заданное время (миллисекунды).

join() – заставляет текущий поток ждать завершения другого потока.

interrupt() – посылает потоку сигнал прерывания (устанавливает флаг interrupted).

isAlive() – возвращает true, если поток запущен и еще не завершен.

Пояснение:
Класс Thread предоставляет множество методов для управления потоками. Рассмотрим наиболее важные из них более подробно:

start() – самый главный метод класса Thread. Он создает новую нить выполнения. Внутри start() JVM выделяет ресурсы для потока, регистрирует его у планировщика и затем вызывает метод run() этого объекта в новом потоке. Метод start() можно вызвать только один раз за жизненный цикл объекта Thread; повторный вызов приведет к исключению. Важно: если не вызвать start(), никакой новый поток не начнется. Иногда новички ошибочно вызывают run() вручную – тогда код выполняется в текущем потоке, а не параллельно.


run() – содержит логику работы потока. По умолчанию в классе Thread метод run() пустой, поэтому обычно есть два подхода: либо переопределить run() в подклассе Thread, описав в нем нужные действия, либо передать реализацию Runnable при создании Thread – тогда поток выполнит код внутри метода run() объекта Runnable. В обоих случаях логика потока находится в методе run(). Вызывать run() напрямую обычно не имеет смысла – как сказано выше, это приведет к обычному последовательному выполнению метода в текущем потоке, без какой-либо параллельности.


sleep(long millis) – статический метод, который приостанавливает текущий поток на указанное количество миллисекунд. Его вызывают как Thread.sleep(1000) например. Метод заставляет поток уйти в состояние TIMED_WAITING на заданный период времени. По истечении времени поток снова перейдет в состояние RUNNABLE. sleep() может выбросить проверяемое исключение InterruptedException, потому что спящий поток можно прервать (см. interrupt() ниже). Поэтому вызов sleep() всегда нужно оборачивать в блок try-catch или объявлять в сигнатуре метода. Пример использования:


try {
    Thread.sleep(500); // приостановить поток на 0.5 секунды
} catch (InterruptedException e) {
    // поток проснулся раньше времени по сигналу прерывания
    System.out.println("Sleep interrupted!");
    Thread.currentThread().interrupt(); // восстанавливаем флаг прерывания
}


Обратите внимание: вызов sleep() не освобождает никакие монитор-локи, которые удерживает поток. То есть если поток вошел в synchronized-блок и вызвал sleep(), то монитор останется заблокированным на время сна.


join() – позволяет одному потоку подождать завершения другого. Если у вас есть поток t, вызов t.join(); приостановит текущий поток до тех пор, пока поток t не закончит выполнение (либо до наступления исключительной ситуации). Это удобно, когда нужно дождаться результатов работы фонового потока. У метода есть перегрузки join(long millis) и join(long millis, int nanos) – они позволяют задать максимальное время ожидания. Если время истечет, метод выйдет, даже если поток еще не завершен. При ожидании без таймаута join() может блокировать текущий поток очень долго, поэтому применять его следует осознанно. Как и sleep(), метод join() может бросить InterruptedException, если текущий поток был прерван пока ждал.


interrupt() – посылает потоку запрос на прерывание. Вызов thread.interrupt() не убивает поток мгновенно и не генерирует исключение сам по себе внутри целевого потока. Он лишь устанавливает специальный флаг "interrupted" у объекта Thread. Этот флаг могут проверять как сам поток, так и внешние компоненты. Многие методы блокирующих операций (такие как Thread.sleep(), Object.wait() и методы ввода-вывода NIO) реагируют на прерывание: они бросают InterruptedException и тем самым уведомляют поток, что его попросили остановиться. Самый распространенный паттерн – при длинных вычислениях периодически проверять статус прерывания через Thread.interrupted() или Thread.currentThread().isInterrupted(), и при флаге true аккуратно завершать работу потока. Например:


public void run() {
    while (!Thread.currentThread().isInterrupted()) {
        // ... выполняем задачи ...
    }
    // Если флаг прерывания установлен, выходим из цикла и завершаем run()
}


Таким образом, interrupt() реализует кооперативную модель остановки потоков: поток сам решает корректно ли ему остановиться, проверяя флаг. Прерывание потоков – более безопасный способ сигнализировать о прекращении работы, чем устаревшие методы stop() (он мгновенно останавливал поток, но приводил к несогласованности данных, поэтому был deprecated).


isAlive() – возвращает булево значение, показывающее, работает ли поток. Он вернет true после вызова start() и до тех пор, пока поток не перешел в состояние TERMINATED. Иными словами, isAlive() служит для проверки: был ли поток запущен и не завершен ли он еще. Например, часто после старта потока делают if (t.isAlive()) { ... } чтобы удостовериться, что поток действительно запущен, или в цикле ждут, пока поток перестанет быть "alive". Однако обычно вместо ручной проверки isAlive() предпочитают использовать механизмы синхронизации (тот же join() или другие), чтобы поток безопасно дождался другого.

Кроме указанных, класс Thread содержит и другие методы управления потоками. Например, есть методы управления приоритетом (setPriority(int)), но их использование не рекомендуется, поскольку планировщик ОС зачастую игнорирует приоритеты Java-потоков или разница незначительна. Также есть метод setDaemon(boolean) для пометки потока как демона (описано выше). Метод yield() позволяет потоку добровольно уступить оставшееся время квантa другим потокам, но его семантика нечеткая и от него мало пользы – в современных JVM он обычно не нужен. Устаревшие и опасные методы suspend(), resume(), stop() уже давно не используются из-за проблем с блокировкой ресурсов и целостностью данных. Вместо них правильнее применять описанный выше механизм прерывания или более высокоуровневые инструменты.
 
Современные практики разработки на Java зачастую сводят к минимуму прямое использование класса Thread. Вместо явного создания потоков вручную рекомендуется пользоваться пулом потоков через ExecutorService и связанными интерфейсами (Callable, Future и т.д.). Это обеспечивает лучшее распределение задач по ограниченному числу потоков и упрощает управление жизненным циклом потоков (не нужно самостоятельно вызывать join для десятков потоков и следить за их завершением – ExecutorService может это делать). Тем не менее, понимать методы Thread необходимо, так как они лежат в основе работы ExecutorService и других высокоуровневых средств. К тому же, при отладке многопоточных проблем часто приходится оперировать низкоуровневыми понятиями потоков.
 
Рейтинг@Mail.ru