在java中限制应用程序的多个实例

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

  1. 锁定文件
  2. 锁定sockets

但哪一种更有效,更好用? 我应该使用哪一个?

任何其他做同样的解决方案也是受欢迎的。

编辑:我尝试使用Win200864b(版本并不重要)和活着的JFrame并使用JFrame.DO_NOTHING_ON_CLOSE移动到前台()或在SystemTray中图标化

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

有一个名为jUnique的库可以帮助您自己实现它。

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

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

我的投票是锁定一个端口(我认为这是你的意思是socket)。 我不知道确切的原因。 但事实上,在大多数实际项目中,我只是将其作为解决方案。 虽然我很乐意听到其他方式。

为了回答您的问题,端口解决方案将从机器中获取更多资源:
您将保持端口锁定 :端口有限,您可能会发现防火墙或其他程序在同一端口上侦听时出现问题。
你需要一个活跃的线程

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

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

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

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

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