简体   繁体   中英

Restrict multiple instances of an application in java

I want to prevent multiple instances of application being launched in java. I know 2 methods for this:

  1. locking file
  2. locking socket

But which is one is more efficient and good to use? Which one should I use?

Any other solution to do the same are also welcome.

There is a library called jUnique which does that and will save you the bother of implementing it yourself.

If you deploy with Java WebStart the SingleInstanceService does this.

See http://download.oracle.com/javase/6/docs/technotes/guides/javaws/developersguide/faq.html#218

My vote goes to locking on a port (i think this is what you mean by socket). I don't know the exact reason for this. But in fact i come across only this as a solution in most practical projects. Though i will be happy to hear the alternative ways.

In response to your question, the port solution will keep more resources from the machine:
- You will keep a port locked : ports are limited and you may find problems with firewalls or other programs listening on the same port.
- You'll need an active thread .

The file solution will use less resources from the machine, to avoid locking the file forever you need to add a thread, to delete the file, in the addShutdownHook method from Runtime.

EDIT: I tried that with Win200864b(version isn't important) and alive JFrame and move toFront() or Iconified in SystemTray with JFrame.DO_NOTHING_ON_CLOSE

    public interface ApplicationStartedListener {

        void applicationStarted();

        void foreignApplicationStarted(String name);

        void messageArrived(Object obj);
    }

//

    import java.io.Serializable;

    public class ClassCheck implements Serializable {

        private static final long serialVersionUID = 1L;
        private String className = null;

        public ClassCheck() {
        }

        public ClassCheck(String className) {
            setClassName(className);
        }

        @Override
        public String toString() {
            return this.className;
        }

        public String getClassName() {
            return this.className;
        }

        public void setClassName(String className) {
            this.className = className;
        }
    }
//

    import java.awt.AWTException;
    import java.awt.BorderLayout;
    import java.awt.Frame;
    import java.awt.MouseInfo;
    import java.awt.Point;
    import java.awt.Robot;
    import java.awt.event.InputEvent;
    import java.io.File;
    import javax.swing.JFrame;
    import javax.swing.JTextField;
    import javax.swing.SwingUtilities;

    public class RunOnceFromFile {

        private SingleInstanceController sic = null;
        private JFrame frame;
        private Robot r;
        private JTextField tf;

        public RunOnceFromFile() {
            try {
                r = new Robot();
            } catch (AWTException ex) {
                ex.printStackTrace();
            }
            sic = new SingleInstanceController(new File(System.getProperty("java.io.tmpdir") + "Example.file"), "sic_example_application");
            if (sic.isOtherInstanceRunning()) {
                sic.sendMessageToRunningApplication("toFront");
                System.exit(0);
            } else {
                frame = new JFrame("TEST");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setSize(400, 300);
                tf = new JTextField("JTextFiled");
                frame.add(tf, BorderLayout.NORTH);
                frame.setExtendedState(Frame.ICONIFIED);
                frame.setExtendedState(Frame.NORMAL);
                frame.setExtendedState(frame.getExtendedState() | JFrame.ICONIFIED);
                frame.setExtendedState(frame.getExtendedState() & (~JFrame.ICONIFIED));
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
                sic.registerApplication();
                sic.addApplicationStartedListener(new ApplicationStartedListener() {

                    public void applicationStarted() {
                        Runnable doRun = new Runnable() {

                            public void run() {
                                frame.toFront();
                            }
                        };
                        SwingUtilities.invokeLater(doRun);
                    }

                    public void foreignApplicationStarted(final String name) {
                        Runnable doRun = new Runnable() {

                            public void run() {
                                frame.toFront();
                            }
                        };
                        SwingUtilities.invokeLater(doRun);
                    }

                    public void messageArrived(final Object obj) {
                        Runnable doRun = new Runnable() {//activateWindow(frame);

                            public void run() {
                                frame.toFront();
                            }
                        };
                        SwingUtilities.invokeLater(doRun);
                    }

                    private void activateWindow(JFrame frame) {
                        frame.setExtendedState(Frame.ICONIFIED);
                        frame.setExtendedState(Frame.NORMAL);
                        frame.setAlwaysOnTop(true);
                        frame.setAlwaysOnTop(false);
                        Point location = MouseInfo.getPointerInfo().getLocation();
                        Point locationOnScreen = frame.getLocationOnScreen();
                        r.mouseMove(locationOnScreen.x + 100, locationOnScreen.y + 10);
                        r.mousePress(InputEvent.BUTTON1_MASK);
                        r.mouseRelease(InputEvent.BUTTON1_MASK);
                        r.mouseMove(location.x, location.y);
                    }
                });
            }
        }

        public static void main(String[] args) {
            RunOnceFromFile roff = new RunOnceFromFile();
        }
    }
//

    import java.io.BufferedReader;
    import java.io.BufferedWriter;
    import java.io.File;
    import java.io.FileReader;
    import java.io.FileWriter;
    import java.io.IOException;
    import java.io.ObjectInputStream;
    import java.io.ObjectOutputStream;
    import java.net.ServerSocket;
    import java.net.Socket;
    import java.util.ArrayList;

    public class SingleInstanceController {

        private String appname = null;
        private Socket client = null;
        private File file = null;
        private ArrayList<ApplicationStartedListener> listener = null;
        private ObjectInputStream ois = null;
        private ObjectOutputStream oos = null;
        private boolean result = false;
        private ServerSocket server = null;

        public SingleInstanceController(String appname) {
            this(new File(System.getProperty("java.io.tmpdir") + "/923jhakE53Kk9235b43.6m7"), appname);
        }

        public SingleInstanceController(File file, String appname) {
            this.file = file;
            this.appname = appname;
            this.listener = new ArrayList<ApplicationStartedListener>();
        }

        public void addApplicationStartedListener(ApplicationStartedListener asl) {
            this.listener.add(asl);
        }

        public void removeApplicationStartedListener(ApplicationStartedListener asl) {
            this.listener.remove(asl);
        }

        public boolean isOtherInstanceRunning() {
            if (!this.file.exists()) {
                return false;
            }
            return sendMessageToRunningApplication(new ClassCheck(this.appname));
        }

        public boolean sendMessageToRunningApplication(final Object obj) {
            this.result = false;
            try {
                this.client = new Socket("localhost", getPortNumber());
                new Thread(new Runnable() {

                    public void run() {
                        try {
                            SingleInstanceController.this.oos = new ObjectOutputStream(SingleInstanceController.this.client.getOutputStream());
                            SingleInstanceController.this.ois = new ObjectInputStream(SingleInstanceController.this.client.getInputStream());
                            SingleInstanceController.this.oos.writeObject(obj);
                            SingleInstanceController.this.oos.flush();
                            SingleInstanceController.this.result = SingleInstanceController.this.ois.readBoolean();
                        } catch (IOException e) {
                            SingleInstanceController.this.result = false;
                        }
                    }
                }).start();
                for (int i = 0; i < 10; i++) {
                    if (this.result == true) {
                        break;
                    }
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                this.client.close();
                return this.result;
            } catch (IOException e) {
                return false;
            }
        }

        public boolean registerApplication() {
            try {
                if (!this.file.exists()) {
                    if (!this.file.getParentFile().mkdirs() && !this.file.getParentFile().exists()) {
                        return false;
                    }
                    if (!this.file.createNewFile()) {
                        return false;
                    }
                }
                BufferedWriter wuffy = new BufferedWriter(new FileWriter(this.file));
                int port = getFreeServerSocket();
                if (port != -1) {
                    startServer();
                }
                wuffy.write(String.valueOf(port));
                wuffy.close();
                return true;
            } catch (IOException e) {
                return false;
            }
        }

        protected void messageArrived(Object obj) {
            for (ApplicationStartedListener asl : this.listener) {
                asl.messageArrived(obj);
            }
        }

        protected void applicationStartet() {
            for (ApplicationStartedListener asl : this.listener) {
                asl.applicationStarted();
            }
        }

        protected void foreignApplicationStarted(String name) {
            for (ApplicationStartedListener asl : this.listener) {
                asl.foreignApplicationStarted(name);
            }
        }

        private int getPortNumber() {
            try {
                BufferedReader buffy = new BufferedReader(new FileReader(this.file));
                int port = Integer.parseInt(buffy.readLine().trim());
                buffy.close();
                return port;
            } catch (Exception e) {
                return -1;
            }
        }

        private void startServer() {
            new Thread(new Runnable() {

                public void run() {
                    while (true) {
                        try {
                            SingleInstanceController.this.client = SingleInstanceController.this.server.accept();
                            if (SingleInstanceController.this.client.getInetAddress().isLoopbackAddress()) {
                                new Thread(new Runnable() {

                                    public void run() {
                                        try {
                                            SingleInstanceController.this.oos = new ObjectOutputStream(SingleInstanceController.this.client.getOutputStream());
                                            SingleInstanceController.this.ois = new ObjectInputStream(SingleInstanceController.this.client.getInputStream());
                                            Object obj = SingleInstanceController.this.ois.readObject();
                                            if (obj instanceof ClassCheck) {
                                                if (obj.toString().equals(SingleInstanceController.this.appname)) {
                                                    SingleInstanceController.this.oos.writeBoolean(true);
                                                    applicationStartet();
                                                } else {
                                                    SingleInstanceController.this.oos.writeBoolean(false);
                                                    foreignApplicationStarted(obj.toString());
                                                }
                                            } else {
                                                messageArrived(obj);
                                                SingleInstanceController.this.oos.writeBoolean(true);
                                            }
                                            SingleInstanceController.this.oos.flush();
                                            SingleInstanceController.this.client.close();
                                        } catch (IOException e) {
                                            e.printStackTrace();
                                        } catch (ClassNotFoundException e) {
                                            e.printStackTrace();
                                        }
                                    }
                                }).start();
                            }
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }).start();
        }

        private int getFreeServerSocket() {
            for (int i = 2000; i < 10000; i++) {
                try {
                    this.server = new ServerSocket(i);
                    return i;
                } catch (IOException ignore) {
                }
            }
            return -1;
        }
    }

I know that this question is pretty old, but I have to solve the same problem at the moment. I prefer the socket solution because I have never thought that such kind of task should have anything to do with the file system. It is better to solve the problem in memory and not in the file system I think.

the serversocket solution is cross-platform. And will not be vulnerable to the program crashing and not resetting the lock.

File lock is better way to do- imo. When you create the file in User's Home directory, this will still work in a multi-user environment.

I came across - JUnique - haven't had a chance to use it http://www.sauronsoftware.it/projects/junique/manual.php

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM