← Назад к вопросам

Какие знаешь статусы потока в Java?

2.0 Middle🔥 181 комментариев
#Многопоточность#Основы Java

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Статусы потока (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(финальное)

Лучшие практики:

  1. Избегай бесконечного BLOCKED — используй таймауты
  2. Используй TIMED_WAITING вместо бесконечного WAITING
  3. Правильно обрабатывай InterruptedException
  4. Используй новые API (CompletableFuture, Executors) вместо низкоуровневого управления потоками
  5. Мониторь состояния потоков при отладке deadlock'ов
Какие знаешь статусы потока в Java? | PrepBro