Какие знаешь статусы потока в Java?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Статусы потока (Thread States) в Java
Поток в Java может находиться в одном из шести состояний на протяжении своего жизненного цикла. Понимание этих состояний критично для написания правильного многопоточного кода и отладки проблем с deadlock'ами и зависаниями.
Шесть состояний потока
1. NEW (Новый)
Поток создан, но ещё не запущен.
Thread thread = new Thread(() -> {
System.out.println("Running");
});
// Статус: NEW
System.out.println(thread.getState()); // NEW
// Поток всё ещё в состоянии NEW
System.out.println("Thread is still " + thread.getState()); // NEW
Характеристики:
- Объект Thread создан
- Код потока не начинал выполняться
- Операционная система не знает об этом потоке
- Единственный способ выйти из NEW — вызвать
start()
Пример:
Thread t = new Thread(() -> System.out.println("Hello"));
System.out.println(t.getState()); // NEW
t.start();
// Теперь t не в NEW
2. RUNNABLE (Готов к выполнению)
Поток запущен и готов к выполнению, или в процессе выполнения.
Thread thread = new Thread(() -> {
System.out.println("I'm running");
});
thread.start();
// Поток может быть в RUNNABLE даже если он в этот момент
// выполняется на процессоре
System.out.println(thread.getState()); // RUNNABLE (обычно)
Характеристики:
- Поток вызвал
start() - JVM создал поток и OS распланировал его
- Поток либо выполняется на процессоре, либо ждёт времени процессора
- В Java нет разделения между "Running" и "Ready"
Переход в RUNNABLE:
Thread t = new Thread(() -> System.out.println("Hello"));
t.start(); // Переход: NEW → RUNNABLE
Пример с мониторингом:
public class ThreadStateExample {
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(() -> {
for (int i = 0; i < 1000000; i++) {
// Долгая работа
}
});
t.start();
while (t.isAlive()) {
System.out.println("Thread state: " + t.getState()); // Обычно RUNNABLE
Thread.sleep(100);
}
}
}
3. BLOCKED (Заблокирован)
Поток ждёт монитора (synchronized lock) для входа в synchronized блок.
public class BlockedExample {
private static final Object lock = new Object();
public static void main(String[] args) {
// Поток 1 захватит lock
Thread t1 = new Thread(() -> {
synchronized (lock) {
System.out.println("T1 has lock");
try {
Thread.sleep(5000); // Держит lock 5 секунд
} catch (InterruptedException e) {}
}
});
// Поток 2 попытается захватить lock
Thread t2 = new Thread(() -> {
System.out.println("T2 trying to get lock");
synchronized (lock) {
System.out.println("T2 has lock");
}
});
t1.start();
t2.start();
try {
Thread.sleep(100); // Дать t1 время захватить lock
} catch (InterruptedException e) {}
// t2 находится в BLOCKED, ждёт lock'а
System.out.println("T2 state: " + t2.getState()); // BLOCKED
}
}
Характеристики:
- Поток попытался войти в synchronized блок, но lock занят
- Поток ждёт, пока текущий owner отпустит lock
- Поток НЕ может выполняться на процессоре
- Отпускает только при успешном захвате lock'а
Важно:
- BLOCKED — это только для synchronized
- ReentrantLock, обычно переводит в WAITING
4. WAITING (Ожидание)
Поток ждёт пока другой поток выполнит конкретное действие.
public class WaitingExample {
private static final Object lock = new Object();
public static void main(String[] args) throws InterruptedException {
// Поток 1
Thread t1 = new Thread(() -> {
synchronized (lock) {
try {
System.out.println("T1 is waiting");
lock.wait(); // Отпускает lock и ждёт
System.out.println("T1 was notified");
} catch (InterruptedException e) {}
}
});
// Поток 2
Thread t2 = new Thread(() -> {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {}
synchronized (lock) {
System.out.println("T2 notifying");
lock.notify(); // Пробудить одного из ждущих
}
});
t1.start();
t2.start();
try {
Thread.sleep(500);
} catch (InterruptedException e) {}
// t1 находится в WAITING
System.out.println("T1 state: " + t1.getState()); // WAITING
}
}
Методы, переводящие в WAITING:
// 1. Object.wait() без параметров
object.wait();
// 2. Thread.join() без таймаута
thread.join();
// 3. LockSupport.park()
LockSupport.park();
Характеристики:
- Поток вызвал
wait(),join()илиLockSupport.park() - Поток отпустил lock
- Ждёт другого потока, который вызовет
notify()илиnotifyAll() - Поток НЕ может выполняться на процессоре
5. TIMED_WAITING (Ожидание с таймаутом)
Поток ждёт, но с указанным таймаутом.
public class TimedWaitingExample {
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(() -> {
try {
System.out.println("Going to sleep for 5 seconds");
Thread.sleep(5000); // TIMED_WAITING
System.out.println("Woke up");
} catch (InterruptedException e) {
System.out.println("Interrupted");
}
});
t.start();
try {
Thread.sleep(100);
} catch (InterruptedException e) {}
// t находится в TIMED_WAITING
System.out.println("T state: " + t.getState()); // TIMED_WAITING
}
}
Методы, переводящие в TIMED_WAITING:
// 1. Thread.sleep(long millis)
Thread.sleep(5000);
// 2. Object.wait(long timeout)
object.wait(5000);
// 3. Thread.join(long millis)
thread.join(5000);
// 4. LockSupport.parkNanos() или parkUntil()
LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(5));
// 5. BlockingQueue.poll(long timeout)
queue.poll(5, TimeUnit.SECONDS);
// 6. Condition.await(long time, TimeUnit unit)
condition.await(5, TimeUnit.SECONDS);
Характеристики:
- Поток ждёт, но с максимальным временем ожидания
- Автоматически переходит в RUNNABLE по истечении таймаута
- Может быть пробужден раньше (через
notify()или interrupt) - Полезно для предотвращения бесконечного ожидания
6. TERMINATED (Завершено)
Поток закончил выполнение и больше не существует.
public class TerminatedExample {
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(() -> {
System.out.println("Running");
});
System.out.println("Before start: " + t.getState()); // NEW
t.start();
System.out.println("After start: " + t.getState()); // RUNNABLE
t.join(); // Ждать завершения потока
System.out.println("After join: " + t.getState()); // TERMINATED
}
}
Характеристики:
- Метод
run()завершился (нормально или с исключением) - Поток больше не может быть запущен
- Вызов
start()на завершённом потоке вызываетIllegalThreadStateException - Невозможно переходить в другие состояния из TERMINATED
Диаграмма переходов
NEW
|
| start()
v
RUNNABLE <-------- (scheduler переводит туда)
| ^
| | notify()
| | notifyAll()
| | park() completed
| | interrupt()
| |
WAITING/TIMED_WAITING
| (wait(), sleep(), join(),
| park(), parkNanos())
|
| (внутри synchronized блока)
v
BLOCKED
|
| захватил lock
v
RUNNABLE
|
| run() завершился
v
TERMINATED
Практический пример всех состояний
public class AllThreadStates {
static class StateMonitor {
void printState(Thread t, String desc) {
System.out.printf("%s: %s%n", desc, t.getState());
}
}
public static void main(String[] args) throws InterruptedException {
StateMonitor monitor = new StateMonitor();
// 1. NEW
Thread t = new Thread(() -> {
// 2. RUNNABLE (когда выполняется)
try {
// 3. TIMED_WAITING
Thread.sleep(100);
// 4. WAITING
synchronized (AllThreadStates.class) {
AllThreadStates.class.wait(1000);
}
} catch (InterruptedException e) {}
});
monitor.printState(t, "1. После создания"); // NEW
t.start();
monitor.printState(t, "2. После start()"); // RUNNABLE
Thread.sleep(50);
monitor.printState(t, "3. Во время sleep()"); // TIMED_WAITING
t.join();
monitor.printState(t, "4. После завершения"); // TERMINATED
}
}
Важные моменты
BLOCKED vs WAITING:
// BLOCKED: ждёт synchronized lock
synchronized (lock) { // Если lock занят → BLOCKED
// код
}
// WAITING: вызвал wait() и отпустил lock
synchronized (lock) {
lock.wait(); // → WAITING
}
// Разница: BLOCKED всё ещё держит захват,
// WAITING отпустил и ждёт пробуждения
Не путай состояния с alive/dead:
boolean isAlive = thread.isAlive();
// true если в RUNNABLE, BLOCKED, WAITING, TIMED_WAITING
// false если в NEW или TERMINATED
Thread.State state = thread.getState();
// Точное состояние из 6 вариантов
Interrupt и состояния:
// Если поток в WAITING/TIMED_WAITING → InterruptedException
Thread t = new Thread(() -> {
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
System.out.println("Interrupted!");
}
});
t.start();
Thread.sleep(100);
t.interrupt(); // Вызовет InterruptedException в sleep()
Мониторинг потоков:
public class ThreadMonitor {
public static void printThreadInfo(Thread t) {
System.out.printf(
"Thread: %s\n" +
" State: %s\n" +
" Is Alive: %s\n" +
" Priority: %d\n" +
" Daemon: %s\n",
t.getName(),
t.getState(),
t.isAlive(),
t.getPriority(),
t.isDaemon()
);
}
}
Итог
| Состояние | Описание | Переход | Выход |
|---|---|---|---|
| NEW | Создан, не запущен | start() | → RUNNABLE |
| RUNNABLE | Готов или выполняется | start() | → BLOCKED/WAITING/TIMED_WAITING/TERMINATED |
| BLOCKED | Ждёт synchronized | В sync блоке | → RUNNABLE (захватил lock) |
| WAITING | Ждёт пробуждения | wait(), join() | → RUNNABLE (notify/join) |
| TIMED_WAITING | Ждёт с таймаутом | sleep(), wait(t) | → RUNNABLE (timeout/notify) |
| TERMINATED | Завершено | run() finished | (финальное) |
Лучшие практики:
- Избегай бесконечного BLOCKED — используй таймауты
- Используй TIMED_WAITING вместо бесконечного WAITING
- Правильно обрабатывай InterruptedException
- Используй новые API (CompletableFuture, Executors) вместо низкоуровневого управления потоками
- Мониторь состояния потоков при отладке deadlock'ов