Start Java program only if not already running

I provide two answers, one for Linux:

Don't run the program if it's already running, put this in a file called Main.java

import java.io.File;
import java.io.RandomAccessFile;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;

class JustOneLock {
  FileLock lock;
  FileChannel channel;

  public boolean isAppActive() throws Exception{
    File file = new File(System.getProperty("user.home"),
            "FireZeMissiles1111" + ".tmp");
    channel = new RandomAccessFile(file, "rw").getChannel();

    lock = channel.tryLock();
    if (lock == null) {
      return true;
    }
    Runtime.getRuntime().addShutdownHook(new Thread() {
      public void run() {
        try {
          lock.release();
          channel.close();
        } catch (Exception e) {
          e.printStackTrace();
        }
      }
    });
    return false;
  }
}

public class Main {
  public static void main(String[] args)throws Exception {
    JustOneLock u = new JustOneLock();

    if (u.isAppActive()) {
      System.out.println("Already active, stop!");
      System.exit(1);
    }
    else {
      System.out.println("NOT active... Do hard work for 5 seconds.");
      try{Thread.sleep(5000);}catch(Exception e){}
    }
  }
}

Compile it and run it. Then open a new terminal and try to run it again while the other is running and it won't.

Another answer for Windows

This program will not allow itself to be run if it is already running on the current system. This is for windows only systems.

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(5000);
        } 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 is designed to get the PID from the windows system, it may
        //not work for Linux or Mac.  You'll have to acquire a suitable getCurrentPID function
        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
        //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 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");
        }
    }
}

The strategy of the above code is to keep the PID around from the last run, if that PID is found running on the system, don't start. If you finish, reset.

The preferences are stored on Windows Registry in HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Prefs

I advise against using File Locking to make sure a java application doesn't run twice at the same time because if the program crashes or hangs forever and is killed, then the lock is left in an inconsistent state and perhaps may even survive a reboot which will cause problems because how will the program know the difference between a program which is still running and a program that has crashed and left the locked file locked?


In order to avoid potential lock file / crash issues, it is possible to start a server and catch the port collision. These servers are automatically stopped on system shutdown (Even after a crash)

public static ServerSocket ss;

public static void main (String[] args) {

    ss = null;

    try {
        ss = new ServerSocket(1044);
    } catch (IOException e) {
        System.err.println("Application already running!");
        System.exit(-1);
    }
}

I'm guessing you don't have control over the other two apps... If you did, this wouldn't be too bad--you could just have them listen to a socket and see if the socket is available when you come up.

The next solution may actually be language independent. You could manage the whole system through batch file wrappers. Write a batch file that creates a file when it starts up and deletes it when it stops. Unix systems use this technique a lot--they call the file a lock file more often than not.

If only your app will ever start these other apps, then you could simply track if you've started it or not, so I'm guessing this isn't possible or you wouldn't be asking, so I'm assuming that the user may have launched these programs through some other mechanism.

If you have NO control over the launching of the other apps and can't even write a batch file to launch them, then you just can't do what you want to do (Note, the apps would have to always use the batch file, even if the user started them by hand).

I just a very-last ditch effort might be to get a process status and parse it, but you'd have to know exactly what the other apps were called in the PS, this isn't really trivial. Also, all java apps tend to have the same exact signature in most process status printouts which could make this useless.

The problem is that if one of these programs were started outside your app, you have virtually NO WAY to identify that fact unless you happen to know it's exact process status signature, and even then it's flaky.