Pergunta

Eu preciso começar a 1-3 programas externos na minha aplicação Java que têm caminhos definidos pelo usuário. Eu tenho alguns requisitos:

  1. Eu não quero o programa para executar se ele já está sendo executado

  2. Eu não quero qualquer um dos programas para roubar o foco do meu aplicativo Java

  3. Eu não me importo se algum deles falhar ao iniciar ou não. Eles só precisam de falhar silenciosamente.

Aqui está o que eu vim acima com a medida:

ProcessBuilder pb = new ProcessBuilder(userDefinedPath1);
try {
    pb.start();
}
catch (Exception e) {
    // Something went wrong, just ignore
}

E então eu repito que mais 3 vezes com os outros dois caminhos. Isso começa como eu esperaria e encontra o meu terceiro requisito muito bem, mas não nos dois primeiros.

Qual é a melhor maneira de fazer isso?

Editar:

  1. Eu não tenho nenhum controle desses outros aplicativos. Eles são terceiros. Além disso, eles poderiam ter sido de início ou parada pelo utilizador manualmente a qualquer momento.

  2. Eu sei que o exata nomes dos executáveis ??(por exemplo, "blah.exe") e eles vão sempre ser o mesmo, mas os caminhos para os arquivos executáveis não será necessariamente.

  3. wrappers arquivo de lote não são viáveis ??aqui.

  4. As outras aplicações são não aplicativos java, simplesmente velho executáveis ??do Windows.

Foi útil?

Solução

Eu estou supondo que você não tem controle sobre os outros dois aplicativos ... Se você fez, isso não seria muito ruim - você poderia simplesmente tê-los ouvir um soquete e ver se o soquete está disponível quando você vir para cima.

A próxima solução pode realmente ser independente da linguagem. Você pode gerenciar todo o sistema por meio de invólucros de arquivo batch. Escrever um arquivo batch que cria um arquivo quando ele inicia e exclui-lo quando ele pára. sistemas Unix usar esta técnica muito - eles chamam o arquivo de um arquivo de bloqueio mais frequentemente do que não

.

Se apenas a sua aplicação vai sempre iniciar esses outros aplicativos, então você poderia simplesmente acompanhar se você começou ou não, então eu estou supondo que isso não é possível ou você não estaria perguntando, então eu sou assumindo que o usuário pode ter lançado esses programas através de algum outro mecanismo.

Se você não tem controle sobre o lançamento dos outros aplicativos e não pode mesmo escrever um arquivo de lote para lançá-los, então você simplesmente não pode fazer o que você quer fazer (Nota, os aplicativos teria que sempre uso o arquivo de lote, mesmo se o usuário começou-los à mão).

Eu apenas um de muito último esforço poderia ser a de obter um status do processo e analisá-lo, mas você tem que saber exatamente o que os outros aplicativos foram chamados no PS, este não é realmente trivial. Além disso, todos os aplicativos java tendem a ter a mesma assinatura exata na maioria das impressões de status processo que poderia fazer esta inútil.

O problema é que, se um desses programas foram iniciados fora do seu aplicativo, você tem praticamente nenhuma maneira de identificar esse fato a menos que você sabe que é exata assinatura estado do processo, e mesmo assim é esquisito.

Outras dicas

I fornecem duas respostas, uma para Linux:

Não execute o programa se ele já está em execução, colocar isso em um arquivo chamado Main.java

import java.io.File;
import java.io.RandomAccessFile;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;

class JustOneLock {
  FileLock lock;
  FileChannel channel;

  public boolean isAppActive() throws Exception{
    File file = new File(System.getProperty("user.home"),
            "FireZeMissiles1111" + ".tmp");
    channel = new RandomAccessFile(file, "rw").getChannel();

    lock = channel.tryLock();
    if (lock == null) {
      return true;
    }
    Runtime.getRuntime().addShutdownHook(new Thread() {
      public void run() {
        try {
          lock.release();
          channel.close();
        } catch (Exception e) {
          e.printStackTrace();
        }
      }
    });
    return false;
  }
}

