Thread Life Circle, состояние объекта Thread - 1

— Привет, Амиго!

Мы начинаем новую тему – работа с нитями или как их еще называют – трэдами (от thread).

— А я слышал, что треды называют потоками.

— Да, такое название все еще употребляется, но постепенно выходит из моды. Проблема в том, что есть еще stream, который дословно переводится как «поток». Поэтому thread’ы принято называть нитями (дословный перевод) или программными потоками. В противовес stream’ам, которые называют потоками ввода-вывода.

Итак. Сегодня мы рассмотрим состояния объекта Thread, через которые он проходит (или может проходить) в процессе работы нити.

Сколько состояний ты можешь назвать прямо сейчас, Амиго?

— Два. Первое – это нить до вызова метода start(): объект есть, но нить еще не активна. И второе — после вызова метода start() – когда нить что-то делает, важное.

— Ты прав, такое разграничение есть, эти состояния называются new и running, но это только самое начало.

Во-первых, нить когда-нибудь заканчивает работу, а значит, может быть такая ситуация – объект Thread есть, но нить не в состоянии new и не в состоянии running. Такое состояние, когда нить завершила работу, называется terminated.

Но и это еще не все. Не стоит забывать, что в каждый момент времени работает только одна нить. А видимая одновременная работа – это постоянное перескакивание процессора с нити на нить. Для времени, когда нить как бы работает, а на самом деле ждет своей очереди, тоже есть отдельное состояние. Оно называется ready-to-run. Нить во время работы постоянно меняет состояние с running на ready и потом снова на running, когда становится активной.

Сразу после вызова метода start() нить получает статус ready-to-run, и помещается в общий список нитей, между которыми переключается Java-машина.

— Не так уж и сложно. До начала работы – состояние new, после окончания – terminated. А в процессе работы нить находится то в активном (running), то в пассивном (ready) режиме работы.

— Твоя краткость удивляет, но так и есть.

Но и это еще не все. Нить может быть заблокирована. Например, при входе в блок synchronized. Нить подошла к блоку кода, помеченному synchronized, а он занят другой нитью. Тогда наша нить получит состояние blocked и будет ждать освобождения объекта-мютекса.

Вот как выглядит эта ситуация с состояниями:

Thread Life Circle, состояние объекта Thread - 2

Но и это еще не все. Есть еще отдельное состояние, когда нить не blocked, но и не ready – это waiting. Например, при вызове методов join() у другой нити.

При вызове join() у объекта другой нити, наша нить как-бы «присоединяется к ней», а на деле – просто ждет ее завершения.

Кроме того, есть еще метод wait(), (из набора wait, notify, notifyAll), вызов которого тоже переводит нить в состояние waiting.

— Ничего себе.

— Подожди! Но и это еще не все. Нить может спать, например, при вызове метода sleep. Для этого тоже есть отдельное состояние «timed waiting». «timed waiting» значит, что нить чего-то ждет ограниченное время. Если вызвать метод wait с параметром — wait(timeout) или join(timeout), то нить перейдет в состояние timed waiting.

Так что вот тебе полная схема:

Thread Life Circle, состояние объекта Thread - 3

— Гм. Это все? Или там есть еще 10 новых интересных состояний?

— Пока – все.

На самом деле – можешь запомнить только первую схему – она проще. Но вторая точнее.

Как ни странно – в интернете очень много схем состояний Thread и они все разные.

Поэтому я и привела тебе эту схему – она самая полная и правильная.

На этой схеме состояния ready и running объединены в единый блок – runnable, и знаешь почему?

— Нет. Я же в первый раз это все вообще вижу.

— У класса Thread есть внутренний класс State, а также метод public State getState().

Пример
public enum State 
{
 NEW,
 RUNNABLE,
 BLOCKED,
 WAITING,
 TIMED_WAITING,
 TERMINATED;
}

Ты всегда можешь вызвать у объекта типа Thread метод getState() и узнать его текущее состояние. И, конечно, оно будет одним из значений enum State.

— Ясно. То есть настоящие состояния внутри Java-машины, а есть состояния, которые можно получить из Java-кода с помощью метода State getState().

А в каких ситуациях я буду это использовать?

— Скорее всего – в никаких.

Но знать о том, что происходит при работе внутри нити, ты обязан. Иначе на твоем пути будет много ошибок, и ты даже не будешь догадываться об их причине.

Кроме того, состояния Thread очень любят спрашивать на собеседованиях.