【问题标题】:Restrict multiple instances of an application in java在java中限制应用程序的多个实例
【发布时间】:2011-09-02 08:15:47
【问题描述】:

我想防止在 java 中启动多个应用程序实例。我知道两种方法:

  1. 锁定文件
  2. 锁定插座

但哪一种更高效且好用?我应该使用哪一个?

也欢迎任何其他相同的解决方案。

【问题讨论】:

  • 哪个文件?哪个插座?什么对应用最有意义?
  • @jcomeau_ictx: 可以使用任何可用的文件/任何套接字。

标签: java swing multiple-instances single-instance


【解决方案1】:

有一个名为 jUnique 的库可以做到这一点,并且可以省去您自己实现它的麻烦。

【讨论】:

  • 我可以在未经任何许可或必须购买的情况下将 jUnique 嵌入我的应用程序吗?
  • 作者声明它是免费的,但如果你觉得它有用就请求捐赠。看起来很合理。
【解决方案2】:

我知道这个问题已经很老了,但我现在必须解决同样的问题。我更喜欢套接字解决方案,因为我从来没有想过这种任务应该与文件系统有任何关系。我认为最好在内存而不是文件系统中解决问题。

【讨论】:

    【解决方案3】:

    编辑:我尝试使用 Win200864b(版本不重要)和活动的 JFrame 并使用 JFrame.DO_NOTHING_ON_CLOSE 在 SystemTray 中移动 toFront() 或 Iconified

        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;
            }
        }
    

    【讨论】:

    • 这一切有什么作用?
    • 当我关闭单个正在运行的实例时会发生什么?用于锁定的文件当时不会被删除。而且在运行时文件也没有正确锁定,因为用户可以通过进入临时目录来删除文件。
    • @Harry Joy "用户可以通过进入临时目录删除文件" 是的,这是正确的,因为并非所有 PC 用户都具有操作系统的管理员访问权限,您必须检查 ServerSocket 的工作原理
    • @mKorbel:调用sendMessageToRunningApplication("toFront")有什么用?它有什么作用?
    • @Harry Joy 如果文件(如果 JVM 存在)被 ServerSocket 锁定,则通知已经运行的应用程序(如果设置 JFrame.DO_NOTHING_ON_CLOSE,则必须添加 frame.set*Visibel(true),太) frame.toFront();
    【解决方案4】:

    针对您的问题,端口解决方案将保留更多机器资源:
    - 您将锁定端口:端口有限,您可能会发现防火墙或其他程序在同一端口上侦听的问题。
    - 你需要一个活跃的线程

    文件解决方案将使用更少的机器资源,为了避免永远锁定文件,您需要在运行时的addShutdownHook 方法中添加线程,删除文件。

    【讨论】:

      【解决方案5】:

      文件锁定是更好的方法。当您在用户的主目录中创建文件时,这仍然适用于多用户环境。

      我遇到了 - JUnique - 还没有机会使用它 http://www.sauronsoftware.it/projects/junique/manual.php

      【讨论】:

        【解决方案6】:

        serversocket 解决方案是跨平台的。并且不会受到程序崩溃和不重置锁的影响。

        【讨论】:

          【解决方案7】:

          如果您使用 Java WebStart 进行部署,SingleInstanceService 会执行此操作。

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

          【讨论】:

            【解决方案8】:

            我的投票是锁定端口(我认为这就是您所说的套接字)。我不知道这个的确切原因。但事实上,在大多数实际项目中,我只是将此作为解决方案。虽然我很乐意听到其他方法。

            【讨论】:

            • 一旦应用程序启动,锁定一个 Socket 就没有任何开销。它使用大约 4 行代码。优点是第二个实例可以与第一个实例进行通信,例如假设你想用第二个实例打开一个文件,它可以在退出之前向第一个实例发送消息以打开文件。
            猜你喜欢
            • 2010-11-15
            • 1970-01-01
            • 2011-06-26
            • 1970-01-01
            • 1970-01-01
            • 2011-10-25
            • 2011-05-04
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多