public class Main {
  public static void main(String[] args)throws Exception {
    JustOneLock u = new JustOneLock();

    if (u.isAppActive()) {
      System.out.println("Already active, stop!");
      System.exit(1);
    }
    else {
      System.out.println("NOT active... Do hard work for 5 seconds.");
      try{Thread.sleep(5000);}catch(Exception e){}
    }
  }
}

compilá-lo e executá-lo. Em seguida, abra um novo terminal e tentar executá-lo novamente, enquanto o outro está em execução e que não vai.

Outra resposta para Windows

Este programa não se deixará ser executado se ele já estiver em execução no sistema atual. Este é apenas para Windows sistemas.

import java.io.*;
import java.util.prefs.Preferences;

public class JavaApplication3 {

    public static void main(String[] args){
        if(isRunning()){
            System.out.println("Two instances of this program cannot " +
                    "be running at the same time.  Exiting now");
        }
        else{
            onStart();
            epicHeavyWorkGoesHere();
            onFinish();
        }
    }
    public static void epicHeavyWorkGoesHere(){
        try {
            Thread.sleep(5000);
        } catch (InterruptedException ex) {}
    }
    public static void onStart(){
        Preferences prefs = Preferences.systemRoot().node("JavaApplication3");
        prefs.put("RUNNINGPID", getCurrentPID());
    }
    public static void onFinish(){
        Preferences prefs = Preferences.systemRoot().node("JavaApplication3");
        prefs.put("RUNNINGPID", "");
    }
    public static boolean isRunning(){
        Preferences prefs = Preferences.systemRoot().node("JavaApplication3");

        if (prefs.get("RUNNINGPID", null) == null || prefs.get("RUNNINGPID", null).equals(""))
            return false;

        if (isProcessIdRunningOnWindows(Integer.parseInt(prefs.get("RUNNINGPID", null))))
            return true;
        return false;
    }
    public static String getCurrentPID(){
        //This function is designed to get the PID from the windows system, it may
        //not work for Linux or Mac.  You'll have to acquire a suitable getCurrentPID function
        try{
            java.lang.management.RuntimeMXBean runtime = java.lang.management.ManagementFactory.getRuntimeMXBean();
            java.lang.reflect.Field jvm = runtime.getClass().getDeclaredField("jvm");
            jvm.setAccessible(true);
            sun.management.VMManagement mgmt = (sun.management.VMManagement) jvm.get(runtime);
            java.lang.reflect.Method pid_method = mgmt.getClass().getDeclaredMethod("getProcessId");
            pid_method.setAccessible(true);
            return pid_method.invoke(mgmt) + "";
        }
        catch(Exception e){
            throw new RuntimeException("Cannot get the current PID");
        }
    }
    public static boolean isProcessIdRunningOnWindows(int pid){
        //This Function only works for windows, if you want it to work on linux
        //you will have to go find a replacement method that takes the processID
        //as a parameter and spits out a true/false if it is running on the system.
        try {
            Runtime runtime = Runtime.getRuntime();
            String cmds[] = {"cmd", "/c", "tasklist /FI \"PID eq " + pid + "\""};
            Process proc = runtime.exec(cmds);

            InputStream inputstream = proc.getInputStream();
            InputStreamReader inputstreamreader = new InputStreamReader(inputstream);
            BufferedReader bufferedreader = new BufferedReader(inputstreamreader);
            String line;
            while ((line = bufferedreader.readLine()) != null) {
                if (line.contains(" " + pid + " ")){
                    return true;
                }
            }
            return false;
        }
        catch (Exception ex) {
            throw new RuntimeException("Cannot run the tasklist command to query if a pid is running or not");
        }
    }
}

A estratégia do código acima é manter o PID em torno da última corrida, se isso PID é encontrado em execução no sistema, não comece. Se você terminar, reinicie.

As preferências são armazenadas no Registro do Windows em HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Prefs

