Impedir nova execução se já estiver rodando [Resolvido]

20 respostas
S

Boa noite a todos!

Tenho esta dúvida: Como impedir uma nova execução do aplicativo que já está rodando? (ou seja, ao invés de rodar um novo, ele retorna o que já está em execução)

Grato pela ajuda!

20 Respostas

B

Bom, eu não sei exatamente sobre como retornar o que já está em execução. Porém conheço duas estratégias que utilizam para evitar duas instancias de um mesmo programa de rodar ao mesmo tempo.

A primeira é manter um arquivo locked para a aplicação, ao tentar rodar ou instancia e tentar dar o lock ele vai se deparar com um problema e assumir que já há uma instancia rodando. Essa eu sei que tem alguns problemas, não me lembro exatamente qual.

A outra é utilizar um socket para a instancia, e funciona de forma semelhante, ao tentar rodar outra instancia é verificado que o socket já está ocupado.

Algo que achei e que parece retornar a instancia que está rodando ao tentar executar outra:

http://www.rbgrn.net/content/43-java-single-application-instance

Não cheguei a testar, mas estava num fórum americano que confio bastante…

Valeu

A

Com Java não sei se é possível ver se um determinado programa está em execução, mas com C, usando a API do Windows, com toda certeza você consegue implementar algo. Você pode criar uma DLL em C que faça esta verificação, e usa-la com Java. Ou, se preferir, você pode fazer uma gambiarra. Ao abrir seu programa, você cria um arquivo cujo conteúdo é 1. Ao fechar, você apaga todo o conteúdo deste arquivo, e escreve 0 nele. Assim, sempre ao abrir seu programa, faça a leitura verifique o conteúdo deste arquivo. Se for 1, é porque já têm uma instância aberta, se for 0, não está aberto e você pode abrir normalmente. Só que como eu disse, é uma típica gambiarra, não recomendo que o faça.

S

valeu gente!

vou dar uma estudada neste assunto…

A

tem uma boa solucao do luca com sockets… pesquise aqui…

J

Você pode utilizar os parametros de inicialização da JVM, conforme abaixo:

-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.port=6676

Com isso só será possível um único processo utilizando a porta 6676…

S

oi joão!

eu coloco este código em qual parte do meu aplicativo?

J

Olá SandroSoftwares, blz?

Você pode adicionar estas informações no .bat ou .sh que inicia sua app…

java -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.port=6676 -cp $CLASS_PATH -jar RoboTeste.jar

Sua aplicação é um processo batch (robô) ??

S

cara, minha aplicação é um software de cadastro… eu não tenho um bat que inicia… pode me explicar melhor?

J

Se sua aplicação é Java, você pode utilizar a lista de parametros apresentada pelo link abaixo no momento da inicializção da JVM onde seu aplicativo irá ser executado.

http://blogs.oracle.com/watt/resource/jvm-options-list.html

V
  1. Abra um ServerSocket numa porta qualquer;
  2. Se o Socket não abrir, dê o erro e saia da aplicação.

Essa solução funciona bem, pois somente um único socket pode estar aberto numa porta por vez.

A

ViniGodoy:
1. Abra um ServerSocket numa porta qualquer;
2. Se o Socket não abrir, dê o erro e saia da aplicação.

Essa solução funciona bem, pois somente um único socket pode estar aberto numa porta por vez.

Exato! Era esta a solução do luca

P

ViniGodoy:
1. Abra um ServerSocket numa porta qualquer;
2. Se o Socket não abrir, dê o erro e saia da aplicação.

Essa solução funciona bem, pois somente um único socket pode estar aberto numa porta por vez.

Poderia exemplificar com código?

V

Nossa, precisava mesmo?

Declare seu serversocket como:

private static ServerSocket s;
try {
    s = new ServerSocket(9581);
} catch (Exception e) {
    JOptionPane.showMessageDialog(null, "Desculpe, mas só uma aplicação pode ser executada por vez.");
}

E não esqueça de fazer “close” no socket antes de fechar a aplicação.

T

ViniGodoy:
1. Abra um ServerSocket numa porta qualquer;
2. Se o Socket não abrir, dê o erro e saia da aplicação.

Essa solução funciona bem, pois somente um único socket pode estar aberto numa porta por vez.

Realmente funciona legal, também usamos esta idéia em nossos sistemas =)

L

Só quero adicionar uma observação. O brunoskrebs sugeriu você utilizar um arquivo de lock, e isso para mim é a melhor solução.

O eclipse gerencia o uso dos workspaces através de lock files (arquivo .lock dentro do diretório .metadata). Esse é o jeito que a maioria dos processos em unix também utilizam para evitar o processo repetido.

O problema disso é o programa terminar sem “limpar” o arquivo de lock. Isso vai causar o arquivo de lock ficar lá “sozinho” e vai parecer que você tem alguma instância executando, quando na verdade, não tem. A resolução disso é perguntar ao usuário se ele vê alguma outra instância executando e perguntar o que fazer com isso: sair da aplicação ou “roubar” o lock para si. O método de socket também tem problemas: se você não fechar o socket “direito” ou dependendo de como abre, ele pode ficar em “closeWait” e ocupar a porta quando você for abrir de novo logo em seguida.

Se for útil, eu posto depois um código-exemplo de como fazer isso, mas deve ser simples mesmo:

File lockFile = new File(".lock");
if (lockFile.exists()) {
  //perguntar para o usuario se rouba o lock ou não
  if (!roubar) {
     throw new IllegalStateException("Instância em execução");
  }
}
lockFile.deleteOnExit();
//segue a vida
V

Você pode evitar esse estado do socket chamando:

seuSocket.setReuseAddr(true);

http://download.oracle.com/javase/1.5.0/docs/api/java/net/ServerSocket.html#setReuseAddress(boolean)

O problema é do arquivo de lock é que alguns SOs mais antigos podem deixar o arquivo travado até que o computador seja reiniciado. Eu não me preocuparia com isso hoje em dia, mas era bastante chato na época do Windows 98.

L

Não quis dizer usar File.lock(). Só a existência do arquivo seria a trava. Usar File.lock() realmente é problemático e não deveria ser utilizado para isso/não tem para quê. Minha sugestão é só usar a existência do arquivo. Usando o .deleteOnExit(), a VM limpa o arquivo quando o programa terminar “bonito”.

V

Nesse caso nada garante que o usuário não irá abrir uma nova instância. Ele pode sozinho apagar o outro arquivo do disco ou, no código que você sugeriu, responder “sim” e abrir a segunda instância por conta própria.

Acho que tudo depende do quanto você confie no usuário, e o quão importante é impedir duas instâncias de abrirem simultaneamente.

S

rsrsrs… pra mim também precisava! mas agora tá rodando legal!

Inclusive ViniGodoy eu coloquei a chamada dentro do metodo main e o resultado é o seguinte:

Ele dá a mensagem quando tento executar simultaneamente…
mas eu não precisei colocar o “close” para fechar… (quando fecho o programa no X, automaticamente já me parece que o close é feito…)

Valeu mesmo!

T

Valeu a dica.
O único cuidado seria em relação a codificação da porta.
Funcionou perfeitamente.

Criado 28 de maio de 2011
Ultima resposta 30 de out. de 2014
Respostas 20
Participantes 10