题
我要开始1-3外部程序在我Java应用程序,有的路径定义的用户。我有几个要求:
我不想的程序来执行,如果它已经运行
我不想任何程序偷重点从我Java应用程序
我不在乎如果他们中的任何不开始或不行。他们只需要失败的默默。
这里是我们想出了迄今为止:
ProcessBuilder pb = new ProcessBuilder(userDefinedPath1);
try {
pb.start();
}
catch (Exception e) {
// Something went wrong, just ignore
}
然后我重复,3次与其他两个途径。这样开始我就期望和满足我的第三个要求的只是罚款,但未在第二。
什么是最好的方式做到这一点?
编辑:
我没有任何控制这些其他应用程序。他们是第三方。此外,他们可能已经开始或停止用户手动在任何时间。
我知道的 确切的 名称的可执行文件(例如"blah.exe"),他们将 总是 是相同的,但途径的可执行程序不一定可以。
批文件包是不可行的,在这里。
其他应用程序是 不 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();
}
这个小,将检测,如果给定的程序正在运行。好,它是不是很漂亮,因为vbscript但它很容易实现。
如果我们处理这个问题上基于unix系统我会被诱惑到编写本机功能收集信息的过程,并试图启动的外部应用程序。这违背了精神Java、但类型的信息你正在试图收集和控制的应用程序启动之外的JVM。
我不知道足够关于Windows的编程为你指出正确的方向,但是我想象的有Windows API的电话你可以访问。网络语言或普通C++,可以帮助你,与你的第二个标准。也许你可以改变的问题,以吸引非Java开发人员可能会有帮助。
编辑:
检查出来的 壳执行功能 Windows API。该SW_SHOWNOACTIVATE选项似乎允许目前的窗口,以保持活动。
有一个微小事你可以做到所有系统,这包括文件锁的能力。
在运行的程序 第一,创建文件和锁定它。名字这东西像文件锁.产生一个时间戳和加密。写入这个进入它。
在相同的运行程序 第一,检查是否存在一个加锁的文件。试图锁定它。忽略这种可能性,这个文件是锁着的。读取和检查的时间戳。如果时间戳是空的小型(如1小时前),尝试运行程序。你会写错误的时间戳回,因为它被锁定。在这种情况下,假定有一个程序已经打开。
在程序退出,删除这个锁的文件。
在windows xp(pro?) 你可以启动的命令'的任务列表'和分析产出,以确定如果一个过程在运行。你可以使用线,避免任何问题聚焦(i think)
你可以使用太平绅士知道的运行java程序的状态。jps是一个java的工具,如javac、java等,