Eu aconselho contra o uso de bloqueio de arquivos para certificar-se de uma aplicação java não é executado duas vezes ao mesmo tempo, porque se o programa falhar ou trava para sempre e é morto, então o bloqueio é deixado em um estado inconsistente e, talvez, pode até sobreviver uma reinicialização que irá causar problemas, pois como é que o programa sabe a diferença entre um programa que ainda está em execução e um programa que caiu e deixou o arquivo bloqueado bloqueado?

Estou muito confiante de que esta é a melhor maneira; O aplicativo é executado um "servidor" na inicialização, e se a porta do servidor já está tomada, o fechamento de aplicativos.

public static ServerSocket ss;

public static void main (String[] args) {

    ss = null;

    try {
        ss = new ServerSocket(1044);
    } catch (IOException e) {
        System.err.println("Application already running!");
        System.exit(-1);
    }
}

Este é o que eu fiz para resolver o problema, é uma solução simples em para usando java puro:

Note, se o seguinte código trava uma vez, ele é deixado em um estado inconsistente e não tem maneira de lidar com um suspenso ou paralisado programa.

public void main(String[] args){
    if(isRunning()){
        JOptionPane.showMessageDialog(this, "2 instances of this program cannot be running at the same time. \n Exiting now");
        System.exit(0);
    }else{
        onStart();
    }
}    

public final void onStart(){
    Preferences prefs;
    prefs = Preferences.userRoot().node(this.getClass().getName());
    prefs.put("RUNNING", "true");
}

public final void onFinish(){
    Preferences prefs;
    prefs = Preferences.userRoot().node(this.getClass().getName());
    prefs.put("RUNNING", "false");
}

public boolean isRunning(){
    Preferences prefs;
    prefs = Preferences.userRoot().node(this.getClass().getName());
    return prefs.get("RUNNING", null) != null ? Boolean.valueOf(prefs.get("RUNNING", null)) : false;
}

private void formWindowClosing(java.awt.event.WindowEvent evt) {
    onFinish();
}

Verifique se um programa ou processo está em execução (Windows)

Esta dica irá detectar se um determinado programa está em execução. Ok, não é bonito por causa do VBScript, mas é fácil de implementar.

Se eu estivesse lidando com esse problema em um sistema baseado em UNIX eu seria tentado a escrever uma função nativa para reunir informações de processo e tentar lançar as aplicações externas. Isso vai contra o espírito do Java, mas o tipo de informação que você está tentando reunir e controle de lançamento aplicação estão fora do JVM.

Eu não sei o suficiente sobre o Windows programação para que você aponte na direção certa, mas eu imagino que há o Windows API chamadas que você pode acessar em linguagens .NET ou planície C ++ que poderiam ajudá-lo com o seu segundo critério. Talvez você possa mudar a pergunta para atrair os desenvolvedores não-Java que poderia ajudar.


Editar:

Confira o Shell executar a função da API do Windows. A opção SW_SHOWNOACTIVATE parece permitir que a janela atual para permanecer ativo.

Há uma pequena coisa que você pode fazer para todos os sistemas, e isso inclui a capacidade de bloqueio de arquivo.

Executar Programa On Primeiro, crie um arquivo e bloqueá-lo. Nomeá-lo algo como lockfile. Gerar um timestamp e criptografá-lo. Escreve isto para ele.

No mesmo programa run Em primeiro lugar, verificar se existe um arquivo de bloqueio presente. Tentar bloqueá-lo. Ignorar a possibilidade de que este arquivo está bloqueado. Leia e verificação timestamp. Se o carimbo de tempo é algo inanely pequena (como 1 hora atrás), tentar executar o programa. Você vai erro ao escrever uma volta timestamp, porque está bloqueado. Neste caso, supor que há um programa já está aberto.

Na saída do programa, excluir este arquivo de bloqueio.

no Windows XP (pro?) Você pode lançar o comando 'tasklist' e analisar a saída para determinar se um processo está sendo executado. você pode usar tópicos para evitar qualquer problema com foco (eu acho)

Você pode usar JPS para conhecer o estado de funcionamento do programa de java. JPS é uma ferramenta java como javac, java etc.,

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top