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

Можно ли у одного и того же потока вызвать два раза метод start?

1.2 Junior🔥 131 комментариев
#Многопоточность

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

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

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

Двойной вызов start() у потока

Ответ: нет, нельзя. Попытка вызвать start() дважды на одном объекте Thread вызовет IllegalThreadStateException.

Пример: что происходит

Thread thread = new Thread(() -> {
    System.out.println("Thread is running");
});

thread.start();      // Первый вызов - OK
thread.start();      // Второй вызов - ОШИБКА!

// Exception in thread "main": java.lang.IllegalThreadStateException

Почему это происходит

Жизненный цикл потока:

NEW -> RUNNABLE -> RUNNING -> BLOCKED/WAITING -> TERMINATED
      (первый start())

После первого start() поток переходит в состояние RUNNABLE или RUNNING. Второй вызов start() запускает проверку:

public synchronized void start() {
    if (threadStatus != 0)  // Проверка: не был ли уже запущен?
        throw new IllegalThreadStateException();
    
    // ... запуск потока ...
}

threadStatus изменяется:

  • 0 - NEW (только создан)
  • 1 - RUNNABLE (запущен)
  • 2 - TERMINATED (завершен)

Демонстрация

public class ThreadStartDemo {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(() -> {
            System.out.println("Running on: " + Thread.currentThread().getName());
        });
        
        // Первый старт
        thread.start();
        Thread.sleep(100);  // Ждём завершения
        
        // Попытка второго старта
        try {
            thread.start();
        } catch (IllegalThreadStateException e) {
            System.out.println("ОШИБКА: " + e.getMessage());
            // Exception: Thread already started
        }
    }
}

Состояния потока (Java Thread States)

Thread.State состояния:

1. NEW - потоку еще не вызывали start()
   - Только созданный объект Thread
   - thread.getState() == Thread.State.NEW

2. RUNNABLE - поток запущен (или готов к запуску)
   - После вызова start()
   - thread.getState() == Thread.State.RUNNABLE

3. BLOCKED - поток ждет блокировки (synchronized)
   - Ждет получения монитора
   
4. WAITING - поток в ожидании
   - wait(), join(), park()
   
5. TIMED_WAITING - ожидание с таймаутом
   - sleep(long), wait(long), join(long)
   
6. TERMINATED - поток завершен
   - Вышел из run()
   - thread.getState() == Thread.State.TERMINATED

Проверка состояния перед стартом

public class SafeThreadStart {
    
    public static void startThreadSafely(Thread thread) {
        if (thread.getState() == Thread.State.NEW) {
            thread.start();
            System.out.println("Thread started successfully");
        } else {
            System.out.println("Thread cannot be started, state: " + thread.getState());
        }
    }
    
    public static void main(String[] args) {
        Thread thread = new Thread(() -> {
            System.out.println("Work");
        });
        
        startThreadSafely(thread);  // OK
        startThreadSafely(thread);  // Выведет: "Thread cannot be started"
    }
}

Частые ошибки

Ошибка 1: Переиспользование Thread

// ❌ НЕПРАВИЛЬНО
Thread worker = new Thread(() -> doWork());
worker.start();

// Позже в коде
worker.start();  // IllegalThreadStateException!

Ошибка 2: Перезапуск в цикле

// ❌ НЕПРАВИЛЬНО
Thread thread = new Thread(longRunningTask);

for (int i = 0; i < 10; i++) {
    thread.start();  // Упадет при i >= 1
    Thread.sleep(1000);
}

// ✅ ПРАВИЛЬНО
for (int i = 0; i < 10; i++) {
    Thread thread = new Thread(longRunningTask);  // Новый поток каждый раз
    thread.start();
    Thread.sleep(1000);
}

Ошибка 3: Забыли про ExecutorService

// ❌ НЕПРАВИЛЬНО - создаём новые потоки вручную
for (Task task : tasks) {
    Thread t = new Thread(task);
    t.start();
    // Возможны утечки, нет контроля над потоками
}

// ✅ ПРАВИЛЬНО - используем пул потоков
ExecutorService executor = Executors.newFixedThreadPool(5);
for (Task task : tasks) {
    executor.submit(task);  // ExecutorService переиспользует потоки
}
executor.shutdown();

Правильный подход: ExecutorService

Если нужно запускать задачи многократно - используй ExecutorService:

public class ProperThreadManagement {
    
    public static void main(String[] args) throws InterruptedException {
        
        // Пул из 3 потоков
        ExecutorService executor = Executors.newFixedThreadPool(3);
        
        // Запускаем 10 задач
        for (int i = 0; i < 10; i++) {
            final int taskId = i;
            executor.submit(() -> {
                System.out.println("Task " + taskId + " on " + 
                    Thread.currentThread().getName());
            });
        }
        
        executor.shutdown();  // Проводим graceful shutdown
        executor.awaitTermination(10, TimeUnit.SECONDS);
    }
}

Что делать, если нужно перезапустить логику

Вариант 1: Новый поток каждый раз

public class RestartableTask {
    
    private final Runnable task;
    
    public RestartableTask(Runnable task) {
        this.task = task;
    }
    
    public Thread runAsync() {
        Thread t = new Thread(task);
        t.start();
        return t;
    }
    
    public static void main(String[] args) throws InterruptedException {
        RestartableTask task = new RestartableTask(() -> {
            System.out.println("Doing work...");
        });
        
        // Каждый раз создаём новый поток
        task.runAsync();
        Thread.sleep(100);
        task.runAsync();  // OK
        Thread.sleep(100);
        task.runAsync();  // OK
    }
}

Вариант 2: ExecutorService (рекомендуется)

public class BetterRestartableTask {
    
    private final ExecutorService executor = 
        Executors.newSingleThreadExecutor();
    
    private final Runnable task;
    
    public BetterRestartableTask(Runnable task) {
        this.task = task;
    }
    
    public void runAsync() {
        executor.submit(task);  // Переиспользует поток
    }
    
    public void shutdown() {
        executor.shutdown();
    }
}

Итоговый контрольный список

Можно ли вызвать start() дважды?

  • Нет - вызовется IllegalThreadStateException

Почему?

  • Thread имеет состояние (NEW, RUNNABLE, TERMINATED)
  • После первого start() состояние != NEW
  • Вторая попытка start() отклоняется

Как правильно запускать задачи многократно?

  • ✅ ExecutorService с переиспользованием потоков
  • ✅ Создавать новый Thread для каждой задачи
  • ✅ Использовать Thread Pool паттерны