如何允许一次只运行一个Java程序实例?
我需要防止用户多次启动我的Java应用程序(WebStart Swing应用程序)。因此,如果应用程序已在运行,则不可能再次启动或显示警告/再次关闭 有什么方便的方法可以做到这一点吗?我想阻塞一个端口或将某物写入一个文件。但希望您可以访问一些系统属性或JVM如何允许一次只运行一个Java程序实例?,java,java-web-start,jnlp,Java,Java Web Start,Jnlp,我需要防止用户多次启动我的Java应用程序(WebStart Swing应用程序)。因此,如果应用程序已在运行,则不可能再次启动或显示警告/再次关闭 有什么方便的方法可以做到这一点吗?我想阻塞一个端口或将某物写入一个文件。但希望您可以访问一些系统属性或JVM 顺便说一句,目标平台是Windows XP和Java 1.5,您可以使用注册表,尽管这会使使用Java这样的高级语言的目的落空。至少你的目标平台是windows=D我认为你建议在启动应用程序时打开一个端口进行监听是最好的主意 这很容易做到,
顺便说一句,目标平台是Windows XP和Java 1.5,您可以使用注册表,尽管这会使使用Java这样的高级语言的目的落空。至少你的目标平台是windows=D我认为你建议在启动应用程序时打开一个端口进行监听是最好的主意 这很容易做到,而且当您关闭应用程序时,您不需要担心清理它。例如,如果您写入一个文件,但有人使用任务管理器终止了进程,则该文件不会被删除 另外,如果我没记错的话,没有简单的方法可以从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
,这将避免任何防火墙警告,因为此地址上的任何通信必须来自本地系统
选择端口时,请尽量避免使用中提到的端口。在冲突的情况下,您应该理想地使端口可配置在文件中或通过命令行开关。< P>我们通过创建一个内核互斥对象并在启动时查找它来在C++中做同样的操作。其优点与使用套接字相同,即当进程死亡/崩溃/退出/终止时,互斥对象由内核清理
我不是Java程序员,所以我不确定您是否可以用Java做同样的事情?因为问题表明正在使用WebStart,显而易见的解决方案是使用
此服务在1.5版中提供。请注意,1.5目前是其使用寿命结束期间的大部分时间。使用JavaSE6 我认为更好的办法是使用文件锁(这是一个非常古老的想法:))。自从Java1.4引入一个新的I/O库以来,它允许文件锁定 一旦应用程序启动,它将尝试获取文件的锁(如果不存在,则创建该文件),当应用程序退出时,锁将被释放。若应用程序无法获取锁,它将退出 例如,中提供了如何执行文件锁定的示例
如果要在Java Web Start应用程序或小程序中使用文件锁定,则需要使用该应用程序或小程序。我已经创建了跨平台的AppLock类 它使用文件锁定技术
更新。2016年10月14日,我创建了一个与maven/gradle兼容的软件包,并在这里解释了它我看到了很多这样的问题,我希望以一种平台无关的方式来解决同样的问题,而不是冒着与防火墙冲突或进入套接字的风险 下面是我所做的:
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;
}
}
对我来说就是这样。现在,如果您杀死程序,它不会删除锁文件,但您可以通过将程序的PID写入锁文件并使lock()方法检查该进程是否已在运行来解决此问题。这是留给感兴趣的任何人的一项协助。:) 您可以使用JUnique库。它支持运行单实例java应用程序,并且是开源的 另请参见我在上的完整答案,试试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);
}
好主意!一个非常严格的安全管理器会有任何安全问题吗?这会导致任何防火墙警告吗?如何选择一个我们知道没有被其他程序使用的端口?正如欧文指出的,我相信这会引起防火墙警告。我不太同意这种方法。一定有更优雅的方式。Jon Skeet在哪里?在示例代码中,我显式绑定到127.0.0.1,这应该避免任何防火墙警告,因为该地址上的任何流量只能在本地系统内部。这是一个坏主意,因为端口是按系统分配的,而不是按用户分配的。在Windows终端服务器、具有快速用户切换功能的Windows、具有快速用户切换功能的Mac或多人登录UNIX设备上,这将成为拒绝服务攻击。最简单的解决方案:-)java.nio.file lock请参阅完整示例,它也会遇到与锁定文件相同的问题:如果程序死亡,您如何知道何时解除锁定?由于Taskmanager或Linux kill命令未释放锁定文件,文件锁定将无法工作看起来是个不错的选择。您的解决方案是否能够识别我的应用程序的前一个实例是否被终止,而不是正常停止?
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);
}