如何允许一次只运行一个Java程序实例?

时间:2009-05-28 11:28:24

标签: java java-web-start jnlp

我需要多次阻止用户启动我的Java应用程序(WebStart Swing应用程序)。因此,如果应用程序已在运行,则无法再次启动它或显示警告/再次关闭。

有没有一些方便的方法来实现这一目标?我想过阻塞一个端口或写一个文件。但希望您可以访问某些系统属性或JVM?

顺便说一句。目标平台是带有Java 1.5的Windows XP

9 个答案:

答案 0 :(得分:35)

我认为您在启动应用程序时打开端口进行监听的建议是最好的选择。

这很容易做到,关闭应用程序时无需担心清理它。例如,如果您写入文件但有人使用任务管理器杀死进程,则该文件不会被删除。

另外,如果我没记错,没有简单的方法可以从JVM内部获取Java进程的PID,所以不要尝试使用PID来制定解决方案。

这样的事情可以解决问题:

private static final int PORT = 9999;
private static ServerSocket socket;    

private static void checkIfRunning() {
  try {
    //Bind to localhost adapter with a zero connection queue 
    socket = new ServerSocket(PORT,0,InetAddress.getByAddress(new byte[] {127,0,0,1}));
  }
  catch (BindException e) {
    System.err.println("Already running.");
    System.exit(1);
  }
  catch (IOException e) {
    System.err.println("Unexpected error.");
    e.printStackTrace();
    System.exit(2);
  }
}

此示例代码明确绑定到127.0.0.1,这应该避免任何防火墙警告,因为此地址上的任何流量必须来自本地系统。

选择端口时尽量避免使用list of Well Known Ports中提到的端口。理想情况下,您应该在文件中使用可配置的端口,或者在发生冲突时通过命令行开关进行配置。

答案 1 :(得分:26)

由于问题表明正在使用WebStart,显而易见的解决方案是使用javax.jnlp.SingleInstanceService

此服务在1.5中提供。请注意,1.5目前是其服务终止期限的大部分时间。使用Java SE 6!

答案 2 :(得分:3)

我认为更好的想法是使用文件锁(相当古老的想法:))。从Java 1.4开始,引入了一个新的I / O库,允许文件锁定。

一旦应用程序启动,它会尝试获取文件的锁定(或者如果不存在则创建它),当应用程序退出锁定时会被重新启动。如果应用程序无法获取锁定,则退出。

如何进行文件锁定的示例例如在Java Developers Almanac

如果要在Java Web Start应用程序或applet中使用文件锁定,则需要唱出应用程序或小程序。

答案 3 :(得分:1)

我们在C ++中通过创建一个内核互斥对象并在启动时查找它来做同样的事情。优点与使用套接字相同,即当进程死亡/崩溃/退出/被杀死时,内核会清除互斥对象。

我不是Java程序员,所以我不确定你是否可以用Java做同样的事情?

答案 4 :(得分:1)

我已经创建了跨平台的AppLock类。

http://rumatoest.blogspot.com/2015/01/howto-run-only-single-java-application.html

使用文件锁技术。

更新。在2016-10-14我创建了与maven / gradle https://github.com/jneat/jneat兼容的包,并在此解释http://rumatoest.blogspot.com/2015/06/synchronize-code-over-multiple-jvm.html

答案 5 :(得分:1)

您可以使用JUnique库。它为运行单实例java应用程序提供支持,并且是开源的。

http://www.sauronsoftware.it/projects/junique/

另见How to implement a single instance Java application?

的完整答案

答案 6 :(得分:0)

你可以使用注册表,虽然这半心半意地失去了使用像java这样的高级语言的目的。至少你的目标平台是windows = D

答案 7 :(得分:0)

尝试JUnique:

String appId = "com.example.win.run.main";
boolean alreadyRunning;
try {
    JUnique.acquireLock(appId);
    alreadyRunning = false;
} catch (AlreadyLockedException e) {
    alreadyRunning = true;
}
if (alreadyRunning) {
    Sysout("An Instance of this app is already running");
    System.exit(1);
}

答案 8 :(得分:-1)

我已经看到了很多这样的问题,我希望以独立于平台的方式解决同样的问题,不会有机会与防火墙发生冲突或进入套接字。

所以,这就是我的所作所为:

import java.io.File;
import java.io.IOException;

/**
 * This static class is in charge of file-locking the program
 * so no more than one instance can be run at the same time.
 * @author nirei
 */
public class SingleInstanceLock {

    private static final String LOCK_FILEPATH = System.getProperty("java.io.tmpdir") + File.separator + "lector.lock";
    private static final File lock = new File(LOCK_FILEPATH);
    private static boolean locked = false;

    private SingleInstanceLock() {}

    /**
     * Creates the lock file if it's not present and requests its deletion on
     * program termination or informs that the program is already running if
     * that's the case.
     * @return true - if the operation was succesful or if the program already has the lock.<br>
     * false - if the program is already running
     * @throws IOException if the lock file cannot be created.
     */
    public static boolean lock() throws IOException {
        if(locked) return true;

        if(lock.exists()) return false;

        lock.createNewFile();
        lock.deleteOnExit();
        locked = true;
        return true;
    }
}

对锁文件路径使用System.getProperty(“java.io.tmpdir”)可确保始终在同一位置创建锁。

然后,从你的程序中你可以调用类似的东西:

blah blah main(blah blah blah) {
    try() {
        if(!SingleInstanceLock.lock()) {
            System.out.println("The program is already running");
            System.exit(0);
        }
    } catch (IOException e) {
        System.err.println("Couldn't create lock file or w/e");
        System.exit(1);
    }
}

这对我来说就是这样。现在,如果您终止该程序,它将不会删除锁定文件,但您可以通过将程序的PID写入锁定文件并使lock()方法检查该进程是否已在运行来解决此问题。对于任何有兴趣的人来说,这都是一种帮助。 :)