É possível eliminar uma máquina virtual Java de outra máquina virtual?
-
09-06-2019 - |
Pergunta
Tenho um aplicativo Java que inicia outro aplicativo Java.O iniciador possui um temporizador de watchdog e recebe notificações periódicas da segunda VM.No entanto, se nenhuma notificação for recebida, a segunda máquina virtual deverá ser encerrada e o inicializador executará algumas atividades de limpeza adicionais.
A questão é: existe alguma maneira de fazer isso usando apenas java?até agora tenho que usar alguns métodos nativos para realizar esta operação e é um tanto feio.
Obrigado!
Solução
Posso estar faltando alguma coisa, mas você não pode ligar para o destroy()
método no Process
objeto retornado por Runtime.exec()
?
Outras dicas
Você pode usar java.lang.Process para fazer o que quiser.Depois de criar o processo aninhado e ter uma referência à instância do Processo, você poderá obter referências aos seus fluxos de saída e erro padrão.Você pode monitorá-los periodicamente e chamar .destroy() se quiser encerrar o processo.A coisa toda pode ser mais ou menos assim:
Process nestedProcess = new ProcessBuilder("java mysubprocess").start();
InputStream nestedStdOut = nestedProcess.getInputStream(); //kinda backwards, I know
InputStream nestedStdErr = nestedProcess.getErrorStream();
while (true) {
/*
TODO: read from the std out or std err (or get notifications some other way)
Then put the real "kill-me" logic here instead of if (false)
*/
if (false) {
nestedProcess.destroy();
//perform post-destruction cleanup here
return;
}
Thread.currentThread().sleep(1000L); //wait for a bit
}
Espero que isto ajude,
Sean
Você também pode publicar um serviço (via serapilheira, hessian, etc) na segunda JVM que chama System.exit() e consumi-lo da JVM watchdog.Se você desejar apenas encerrar a segunda JVM quando ela parar de enviar essas notificações periódicas, ela poderá não estar em condições de responder à chamada de serviço.
Chamar comandos shell com java.lang.Runtime.exec() é provavelmente sua melhor aposta.
A maneira usual de fazer isso é chamar Process.destroy()...no entanto, é uma solução incompleta, pois ao usar a JVM sun em *nix destroy mapeia para um SIGTERM que não garante o encerramento do processo (para isso você também precisa do SIGKILL).O resultado líquido é que você não pode fazer gerenciamento de processos reais usando Java.
Existem alguns bugs abertos sobre esse problema, consulte:Texto do link
java.lang.Process tem um método waitFor() para aguardar a morte de um processo e um método destroy() para encerrar o subprocesso.
OK, a reviravolta da essência é a seguinte:
Eu estava usando a API Process para fechar a segunda máquina virtual, mas não funcionou.
O motivo é que meu segundo aplicativo é um aplicativo Eclipse RCP e eu o iniciei usando o inicializador eclipse.exe incluído.
No entanto, isso significa que o método destroy() da API do processo terá como alvo o processo eclipse.exe.Eliminar esse processo deixa o processo Java ileso.Então, um dos meus colegas aqui escreveu um pequeno aplicativo que eliminará o aplicativo certo.
Portanto, uma das soluções para usar a API de processo (e remover etapas intermediárias redundantes) é usar o inicializador Eclipse, fazendo com que minha primeira máquina virtual duplique todas as suas funcionalidades.
Acho que terei que trabalhar.
Você deve ser capaz de executar os comandos java.lang.Runtime.exec e shell.
Você pode fazer com que o código java detecte a plataforma em tempo de execução e acione o comando kill process da plataforma.Este é realmente um refinamento em sua solução atual.
Há também Processo.destruir(), se você estiver usando o Construtor de Processos API
Não é exatamente gerenciamento de processos, mas você pode iniciar um servidor rmi na máquina virtual java que está iniciando e vincular um controlo remoto instância com um método que faz qualquer limpeza necessária e chama System.exit().A primeira VM poderia então chamar esse método remoto para desligar a segunda VM.