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?
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).
@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.
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.
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:
import java.awt.Container;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingConstants;
import javax.swing.UIManager;
@SuppressWarnings("serial")
public class ProgramaExemplo extends JFrame {
public static void main(String[] args) {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
ProgramaExemplo tela = new ProgramaExemplo();
tela.setDefaultCloseOperation(EXIT_ON_CLOSE);
tela.setLocationRelativeTo(null);
tela.setVisible(true);
} catch (Throwable t) {
t.printStackTrace();
}
}
private JLabel label;
public ProgramaExemplo() {
super("Programa de Exemplo");
verificarExecucao();
label = new JLabel("Tentativas de abrir nova instância:", SwingConstants.CENTER);
label.setPreferredSize(new Dimension(300, 100));
Container container = getContentPane();
container.setLayout(new FlowLayout(FlowLayout.CENTER));
container.add(label);
pack();
}
private void verificarExecucao() {
final int porta = 12345;
if (temOutraInstanciaRodando(porta)) { // se já tem uma instância do programa conectada à porta
mostraOutraInstancia(porta); // mostra a outra intância
System.exit(0); // em seguida encerra esta instância aqui
}
}
private boolean temOutraInstanciaRodando(int porta) {
try {
ServerSocket server = new ServerSocket(porta);
Thread thread = new Thread(() -> monitorarPorta(server), "Monitor porta " + porta);
thread.setDaemon(true);
thread.start();
return false; // se conseguiu abriu o server socket então não tem outra instância executando
} catch (IOException e) {
return true; // senão é sinal de que tem outra instância executando
}
}
private void mostraOutraInstancia(int porta) {
try {
Socket socket = new Socket(InetAddress.getLocalHost(), porta);
DataOutputStream output = new DataOutputStream(socket.getOutputStream());
output.writeBoolean(true); // envia mensagem pra instância que está executando
output.flush();
output.close();
socket.close();
} catch (Exception e) {
e.printStackTrace();
}
}
private void monitorarPorta(ServerSocket server) {
int tentativas = 0;
while (true) {
try {
Socket socket = server.accept();
DataInputStream input = new DataInputStream(socket.getInputStream());
if (input.readBoolean()) { // recebe a mensagem da instância que tentou executar
tentativas++;
label.setText("Tentativas de abrir nova instância:" + tentativas);
toFront();
}
input.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}