Sabemos que o Java usa o javaw.exe para executar as aplicações do JavaSwing. Eu tenho 4 aplicações JavaSwing rodando na rede. Todas possuem uma verificação de múltiplas instâncias funcionando perfeitamente. O problema acontece agora:
Abro a aplicação “A” sem problemas;
Ao tentar abrir as aplicações B, C ou D o aviso de instância já em execução é exibida.
O que posso fazer para o javaw.exe fazer distinção das aplicações que já estão abertas?
Vc está abrindo alguma porta TCP/UDP nessa sua aplicação?
fabioklopes
Não … aplicações puras … apenas conexões com MySQL.
Lucas_Camara
Acho que vai depender da forma como essa verificação está sendo feita. Ela está se baseando no nome do processo, certo?
fabioklopes
Sim, uma verificação bem simples… Veja:
publicvoidverificaProcesso(){Stringline;intinstances=0;try{Processprocesso=Runtime.getRuntime().exec("wmic.exe");try(BufferedReaderbr=newBufferedReader(newInputStreamReader(processo.getInputStream()));OutputStreamWriterosw=newOutputStreamWriter(processo.getOutputStream())){osw.write("process where name='javaw.exe'");osw.flush();while((line=br.readLine())!=null){if(line.contains("javaw.exe")){instances++;}}}if(instances>1){msg.aviso("Esta aplicação já está em execução.");System.exit(0);}}catch(IOExceptione){msg.falha("Falha geral de inicialização.\nMotivo: "+e);}}
rodriguesabner
O JSmooth consegue mudar o nome do processo que o seu Software vai abrir.
fabioklopes
Opa! Vou pesquisar sobre ele… Obrigado! Assim que eu tiver uma novidade, eu volto aqui …
Lucas_Camara2 likes
Talvez vc possa tentar a abordagem de criar um arquivo (.lock, por exemplo) quando o programa estiver rodando e remover o arquivo quando o programa for encerrado corretamente. E, ao tentar abrir uma segunda instância, verificar a existência do arquivo para permitir rodar ou não.
Para ficar melhor, vc pode atualizar o conteudo do arquivo a cada tempo (1 min, por exemplo), com o horário atual, com isso, ao iniciar uma instância, o horário do lock é verificado e, se a diferença for maior do que 1 min, vc pode eliminar esse lock e permitir que a instância seja executada (em caso de falha no encerramento da aplicação sem remover devidamente o lock).
fabioklopes
@rodriguesabner: tentei usar o JSmooth mas parece que ele “estragou” o processo de verificação de serviços em atividade no Windows. Consegui criar um executável e consegui fazer ele criar um serviço com um nome personalizado porém, quando tento executar a segunda aplicação - ou - quando tento forçar uma nova instância dele ou de outra aplicação JavaSwing, eu percebo que o serviço-01 não cai. Mesmo alterando as configurações do JSmooth não está derrubando o serviço. Sabe de algum truque que eu esteja deixando de fazer ou que eu possa fazer para corrigir isso?
@Lucas_Camara: creio que essa seja uma solução paliativa. Futuramente vou retomar a ideia dos services pois como cada estação da rede é usada por vários usuários do Active Directory em dois dias diferentes. O arquivo LOCK me ajudaria por enquanto mas tenho certeza que um dia isso vai me dar dor de cabeça…
Por enquanto muito obrigado… vou tentando por aqui também.
Lucas_Camara1 like
Outra forma é abrir uma porta qualquer no seu programa. Quando uma outra instancia for rodar, ela não vai conseguir abrir a mesma porta pois ela já estará aberta e lançará uma exceção. Já usei dessa forma e me atendeu na época.
fabioklopes
Hummm… parece ser melhor que o LOCK … nunca tentei forçar uma porta. Vou pesquisar sobre isso. Obrigado @Lucas_Camara.
staroski2 likes
O bacana de usar uma porta é que você pode implementar sua aplicação de tal forma que se uma instância da aplicação já estiver rodando, a segunda instância pode enviar uma mensagem para a primeira receber o foco e aí a segunda se encerra.
Veja o exemplo abaixo:
importjava.awt.Container;importjava.awt.Dimension;importjava.awt.FlowLayout;importjava.io.DataInputStream;importjava.io.DataOutputStream;importjava.io.IOException;importjava.net.InetAddress;importjava.net.ServerSocket;importjava.net.Socket;importjavax.swing.JFrame;importjavax.swing.JLabel;importjavax.swing.SwingConstants;importjavax.swing.UIManager;@SuppressWarnings("serial")publicclassProgramaExemploextendsJFrame{publicstaticvoidmain(String[]args){try{UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());ProgramaExemplotela=newProgramaExemplo();tela.setDefaultCloseOperation(EXIT_ON_CLOSE);tela.setLocationRelativeTo(null);tela.setVisible(true);}catch(Throwablet){t.printStackTrace();}}privateJLabellabel;publicProgramaExemplo(){super("Programa de Exemplo");verificarExecucao();label=newJLabel("Tentativas de abrir nova instância:",SwingConstants.CENTER);label.setPreferredSize(newDimension(300,100));Containercontainer=getContentPane();container.setLayout(newFlowLayout(FlowLayout.CENTER));container.add(label);pack();}privatevoidverificarExecucao(){finalintporta=12345;if(temOutraInstanciaRodando(porta)){// se já tem uma instância do programa conectada à portamostraOutraInstancia(porta);// mostra a outra intânciaSystem.exit(0);// em seguida encerra esta instância aqui}}privatebooleantemOutraInstanciaRodando(intporta){try{ServerSocketserver=newServerSocket(porta);Threadthread=newThread(()->monitorarPorta(server),"Monitor porta "+porta);thread.setDaemon(true);thread.start();returnfalse;// se conseguiu abriu o server socket então não tem outra instância executando}catch(IOExceptione){returntrue;// senão é sinal de que tem outra instância executando}}privatevoidmostraOutraInstancia(intporta){try{Socketsocket=newSocket(InetAddress.getLocalHost(),porta);DataOutputStreamoutput=newDataOutputStream(socket.getOutputStream());output.writeBoolean(true);// envia mensagem pra instância que está executandooutput.flush();output.close();socket.close();}catch(Exceptione){e.printStackTrace();}}privatevoidmonitorarPorta(ServerSocketserver){inttentativas=0;while(true){try{Socketsocket=server.accept();DataInputStreaminput=newDataInputStream(socket.getInputStream());if(input.readBoolean()){// recebe a mensagem da instância que tentou executartentativas++;label.setText("Tentativas de abrir nova instância:"+tentativas);toFront();}input.close();}catch(IOExceptione){e.printStackTrace();}}}}
fabioklopes1 like
Caramba, show de bola! Bom saber das possibilidades de uso dos sockets. Vou estudar essa opção então… Obrigado @staroski.