CodeGym /Cursos /JAVA 25 SELF /Análise de erros típicos ao trabalhar com processos

Análise de erros típicos ao trabalhar com processos

JAVA 25 SELF
Nível 61 , Lição 4
Disponível

1. Deadlock ao ler/gravar fluxos

Um dos problemas mais desagradáveis é quando o processo trava e não termina, embora pareça que tudo está certo. Uma causa comum é o estouro do buffer de saída ou de erros do processo externo. Se você não ler ambos os fluxos (stdout e stderr), o processo pode “ficar bloqueado” ao tentar imprimir algo, porque ninguém está esvaziando o buffer dele.

Exemplo do problema

ProcessBuilder builder = new ProcessBuilder("java", "-version");
Process process = builder.start();
// Lemos apenas stdout e ignoramos stderr!
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
    System.out.println(line);
}
process.waitFor();

Se o comando escrever algo em stderr (por exemplo, java -version quase sempre escreve lá!), esse fluxo enche e o processo trava.

Como fazer corretamente

Leia ambos os fluxos em paralelo (com threads separadas ou ExecutorService):

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

// Lemos 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();
    }
});

// Lemos 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();

Conclusão:
Se você não ler stderr — o processo pode travar.
Se você não ler stdout — ele também pode travar.
Leia ambos os fluxos — e tudo ficará bem!

2. Problemas de codificação de caracteres

Processos externos podem usar uma codificação diferente para a saída de texto do que a padrão da sua aplicação Java. Se não indicar a codificação correta, você verá caracteres ilegíveis em vez de texto (isso é especialmente perceptível com caracteres cirílicos).

Exemplo de erro

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

Esse código utiliza a codificação padrão do sistema. Mas se o processo externo escrever, por exemplo, em UTF-8, e o seu estiver em Windows-1251, o texto em cirílico vira uma bagunça.

Como fazer corretamente

Informe explicitamente a codificação necessária, se você a souber:

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

Se não tiver certeza — consulte a documentação do programa ou experimente algumas opções.

Dica: no Windows, utilitários de console frequentemente usam CP866 ou Windows-1251, e no Linux — UTF-8.

3. Diferenças entre plataformas

Comandos que funcionam em um sistema operacional podem não existir em outro. Por exemplo, ls existe no Linux/Mac, mas não no Windows (lá — dir). Também diferem a sintaxe dos comandos, os separadores de caminho e as aspas.

Exemplo de erro

ProcessBuilder builder = new ProcessBuilder("ls", "-l");
builder.start(); // No Windows: "ls" não encontrado!

Como fazer corretamente

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");
}

Caminho para arquivos: use File.separator em vez de “/” ou “\” para não ter problemas com caminhos.

4. Problemas de permissão

Alguns comandos exigem privilégios de administrador (exclusão de arquivos do sistema, alteração de configurações de rede etc.). Sem permissões suficientes, o comando terminará com erro ou nem será iniciado.

Exemplo

ProcessBuilder builder = new ProcessBuilder("rm", "-rf", "/root/secret.txt");
Process process = builder.start();
// ... aguardando erro Permission denied

Como fazer corretamente

  • Verifique se o seu comando exige privilégios elevados.
  • Trate o código de retorno do processo via process.exitValue().
  • Leia o stderr — ali costuma estar a causa do erro (por exemplo, “Permission denied”).

5. Vazamentos de recursos

Se você não fechar os fluxos do processo (InputStream, OutputStream, ErrorStream), eles podem “ficar pendurados”, consumir recursos e até bloquear o encerramento. Da mesma forma, se você não encerrar o próprio processo, ele pode virar um “zumbi” no sistema.

Exemplo de erro

Process process = builder.start();
// ... trabalhamos, mas não fechamos os fluxos!

Como fazer corretamente

Use try-with-resources para os fluxos:

try (BufferedReader reader = new BufferedReader(
         new InputStreamReader(process.getInputStream()))) {
    // Lemos a saída
}

Depois de terminar o trabalho com o processo, finalize-o corretamente:

process.destroy(); // Encerrar o processo (se ainda estiver vivo)

Atenção: se você não fechar os fluxos — podem ocorrer vazamentos de memória, travamentos e problemas no sistema (especialmente ao iniciar muitos processos).

6. Deadlock na comunicação interativa

Em uma troca interativa é fácil cair em bloqueio mútuo: a aplicação Java espera uma resposta, e o processo externo — seus dados. No fim, ambos “ficam em silêncio”. Ou você enviou uma mensagem, mas não lê a resposta — em algum momento o buffer do programa externo enche e ele para de escrever.

Para evitar isso, separe as responsabilidades: uma thread cuida da leitura e outra da escrita. Assim, a interação ocorre em paralelo e ninguém bloqueia ninguém. Também não deixe fluxos abertos após o término — feche-os para que o sistema não retenha recursos desnecessários.

1
Tarefa
JAVA 25 SELF, nível 61, lição 4
Bloqueado
Intrusão na Zona Protegida 🚫
Intrusão na Zona Protegida 🚫
1
Tarefa
JAVA 25 SELF, nível 61, lição 4
Bloqueado
O Olho Onisciente do Detetive 🕵️
O Olho Onisciente do Detetive 🕵️
1
Pesquisa/teste
Trabalho com processos, nível 61, lição 4
Indisponível
Trabalho com processos
Trabalho com processos
Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION