How to make sure that only one instance of a Java application is running?

I want my application to check if another version is already running.

For example, demo.jar started, the user presses a button to start it again, but the second instance implements "oh wait, demo.jar already running". and terminates the message.

+8
java mutex
May 09 '12 at 1:46 am
source share
12 answers

What you are looking for is perhaps best done with a lock file. In the lock file, I just mean a file that will have a predefined location and whose existence is your mutex.

Check if this file exists at the start of your program; if this happens, exit immediately. Create a file in a known place. If your program completed normally, delete the lock file.

It is probably best if you can also fill in the file using pid (process identifier) ​​so that you can detect abnormal outputs that did not delete the file, but it depends on the particular OS.

+5
May 9 '12 at 1:52 AM
source share

Force use of one instance of a program that works with ServerSocket lock

Java code. Put this in the Main.java file:

 import java.net.*; import java.io.*; public class Main{ public static void main(String args[]){ ServerSocket socket = null; try { socket = new ServerSocket(34567); System.out.println("Doing hard work for 100 seconds"); try{ Thread.sleep(100000); } catch(Exception e){ } socket.close(); } catch (IOException ex) { System.out.println("App already running, exiting..."); } finally { if (socket != null) try{ socket.close(); } catch(Exception e){} } } } 

Compile and run

 javac Main.java java Main 

Test it in the normal case:

Run the program. You have 100 seconds to run the program in another terminal again, and it will fail, saying that it already works. Then wait 100 seconds, this should allow you to run it in the 2nd terminal.

Test it after forcibly stopping the program with kill -9

  • Run the program in terminal 1.
  • kill -9, which is processed from another terminal for 100 seconds.
  • Run the program again, it can be started.

Output:

Socket rotation is cleared by the operating system when your program no longer works. Therefore, you can be sure that the program will not work twice.

disadvantages

If some vile person or some naughty process had to bind all the ports or only your port, then your program will not work, because it thinks that it is already working.

+9
Aug 14 '14 at 19:45
source share

A simple but powerful tested solution.

  static File file; static FileChannel fileChannel; static FileLock lock; static boolean running = false; @SuppressWarnings("resource") public static boolean checkIfAlreadyRunning() throws IOException { file = new File(FilePath.FILEPATH + "az-client.lock"); if (!file.exists()) { file.createNewFile(); running = true; } else { file.delete(); } fileChannel = new RandomAccessFile(file, "rw").getChannel(); lock = fileChannel.tryLock(); if (lock == null) { fileChannel.close(); return true; } ShutdownHook shutdownHook = new ShutdownHook(); Runtime.getRuntime().addShutdownHook(shutdownHook); return running; } public static void unlockFile() { try { if (lock != null) lock.release(); fileChannel.close(); file.delete(); running = false; } catch (IOException e) { e.printStackTrace(); } } static class ShutdownHook extends Thread { public void run() { unlockFile(); } } 

Put these methods in some Util class, and before starting your main class, just check that if it already exists, then show some dialog box for another user starting the application. It works even if you anonymously close the Java process or what you do. It is durable and efficient, no need to tune DataGram listeners or anything else ...

+5
Nov 16 '13 at 7:01
source share

The strategy of this code is to maintain the PID from the last run in the registry, if this PID is found in the system, do not run it. If you are done, reset.

