Исправьте цикл, который запускает потоки и завершается
Код должен запустить десять потоков, каждый из которых печатает число, и дать им завершиться. Он даже не компилируется, и ещё один дефект остановил бы вывод даже после исправления компиляции. Найдите оба и исправьте.
Ограничения:
- сохраните десять потоков, каждый печатает свой индекс
- программа должна реально дождаться вывода потоков
for (int i = 0; i < 10; i++) {
Thread t = new Thread(() -> {
try { Thread.sleep(200); } catch (InterruptedException ignored) {}
System.out.println(i);
});
t.start();
}
System.exit(0);
Найдите и исправьте ошибки.
Две ошибки. Первая: лямбда захватывает i, но переменная цикла не является effectively final, поэтому код не компилируется — скопируйте её в финальную локальную (final int n = i;) и печатайте n. Вторая: System.exit(0) немедленно завершает JVM, убивая спящие потоки до печати — уберите его (или сначала join каждый поток), чтобы программа дождалась их вывода.
- ✗Думать, что переменная цикла
foreffectively final и её можно захватить напрямую - ✗Упускать, что
System.exit(0)убивает JVM и ещё работающие потоки - ✗Путать исправление с добавлением
volatile, которое решает видимость, а не захват или завершение
- →Почему переменная цикла
forне effectively final, а переменная foreach может быть? - →Как
joinкаждого потока изменит поведение против удаленияSystem.exit?
Исправление
for (int i = 0; i < 10; i++) {
final int n = i; // копия — effectively final для лямбды
Thread t = new Thread(() -> {
try { Thread.sleep(200); } catch (InterruptedException ignored) {}
System.out.println(n);
});
t.start();
}
// System.exit(0); ← убрано: оно убивало спящие потоки до вывода
Ошибка 1 — захват переменной цикла. Лямбда может захватывать только effectively final переменные. i меняется на каждой итерации, поэтому она не effectively final, и код не компилируется. Решение — скопировать значение в новую локальную final int n = i; и использовать n внутри лямбды.
Ошибка 2 — System.exit(0). Даже после исправления компиляции System.exit(0) немедленно завершает JVM. Потоки спят 200 мс и не успевают напечатать число. Уберите вызов — тогда JVM не завершится, пока живы запущенные не-демон потоки. Если нужен детерминированный порядок завершения, вызовите t.join() для каждого потока перед концом main.