JAVAW.EXE no Gerenciador de Tarefas

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:

  1. Abro a aplicação “A” sem problemas;
  2. 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?

Não … aplicações puras … apenas conexões com MySQL.

Acho que vai depender da forma como essa verificação está sendo feita. Ela está se baseando no nome do processo, certo?

Sim, uma verificação bem simples… Veja:

public void verificaProcesso() {
    String line;
    int instances = 0;

    try {
        Process processo = Runtime.getRuntime().exec("wmic.exe");

        try (
                BufferedReader br = new BufferedReader(new InputStreamReader(processo.getInputStream())); 
                OutputStreamWriter osw = new OutputStreamWriter(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 (IOException e) {
        msg.falha("Falha geral de inicialização.\nMotivo: " + e);
    }
    
}

O JSmooth consegue mudar o nome do processo que o seu Software vai abrir.

Opa! Vou pesquisar sobre ele… Obrigado! Assim que eu tiver uma novidade, eu volto aqui …

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).

2 curtidas

@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.

1 curtida

Hummm… parece ser melhor que o LOCK … nunca tentei forçar uma porta. Vou pesquisar sobre isso. Obrigado @Lucas_Camara.

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();
            }
        }
    }
}
2 curtidas

Caramba, show de bola! Bom saber das possibilidades de uso dos sockets. Vou estudar essa opção então… Obrigado @staroski.

1 curtida