Settings are saved in the Windows HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Prefs at HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Prefs

 import java.io.*; import java.util.prefs.Preferences; public class JavaApplication3 { public static void main(String[] args){ if(isRunning()){ System.out.println("Two instances of this program cannot " + "be running at the same time. Exiting now"); } else{ onStart(); epicHeavyWorkGoesHere(); onFinish(); } } public static void epicHeavyWorkGoesHere(){ try { Thread.sleep(15000); } catch (InterruptedException ex) {} } public static void onStart(){ Preferences prefs = Preferences.systemRoot().node("JavaApplication3"); prefs.put("RUNNINGPID", getCurrentPID()); } public static void onFinish(){ Preferences prefs = Preferences.systemRoot().node("JavaApplication3"); prefs.put("RUNNINGPID", ""); } public static boolean isRunning(){ Preferences prefs = Preferences.systemRoot().node("JavaApplication3"); if (prefs.get("RUNNINGPID", null) == null || prefs.get("RUNNINGPID", null).equals("")) return false; if (isProcessIdRunningOnWindows(Integer.parseInt(prefs.get("RUNNINGPID", null)))) return true; return false; } public static String getCurrentPID(){ //This function should work with Windows, Linux and Mac but you'll have to //test to make sure. If not then get a suitable getCurrentPID function replacement. try{ java.lang.management.RuntimeMXBean runtime = java.lang.management.ManagementFactory.getRuntimeMXBean(); java.lang.reflect.Field jvm = runtime.getClass().getDeclaredField("jvm"); jvm.setAccessible(true); sun.management.VMManagement mgmt = (sun.management.VMManagement) jvm.get(runtime); java.lang.reflect.Method pid_method = mgmt.getClass().getDeclaredMethod("getProcessId"); pid_method.setAccessible(true); return pid_method.invoke(mgmt) + ""; } catch(Exception e){ throw new RuntimeException("Cannot get the current PID"); } } public static boolean isProcessIdRunningOnWindows(int pid){ //This Function only works for windows, if you want it to work on linux //or mac, you will have to go find a replacement method that //takes the processID as a parameter and spits out a true/false //if it is running on the operating system. try { Runtime runtime = Runtime.getRuntime(); String cmds[] = {"cmd", "/c", "tasklist /FI \"PID eq " + pid + "\""}; Process proc = runtime.exec(cmds); InputStream inputstream = proc.getInputStream(); InputStreamReader inputstreamreader = new InputStreamReader(inputstream); BufferedReader bufferedreader = new BufferedReader(inputstreamreader); String line; while ((line = bufferedreader.readLine()) != null) { if (line.contains(" " + pid + " ")){ return true; } } return false; } catch (Exception ex) { throw new RuntimeException("Cannot run the tasklist command to query if a pid is running or not"); } } } 

If the program freezes and pid remains in the task list, it will be blocked. You can add an additional registry key that saves the last successful run time, and if the run time becomes too long, the saved PID will be killed and the program will restart.

+3
Aug 02 '13 at 3:36
source share

If you use Mutex, it is logical that Mutex should be accessible from any JVM on which a copy of the "program" was running. In C programming, this can be done via shared memory, but by default Java does not.

With this understanding, there are many ways to realize what you want. You can open the server socket on the designated port (the operating system ensures that only one process is the recipient of the server socket, and subsequent ones fail).

You can use a β€œlock file”, but it’s a bit complicated, since the file you need to use will really be a directory (and it greatly depends on whether the creation of the directory is atomic for your file system, although most of the creation of the directory). If the system administrator decides to run you through NFS, things get even more complicated (if not impossible).

You can also do some great tricks with the JVM and debugging / JMI if you can somehow make sure that all the relevant JVMs start with the same configurations (over time, an impossible task).

Other people used the exec tool to execute the equivalent of a list of processes, but this is a bit complicated due to the possibility of a race condition (two processes check at the same time and cannot see each other).

In the end, the server socket route is probably the most stable, since it is guaranteed to communicate with only one process by the TCP / IP stack (and is mediated by the operating system). However, you will need to clear the socket of incoming messages, and this will open up the possibility of other security problems.

+2
May 9 '12 at 1:59 a.m.
source share

If your application runs on Windows, you can call CreateMutex through the JNI.

 jboolean ret = FALSE; HANDLE hMutex = CreateMutex(NULL, FALSE, mutexName); ret = TRUE; if(WAIT_TIMEOUT == WaitForSingleObject(hMutex, 10)) { ret = FALSE; } else if(GetLastError() != 0) { ret = FALSE; } 

This returns true if no one is using this mutex, otherwise false. You could provide "myApplication" as the name of the mutex or "Global \ MyApplication" if you want your mutex to be shared across all Windows sessions.

Edit: this is not as difficult as it seems :), and I find it clean.

+2
May 09 '12 at 2:00
source share

Here is one method that uses an automatically named lock file in the user's home directory. The name is based on where the bank comes from.

 import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.RandomAccessFile; import java.nio.channels.FileChannel; public class SingleInstance { @SuppressWarnings("resource") public static boolean isAlreadyRunning() { File file; FileChannel fileChannel; File userDir = new File(System.getProperty("user.home")); file = new File(userDir, myLockName()); if (!file.exists()) { try { file.createNewFile(); file.deleteOnExit(); } catch (IOException e) { throw new RuntimeException("Unable to create Single Instance lock file!", e); } } try { fileChannel = new RandomAccessFile(file, "rw").getChannel(); } catch (FileNotFoundException e) { throw new RuntimeException("Single Instance lock file vanished!", e); } try { if (fileChannel.tryLock() != null) { return false; } } catch (Exception e) { } try { fileChannel.close(); } catch (IOException e1) { } return true; } private static String myLockName() { return "." + SingleInstance.class.getProtectionDomain().getCodeSource().getLocation().getPath() .replaceAll("[^a-zA-Z0-9_]", "_"); } } 
+1
Aug 01 '16 at 16:21
source share

Unlike several other answers, the most reliable method is to create a ServerSocket on a fixed port, known only to you, the way up the drawing cards. It will be automatically released when your application exits, unlike any lock file, and its previous existence through BindException is a pretty infallible sign that another instance is already running.

0
Nov 16 '13 at 7:20
source share

The following solution works in two deadly scenerio too. 1> Even your running exe is scheduled as javaw.exe in the task manager. 2> You can install the application in two places and from launching both places in which it also works.

 String tempDir = System.getProperty("java.io.tmpdir");// dependent to OS find any tem dir. String filePath = tempDir + "lockReserverd.txt"; try { final File file = new File(filePath); if(file.exists()) return false; 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) { //log.error("Unable to remove lock file: " + lockFile, e); } } }); return true; } } catch (Exception e) { //log.Error("Unable to create and/or lock file"); } return false 

or

This will work if your application.exe is listed in the task manager

 "tasklist /FI \"IMAGENAME eq "+MyApplication+".exe 
0
Sep 11 '14 at 6:55
source share

It is also a good solution if your application can be run in the task manager with a unique name.

  "tasklist /FI \"IMAGENAME eq "+MyApplication+".exe 
0
Sep 11 '14 at 7:29
source share

Testing PID Lock and File Lock Method

We can write the process ID of the process that created the lock file to the file. When we encounter an existing lock file, we do not just leave, but check if the process is alive with this identifier. If not, create a new instance of the application. I think MongoDB uses this technique.

  static File file; static FileChannel fileChannel; static FileLock lock; static boolean running = false; static String currentPID = null; static String lockFilePID = null; public static final String USER_DIR = System.getProperty("user.dir"); public static final String LOCK_FILE = "az-client.lock"; public static boolean checkInstance() { try { file = new File(USER_DIR + File.separator + LOCK_FILE); currentPID = Integer.toString(getCurrentPID()); if (!file.exists()) { file.createNewFile(); writePID(currentPID); lockFile(); addShudDownHook(); running = true; return running; } else { if (isFileLocked()) { syso("App already running"); System.exit(0); } else { lockFilePID = getPIDFromLockFile(); if (isProcessIdRunningOnWindows(Integer.parseInt(lockFilePID))) { lockFile(); addShudDownHook(); running = true; return running; } else { file.delete(); file.createNewFile(); writePID(currentPID); lockFile(); addShudDownHook(); running = true; return running; } } } } catch (Exception e) { syso(e + "App already running"); System.exit(0); } return running; } /** * * @return * @throws IOException */ @SuppressWarnings("resource") private static boolean isFileLocked() throws IOException { fileChannel = new RandomAccessFile(file, "rw").getChannel(); lock = fileChannel.tryLock(); if (lock == null) { fileChannel.close(); fileChannel = null; return true; } else { lock.release(); fileChannel.close(); fileChannel = null; } return false; } public static int getCurrentPID() { // This function should work with Windows, Linux and Mac but you'll have // to // test to make sure. If not then get a suitable getCurrentPID function // replacement. try { java.lang.management.RuntimeMXBean runtime = java.lang.management.ManagementFactory.getRuntimeMXBean(); java.lang.reflect.Field jvm = runtime.getClass().getDeclaredField("jvm"); jvm.setAccessible(true); sun.management.VMManagement mgmt = (sun.management.VMManagement) jvm.get(runtime); java.lang.reflect.Method pid_method = mgmt.getClass().getDeclaredMethod("getProcessId"); pid_method.setAccessible(true); return (int) pid_method.invoke(mgmt); } catch (Exception e) { throw new RuntimeException("Cannot get the current PID"); } } public static boolean isProcessIdRunningOnWindows(int pid) { // This Function only works for windows, if you want it to work on linux // or mac, you will have to go find a replacement method that // takes the processID as a parameter and spits out a true/false // if it is running on the operating system. try { Runtime runtime = Runtime.getRuntime(); String cmds[] = { "cmd", "/c", "tasklist /FI \"PID eq " + pid + "\"" }; Process proc = runtime.exec(cmds); InputStream inputstream = proc.getInputStream(); InputStreamReader inputstreamreader = new InputStreamReader(inputstream); BufferedReader bufferedreader = new BufferedReader(inputstreamreader); String line; while ((line = bufferedreader.readLine()) != null) { if (line.contains(" " + pid + " ")) { return true; } } return false; } catch (Exception ex) { throw new RuntimeException("Cannot run the tasklist command to query if a pid is running or not"); } } /** * This method write PID to Lock file * * @param pid * @throws Exception */ private static void writePID(String pid) throws Exception { try { // To Do write PID to LockFile } catch (Exception e) { syso(e); throw e; } } /** * This method return PID from Lock File * * @return * @throws Exception */ private static String getPIDFromLockFile() throws Exception { try { return //To Do getPID from File } catch (Exception e) { syso(e); throw e; } } private static void addShudDownHook() { try { ShutdownHook shutdownHook = new ShutdownHook(); Runtime.getRuntime().addShutdownHook(shutdownHook); } catch (Exception e) { LogWriter.logger.error(e); } } private static void unlockFile() { try { if (lock != null) { lock.release(); } fileChannel.close(); file.delete(); running = false; } catch (IOException e) { syso(e); } } private static void lockFile() { try { fileChannel = new RandomAccessFile(file, "rw").getChannel(); lock = fileChannel.tryLock(); if (lock == null) { fileChannel.close(); fileChannel = null; } } catch (IOException e) { syso(e); } } static class ShutdownHook extends Thread { public void run() { unlockFile(); } } 
0
Sep 15 '14 at 8:31
source share

FileLock does not work on Linux. Please do not use FileLock. I think getting a process name (by creating a unique name, if possible) would be a way to solve this problem. I think the process id is automatically assigned.

Refer to this when getting the process:

http://www.itechp2pexchange.com/content/linux-unix-run-only-one-instance-script

-one
Jul 11 2018-12-12T00:
source share



All Articles