我要开始1-3外部程序在我Java应用程序,有的路径定义的用户。我有几个要求:

  1. 我不想的程序来执行,如果它已经运行

  2. 我不想任何程序偷重点从我Java应用程序

  3. 我不在乎如果他们中的任何不开始或不行。他们只需要失败的默默。

这里是我们想出了迄今为止:

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

然后我重复,3次与其他两个途径。这样开始我就期望和满足我的第三个要求的只是罚款,但未在第二。

什么是最好的方式做到这一点?

编辑:

  1. 我没有任何控制这些其他应用程序。他们是第三方。此外,他们可能已经开始或停止用户手动在任何时间。

  2. 我知道的 确切的 名称的可执行文件(例如"blah.exe"),他们将 总是 是相同的,但途径的可执行程序不一定可以。

  3. 批文件包是不可行的,在这里。

  4. 其他应用程序是 java应用程序,只是普通的老窗户的可执行程序。

有帮助吗?

解决方案

我猜你没有控制的其他两个应用程序...如果你没有,这个也不会太糟糕了-你能让他们听到一个插座和座是当你上来。

下一个解决方案实际上可能是独立的语言。你可以管理整个系统通过批文件包装。写的一批文件,该文件创建了一个文件时,它开始了,并删除它的时候它停止。Unix系统中使用这种技术很多--他们呼叫的文件锁的文件往往并非如此。

如果只有你的应用程序都不会开始这些其他应用程序,然后你可以简单地轨道如果你已经开始或不是,所以我猜这是不可能或者你不会问的,所以我假设,用户可能已经启动这些程序通过的一些其他机构。

如果你有没有控制的发起的其他应用程序,甚至不能写的一批文件,以启动它们,那么你就不能做你想要做什么(注意,这些应用程序必须总是使用批量文件,即使用户开始他们的手).

我只是一个非常-最后的努力可能获得一个进程的状态,并分析它,但是你得知道到底是什么的其他应用程序被称为PS,这并不是微不足道的。此外,所有java应用程序往往有同样的签名,在大多数过程现状的打印输出,这可能使这无用的。

问题是,如果这些程序之一开始了外部的应用程序,你们几乎没有办法确定这一事实,除非你知道它的确切过程的状态签名,甚至那么它的片状。

其他提示

我提供两个答案,一个Linux:

不运行程序,如果它已经运行,把这个放在一个文件叫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){}
    }
  }
}

编制并运行它。然后打开一个新端和尝试再次运行,而另一种是运行的并且它不会将。

另一个答案for Windows

这个程序将不会允许自己进行,如果已在运行当前的系统。这是仅适用于windows系统。

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

该战略的上述代码是保持PID周围从最后一行,如果这PID被发现的系统上运行的,不要开始。如果你完成重置。

首都储存在窗户注册表 HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Prefs

我建议使用的文件锁定,以确保java应用程序不运行两次在同一时间,因为如果程序的崩溃或悬挂永远和被杀害,然后锁在不一致状态和也许甚至可以生存的一个重启这会造成问题,因为将如何知道程序之间的差异程序,它仍在运行和程序,该程序已经崩溃了,左锁着的文件的锁?

我非常相信这是最好的方式;该应用程序运行一个"服务"在启动时,如果服务器的端口是已经采取的应用程序关闭。

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

这是什么我没有要解决的问题,这是一个简单的解决办法在于采用纯java:

注意,如果以下代崩溃后,它留在不一致的国家和没有办法处理一个挂起或崩溃的程序。

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

看看 如果检查程序或进程的运行(Windows)

这个小,将检测,如果给定的程序正在运行。好,它是不是很漂亮,因为vbscript但它很容易实现。

如果我们处理这个问题上基于unix系统我会被诱惑到编写本机功能收集信息的过程,并试图启动的外部应用程序。这违背了精神Java、但类型的信息你正在试图收集和控制的应用程序启动之外的JVM。

我不知道足够关于Windows的编程为你指出正确的方向,但是我想象的有Windows API的电话你可以访问。网络语言或普通C++,可以帮助你,与你的第二个标准。也许你可以改变的问题,以吸引非Java开发人员可能会有帮助。


编辑:

检查出来的 壳执行功能 Windows API。该SW_SHOWNOACTIVATE选项似乎允许目前的窗口,以保持活动。

有一个微小事你可以做到所有系统,这包括文件锁的能力。

在运行的程序 第一,创建文件和锁定它。名字这东西像文件锁.产生一个时间戳和加密。写入这个进入它。

在相同的运行程序 第一,检查是否存在一个加锁的文件。试图锁定它。忽略这种可能性,这个文件是锁着的。读取和检查的时间戳。如果时间戳是空的小型(如1小时前),尝试运行程序。你会写错误的时间戳回,因为它被锁定。在这种情况下,假定有一个程序已经打开。

在程序退出,删除这个锁的文件。

在windows xp(pro?) 你可以启动的命令'的任务列表'和分析产出,以确定如果一个过程在运行。你可以使用线,避免任何问题聚焦(i think)

你可以使用太平绅士知道的运行java程序的状态。jps是一个java的工具,如javac、java等,

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top