Closed Mr-YiQiJia closed 6 months ago
Launch4j's singleInstance
property is not supported by JavaPackager, but maybe you can try this pure Java solution (cross-platform) from SO:
public class Main {
public static boolean lockInstance(final String lockFile) {
try {
final File file = new File(lockFile);
final RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rw");
final FileLock fileLock = randomAccessFile.getChannel().tryLock();
if (fileLock != null) {
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() {
try {
fileLock.release();
randomAccessFile.close();
file.delete();
} catch (Exception e) {
System.err.println("Unable to remove lock file: " + lockFile);
e.printStackTrace();
}
}
});
return true;
}
} catch (Exception e) {
System.err.println("Unable to create and/or lock file: " + lockFile);
e.printStackTrace();
}
return false;
}
public static void main(String[] args) throws IOException {
if (lockInstance(System.getProperty("java.io.tmpdir") + File.separator + Main.class.getName() + ".lock")) {
HelloWorldFrame.main(args);
}
}
}
I've just tried it and it seems to be working fine and is valid for all platforms, not only Windows.
Anyway, we can add support for Launch4j's singleInstance
in JP if you really need it.
This solution works for me:
private static final int PORT = <WhateverPortYouWant>;
private static final String HOST = "localhost";
private ServerSocket serverSocket;
private Thread serverThread;
public static void main(String[] args) {
try (Socket socket = new Socket(HOST, PORT)) {
System.out.println("Application already running");
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
oos.writeObject("bringToFront");
oos.flush();
ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
ois.readObject();
oos.close();
ois.close();
socket.close();
System.exit(0);
} catch (Exception e) {
launch(args);
}
}
@Override
public void start(Stage stage) {
startServer();
// your code here for your stage
}
private void startServer() {
try {
serverSocket = new ServerSocket(PORT);
serverThread = new Thread(() -> {
while (!serverThread.isInterrupted()) {
try (Socket clientSocket = serverSocket.accept();
ObjectInputStream in = new ObjectInputStream(clientSocket.getInputStream());
ObjectOutputStream out = new ObjectOutputStream(clientSocket.getOutputStream())) {
Object message = in.readObject();
if ("bringToFront".equals(message)) {
Platform.runLater(() -> {
primaryStage.show();
primaryStage.toFront();
});
}
out.writeObject("done");
} catch (IOException | ClassNotFoundException e) {
// Handle exception
System.exit(0);
break;
}
}
});
serverThread.start();
// Add shutdown hook to close the server socket and interrupt the thread
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
try {
if (serverThread != null)
serverThread.interrupt();
if (serverSocket != null)
serverSocket.close();
} catch (IOException e) {
// Handle exception
System.exit(0);
}
}));
} catch (BindException e) {
// Close second instance
System.exit(0);
} catch (IOException e) {
System.out.println("Failed to start server socket");
System.exit(0);
}
}
The current requirement for the program is to have multiple instances. If the program is required to have a single instance in the future, it would be very convenient to have a simple setting. But it's not necessary, it's just an idea. Your ideas are very good, and I can refer to your ideas. Thank you very much for providing me with help @fvarrui @valimaties
I'm submitting a…
What is the expected behavior? I want my program to run as a single instance, double clicking again to display the previous running instance What is the current behavior? Each time you double-click to run the program, it will open another instance Do you have outputs, screenshots, demos or samples which demonstrate the problem or enhancement?
What is the motivation / use case for changing the behavior? I want to control the excessive opening of the program Please tell us about your environment: