JAVAW.EXE no Gerenciador de Tarefas

12 respostas
java
fabioklopes

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?

12 Respostas

Lucas_Camara

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:

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);
    }
    
}
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_Camara

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_Camara

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.

staroski

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

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

Criado 3 de julho de 2019
Ultima resposta 5 de jul. de 2019
Respostas 12
Participantes 4