JavaRush /Курсы /JAVA 25 SELF /Разбор типичных ошибок при работе с процессами

Разбор типичных ошибок при работе с процессами

JAVA 25 SELF
61 уровень , 4 лекция
Открыта

1. Deadlock при чтении/записи потоков

Одна из самых неприятных ошибок — когда процесс зависает и не завершается, хотя кажется, что всё сделано правильно. Частая причина — переполнение буфера вывода или ошибок внешнего процесса. Если не читать оба потока (stdout и stderr), процесс может «заблокироваться» при попытке что-то вывести, потому что никто не забирает данные из его буфера.

Пример беды

ProcessBuilder builder = new ProcessBuilder("java", "-version");
Process process = builder.start();
// Читаем только stdout, а stderr игнорируем!
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
    System.out.println(line);
}
process.waitFor();

Если команда пишет что-то в stderr (например, java -version почти всегда пишет туда!), этот поток переполняется, и процесс зависает.

Как правильно

Читайте оба потока параллельно (через отдельные потоки или ExecutorService):

ProcessBuilder builder = new ProcessBuilder("java", "-version");
Process process = builder.start();

// Читаем stdout
Thread stdoutThread = new Thread(() -> {
    try (BufferedReader reader = new BufferedReader(
            new InputStreamReader(process.getInputStream()))) {
        String line;
        while ((line = reader.readLine()) != null) {
            System.out.println("[stdout] " + line);
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
});

// Читаем stderr
Thread stderrThread = new Thread(() -> {
    try (BufferedReader reader = new BufferedReader(
            new InputStreamReader(process.getErrorStream()))) {
        String line;
        while ((line = reader.readLine()) != null) {
            System.err.println("[stderr] " + line);
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
});

stdoutThread.start();
stderrThread.start();

process.waitFor();
stdoutThread.join();
stderrThread.join();

Вывод:
Если не читать stderr — процесс может зависнуть.
Если не читать stdout — тоже может зависнуть.
Читай оба потока — и будет тебе счастье!

2. Проблемы с кодировкой

Внешние процессы могут использовать другую кодировку для вывода текста, чем ваша Java‑программа по умолчанию. Если не указать правильную кодировку, получите «кракозябры» вместо текста (особенно заметно с кириллицей).

Пример ошибки

BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));

Этот код использует системную кодировку по умолчанию. Но если внешний процесс пишет, например, в UTF-8, а у вас Windows-1251, кириллица превратится в абракадабру.

Как правильно

Передавайте явно нужную кодировку, если знаете её:

BufferedReader reader = new BufferedReader(
    new InputStreamReader(process.getInputStream(), StandardCharsets.UTF_8)
);

Если не уверены — изучите документацию к программе или попробуйте несколько вариантов.

Лайфхак: на Windows консольные утилиты часто используют CP866 или Windows-1251, а на Linux — UTF-8.

3. Платформенные различия

Команды, работающие на одной ОС, могут отсутствовать в другой. Например, ls есть на Linux/Mac, но не на Windows (там — dir). Отличаются синтаксис команд, разделители путей и кавычки.

Пример ошибки

ProcessBuilder builder = new ProcessBuilder("ls", "-l");
builder.start(); // На Windows: "ls" не найдена!

Как правильно

String os = System.getProperty("os.name").toLowerCase();
ProcessBuilder builder;
if (os.contains("win")) {
    builder = new ProcessBuilder("cmd", "/c", "dir");
} else {
    builder = new ProcessBuilder("ls", "-l");
}

Путь к файлам: используйте File.separator вместо «/» или «\», чтобы не попасть впросак с путями.

4. Проблемы с правами доступа

Некоторые команды требуют прав администратора (удаление системных файлов, изменение сетевых настроек и т. п.). При недостатке прав команда завершится с ошибкой или вовсе не запустится.

Пример

ProcessBuilder builder = new ProcessBuilder("rm", "-rf", "/root/secret.txt");
Process process = builder.start();
// ... ждём ошибку Permission denied

Как правильно

  • Проверяйте, нужны ли повышенные права для вашей команды.
  • Обрабатывайте код возврата процесса через process.exitValue().
  • Читайте stderr — там чаще всего есть причина ошибки (например, «Permission denied»).

5. Утечки ресурсов

Если не закрывать потоки процесса (InputStream, OutputStream, ErrorStream), они могут «висеть», занимать ресурсы и даже блокировать завершение. Аналогично, если не завершить сам процесс, он может стать «зомби» в системе.

Пример ошибки

Process process = builder.start();
// ... работаем, но не закрываем потоки!

Как правильно

Используйте try-with-resources для потоков:

try (BufferedReader reader = new BufferedReader(
         new InputStreamReader(process.getInputStream()))) {
    // Читаем вывод
}

После завершения работы с процессом корректно его останавливайте:

process.destroy(); // Завершить процесс (если он ещё жив)

Внимание: если не закрыть потоки — возможны утечки памяти, зависания и системные проблемы (особенно при массовом запуске процессов).

6. Deadlock при интерактивном взаимодействии

При интерактивном обмене легко попасть в ситуацию взаимной блокировки: Java ждёт ответ, а внешний процесс — ваших данных. В итоге оба «молчат». Или вы отправили сообщение, но не читаете ответ — в какой-то момент у внешней программы переполняется буфер, и она останавливает запись.

Чтобы этого избежать, разделяйте обязанности: один поток отвечает за чтение, другой — за запись. Тогда взаимодействие идёт параллельно, и никто никого не держит. Также не оставляйте открытые потоки после завершения — закройте их, чтобы система не держала лишние ресурсы.

1
Задача
JAVA 25 SELF, 61 уровень, 4 лекция
Недоступна
Проникновение в Защищенную Зону 🚫
Проникновение в Защищенную Зону 🚫
1
Задача
JAVA 25 SELF, 61 уровень, 4 лекция
Недоступна
Всевидящее Око Детектива 🕵️
Всевидящее Око Детектива 🕵️
1
Опрос
Работа с процессами, 61 уровень, 4 лекция
Недоступен
Работа с процессами
Работа с процессами
Комментарии
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