29

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

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

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

4

9 回答 9

37

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

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

另外,如果我没记错的话,没有简单的方法可以从 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应避免任何防火墙警告的地址,因为此地址上的任何流量都必须来自本地系统。

选择端口时,请尝试避免著名端口列表中提到的端口。理想情况下,您应该在文件中或通过命令行开关配置使用的端口,以防发生冲突。

于 2009-05-28T11:32:15.243 回答
26

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

该服务在 1.5 中可用。请注意,目前 1.5 已经过了其服务生命周期的大部分时间。使用 Java SE 6!

于 2009-05-28T12:33:58.863 回答
3

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

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

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

如果要在 Java Web Start 应用程序或小程序中使用文件锁定,则需要对应用程序或小程序进行调用。

于 2009-05-28T12:35:06.800 回答
2

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

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

另请参阅如何实现单实例 Java 应用程序?

于 2016-11-23T11:32:57.610 回答
1

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

http://mixeddev.info/articles/2015/02/01/run-single-jvm-app-instance.html

它使用文件锁定技术。

更新。在 2016 年 10 月 14 日,我创建了与 maven/gradle 兼容的包https://github.com/jneat/jneat并在此处进行了解释http://mixeddev.info/articles/2015/06/01/synchronize-different -jvm-instances.html

于 2012-07-20T11:08:25.710 回答
1

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

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

于 2009-05-28T12:06:46.890 回答
0

您可以使用注册表,尽管这会半心半意地违背使用像 java 这样的高级语言的目的。至少你的目标平台是 windows =D

于 2009-05-28T11:31:39.300 回答
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);
}
于 2017-09-12T14:21:47.370 回答
-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() 方法检查该进程是否已在运行来解决此问题。这留给任何有兴趣的人作为评估。:)

于 2014-03-06T12:56:06.773 回答