← Назад к вопросам
Можно ли у одного и того же потока вызвать два раза метод 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 паттерны