我在here找到了这段代码,它基本上在某一时刻只允许该应用程序的一个实例。当我尝试从命令行启动 jar 文件的两个实例时,代码工作正常,但在使用 jpackage 生成 .exe 文件后,我可以一次启动应用程序的多个实例。有谁知道为什么它会这样? 在使用 jpackage 创建 .exe 文件后,是否有办法锁定 java 中的进程以防止同一应用程序同时出现多个实例?
您找到的代码是应用程序需要执行的操作的过于简化的版本。 它更像是概念注释,而不是实际的解决方案。
执行此操作的正确方法是在已知的稳定位置创建文件,而不仅仅是在程序的当前工作目录中创建文件。 有几种不同的方法可以让其他尝试打开该程序的人向当前正在运行的实例发送消息。 最简单的一种是本地套接字:
import static java.lang.System.Logger.Level;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.IOException;
import java.net.Socket;
import java.net.ServerSocket;
import java.net.InetAddress;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.nio.file.Files;
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.BorderFactory;
public class SingletonApplication {
private static final System.Logger logger =
System.getLogger(SingletonApplication.class.getName());
private static final int MESSAGE_PORT = 25678;
private static final Path PID_FILE = Path.of(
System.getProperty("java.io.tmpdir"),
SingletonApplication.class.getName() + ".lock");
private final JFrame window;
private void monitorMessages() {
try (ServerSocket service = new ServerSocket(MESSAGE_PORT)) {
Files.writeString(PID_FILE,
String.valueOf(ProcessHandle.current().pid()));
while (true) {
try (Socket connection = service.accept();
BufferedReader reader = new BufferedReader(
new InputStreamReader(
connection.getInputStream(),
StandardCharsets.UTF_8))) {
reader.readLine();
EventQueue.invokeLater(() -> show());
}
}
} catch (IOException e) {
logger.log(Level.WARNING, "Message service failed.", e);
} finally {
try {
Files.deleteIfExists(PID_FILE);
} catch (IOException e) {
logger.log(Level.WARNING,
"Could not delete file \"" + PID_FILE + "\".", e);
}
}
}
public SingletonApplication() {
JLabel label = new JLabel(
String.valueOf(ProcessHandle.current().pid()));
label.setBorder(BorderFactory.createEmptyBorder(150, 150, 150, 150));
window = new JFrame("Singleton Application");
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.getContentPane().add(label);
window.pack();
window.setLocationByPlatform(true);
}
private void show() {
window.setVisible(true);
window.toFront();
window.requestFocus();
}
private static boolean messageExistingInstance() {
if (Files.isReadable(PID_FILE)) {
try (Socket messageChannel =
new Socket(InetAddress.getLocalHost(), MESSAGE_PORT);
BufferedWriter writer = new BufferedWriter(
new OutputStreamWriter(
messageChannel.getOutputStream(),
StandardCharsets.UTF_8))) {
writer.write("start");
} catch (IOException e) {
logger.log(Level.ERROR,
"Could not message existing instance.", e);
return false;
}
return true;
}
return false;
}
public static void main(String[] args) {
if (!messageExistingInstance()) {
EventQueue.invokeLater(() -> {
SingletonApplication application = new SingletonApplication();
application.show();
Thread monitorThread =
Thread.startVirtualThread(application::monitorMessages);
Runtime.getRuntime().addShutdownHook(
new Thread(monitorThread::interrupt));
});
}
}
}