我希望防止用户同时运行我的Java应用程序。
为了防止这种情况发生,当我打开应用程序时,我创建了一个锁文件,并在关闭应用程序时删除该锁文件。
当应用程序正在运行时,您不能打开另一个jar实例。但是,如果您通过任务管理器终止应用程序,则应用程序中的窗口关闭事件不会触发,锁文件也不会被删除。
如何确保锁文件方法有效或者我可以使用什么其他机制?
我希望防止用户同时运行我的Java应用程序。
为了防止这种情况发生,当我打开应用程序时,我创建了一个锁文件,并在关闭应用程序时删除该锁文件。
当应用程序正在运行时,您不能打开另一个jar实例。但是,如果您通过任务管理器终止应用程序,则应用程序中的窗口关闭事件不会触发,锁文件也不会被删除。
如何确保锁文件方法有效或者我可以使用什么其他机制?
您可以使用FileLock,这也适用于多个用户共享端口的环境:
String userHome = System.getProperty("user.home");
File file = new File(userHome, "my.lock");
try {
FileChannel fc = FileChannel.open(file.toPath(),
StandardOpenOption.CREATE,
StandardOpenOption.WRITE);
FileLock lock = fc.tryLock();
if (lock == null) {
System.out.println("another instance is running");
}
} catch (IOException e) {
throw new Error(e);
}
也能在垃圾回收时存活。 一旦您的进程结束,无论是正常退出、崩溃还是其他情况,锁都会被释放。
类似的讨论在http://www.daniweb.com/software-development/java/threads/83331上进行。
绑定ServerSocket。如果绑定失败,则中止启动。由于ServerSocket只能绑定一次,因此程序只能运行单个实例。
在你问之前,不是所有绑定了ServerSocket的程序都可以接受网络流量。只有当程序使用accept()开始“监听”端口时,才会生效。
ServerSocket.accept()
会阻塞线程,因此在自己的线程中运行它可以避免阻塞主线程。public static void main(String[] args) {
assertNoOtherInstanceRunning();
... // application code then
}
public static void assertNoOtherInstanceRunning() {
new Thread(() -> {
try {
new ServerSocket(9000).accept();
} catch (IOException e) {
throw new RuntimeException("the application is probably already started", e);
}
}).start();
}
您可以将创建锁定文件的进程的进程ID写入该文件。
当您遇到现有的锁定文件时,不要仅仅退出,而是检查具有该ID的进程是否仍然存在。 如果不存在,则可以继续进行。
public static void main(String args[]) throws Exception {
File f = new File("checkFile");
if (!f.exists()) {
f.createNewFile();
} else {
System.out.println("App already running" );
return;
}
f.deleteOnExit();
// whatever your app is supposed to do
System.out.println("Blah Blah")
}
new ServerSocket(65535, 1, InetAddress.getLocalHost());
我为这个问题开发了两种解决方案。我还在寻找一种不使用任何库和大量代码的简单方法。
我的解决方案基于:https://dev59.com/WGw05IYBdhLWcg3wxkqr#46705579,我对其进行了改进。因此,我要感谢@akshaya pandey和@rbento
package YOUR_PACKAGE_NAME;
import java.io.File;
import java.io.IOException;
/**
* Minimal reproducible example (MRE) - Example of a simple lock file.
* @author Remzi Cavdar - ict@remzi.info - <a href="https://github.com/Remzi1993">@Remzi1993</a>
*/
public class Main {
public static void main(String[] args) {
/*
* Prevents the user of starting multiple instances of the application.
* This is done by creating a temporary file in the app directory.
* The temp file should be excluded from git and is called App.lock in this example.
*/
final File FILE = new File("App.lock");
try {
if (FILE.createNewFile()) {
System.out.println("Starting application");
} else {
System.err.println("The application is already running!");
return;
}
} catch (IOException e) {
throw new RuntimeException(e);
}
/*
* Register a shutdown hook to delete the lock file when the application is closed. Even when forcefully closed
* with the task manager. (Tested on Windows 11 with JavaFX 19)
*/
FILE.deleteOnExit();
// Whatever your app is supposed to do
}
}
package YOUR_PACKAGE_NAME;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
/**
* Minimal reproducible example (MRE) - Example of a more advanced lock system.
* @author Remzi Cavdar - ict@remzi.info - <a href="https://github.com/Remzi1993">@Remzi1993</a>
*/
public class Main {
public static void main(String[] args) {
/*
* Prevents the user of starting multiple instances of the application.
* This is done by creating a temporary file in the app directory.
* The temp file should be excluded from git and is called App.lock in this example.
*/
final File FILE = new File("App.lock");
if (FILE.exists()) {
System.err.println("The application is already running!");
return;
}
try (
FileOutputStream fileOutputStream = new FileOutputStream(FILE);
FileChannel channel = fileOutputStream.getChannel();
FileLock lock = channel.lock()
) {
System.out.println("Starting application");
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
}
/*
* Register a shutdown hook to delete the lock file when the application is closed. Even when forcefully closed
* with the task manager. (Tested on Windows 11 with JavaFX 19)
*/
FILE.deleteOnExit();
// Whatever your app is supposed to do
}
}
我关闭了应用程序,并在Windows任务管理器中强制关闭了应用程序,两次锁定文件似乎都被删除了。
你可以写出类似这样的内容。
如果文件存在,则尝试删除它。如果无法删除,则可以说应用程序已在运行中。
现在再次创建相同的文件并重定向sysout和syserr。
这对我很有效。
SingleInstanceService
。这是我关于SingleInstanceService
的演示。