如何确保只能执行一个java程序实例?

需要在某个时间只能执行一个JAVA程序实例。 我在不同的早期post中观察到了堆栈溢出中提出的大量解决方案。

解决方案基于:

  • 通过打开套接字:打开套接字连接。
  • 基于文件锁定:创建临时文件并保持锁定。 并在JVM关闭时添加一个关闭钩子来解锁该文件。

我不想使用端口锁定,因为它可能导致端口使用可能发生冲突。

所以我在考虑使用文件锁定。 在搜索了一下之后,我发现基于端口锁定的机制的支持者已经提到如果应用程序崩溃和其他IO错误,文件锁定可能是不可靠的。

我需要的是找到一个在跨平台和多个JDK中一致工作的解决方案。 我的平台是Windows和Linux,JDK是Sun和IBM JDK。

任何人都可以对此有所了解吗?

您可以使用ManagementFactory对象。 从这里 : –

import sun.management.ConnectorAddressLink; import sun.jvmstat.monitor.HostIdentifier; import sun.jvmstat.monitor.Monitor; import sun.jvmstat.monitor.MonitoredHost; import sun.jvmstat.monitor.MonitoredVm; import sun.jvmstat.monitor.MonitoredVmUtil; import sun.jvmstat.monitor.MonitorException; import sun.jvmstat.monitor.VmIdentifier; public static void main(String args[]) { /* The method ManagementFactory.getRuntimeMXBean() returns an identifier with applcation PID in the Sun JVM, but each jvm may have you own implementation. So in anothers jvm, other than Sun, this code may not work., :( */ RuntimeMXBean rt = ManagementFactory.getRuntimeMXBean(); final int runtimePid = Integer.parseInt(rt.getName().substring(0,rt.getName().indexOf("@"))); java.awt.EventQueue.invokeLater(new Runnable() { public void run() { // If exists another instance, show message and terminates the current instance. // Otherwise starts application. if (getMonitoredVMs(runtimePid)) { new MainFrame().setVisible(true); } else JOptionPane.showMessageDialog(null,"There is another instance of this application running."); } }); } 

getMonitoredVMs(int processPid)方法接收当前应用程序PID的参数,并捕获从命令行调用的应用程序名称,例如,应用程序是从c:\ java \ app \ test.jar路径启动的,然后是值变量是“c:\ java \ app \ teste.jar”。 这样,我们将在下面代码的第17行捕获应用程序名称。 之后,我们在JVM中搜索具有相同名称的antoher进程,如果找到它并且应用程序PID不同,则意味着它是第二个应用程序实例。

 private static boolean getMonitoredVMs(int processPid) { MonitoredHost host; Set vms; try { host = MonitoredHost.getMonitoredHost(new HostIdentifier((String)null)); vms = host.activeVms(); } catch (java.net.URISyntaxException sx) { throw new InternalError(sx.getMessage()); } catch (MonitorException mx) { throw new InternalError(mx.getMessage()); } MonitoredVm mvm = null; String processName = null; try{ mvm = host.getMonitoredVm(new VmIdentifier(String.valueOf(processPid))); processName = MonitoredVmUtil.commandLine(mvm); processName = processName.substring(processName.lastIndexOf("\\") + 1,processName.length()); mvm.detach(); } catch (Exception ex) { } // This line is just to verify the process name. It can be removed. JOptionPane.showMessageDialog(null,processName); for (Object vmid: vms) { if (vmid instanceof Integer) { int pid = ((Integer) vmid).intValue(); String name = vmid.toString(); // default to pid if name not available try { mvm = host.getMonitoredVm(new VmIdentifier(name)); // use the command line as the display name name = MonitoredVmUtil.commandLine(mvm); name = name.substring(name.lastIndexOf("\\")+1,name.length()); mvm.detach(); if ((name.equalsIgnoreCase(processName)) && (processPid != pid)) return false; } catch (Exception x) { // ignore } } } return true; } 

另请检查使用SingleInstanceService服务

javax.jnlp.SingleInstanceService为应用程序提供了一组方法,可以将自己注册为单例,并注册侦听器以处理从不同应用程序实例传入的参数。

如果您熟悉C,则可以使用Windows中的命名管道和unix中的本地套接字来解决此问题。 它们都需要一点JNI。 这些通信通道是应用程序的资源,因此当您的应用程序崩溃时,OS有责任释放您的资源。 此外,它们由文本名称标识,因此名称冲突的可能性与文件锁定相同。

您可以在此stackoverflow答案中拾取本地套接字的示例。

可以在此处找到Windows中命名管道的示例

嗨,有很多方法可以做到这一点,只需访问此页面。 我只是复制粘贴。 也查看此线程[stackoverflow] [1]

Java世界中最受欢迎的问题之一是如何将java应用程序作为单个实例。

我谷歌它,并发现了许多技术。 我在这里发布了一些流行的技巧。 如果您有问题,请继续联系……

  1. 通过捕获端口或通过ServerSocket(短代码)。 在这个方法中,我们创建了一个java.net.ServerSocket类的对象。 通过传递一个端口号,我们在第一个实例时被捕获,这样如果发生了另一个实例,它就会抛出一个绑定exception,你可以跟踪系统上运行的任何实例。

只需查看代码链接http://yuvadevelopers.dmon.com/java_examples/Single_Instance_small.htm

  1. 通过捕获端口或通过ServerSocket(大代码)。 它与第一种方法相同,但谷歌我得到这个大代码与不同的选项只需通过代码。

只需查看代码链接,请参阅此处的原始来源获取来自Google http://www.rbgrn.net/blog/2008/05/java-single-application-instance.html

  1. 通过从本地文件系统访问文件。 这也是做同样事情的另一种方法。 但它并不是那么好,因为有时当JVM崩溃或由于某些IO错误发生时,文件不会从硬盘中删除。 注意: – 不要把你的文件(你可以使用任何文件)放在C盘或OS存在的地方。
    请看下面的代码
 / *
 *用于在JAVA中设置单个实例的程序
 *版权所有2009 @ yuvadeveloper
 *代码: -  Prashant Chandrakar
 *
 * /
 import java.net.ServerSocket;
 import javax.swing.JOptionPane;
 import javax.swing.JFrame;
 import java.io.IOException;
 import java.net.BindException;
 class SingleInstance
 {
   public static ServerSocket serverSocket;
   public static String errortype =“Access Error”;
   public static String error =“应用程序已在运行.....”;
   public static void main(String as [])
   {
    尝试
     {
         //创建服务器套接字的对象并绑定到某个端口号serverSocket = new ServerSocket(15486);
         ////不要像80等那样放普通端口号
         ////因为它们已经被系统使用了
         JFrame jf = new JFrame();
         jf.setVisible(真);
         jf.setSize(200,200);
      }
      catch(BindException exc)
      {
         JOptionPane.showMessageDialog(null,error,errortype,JOptionPane.ERROR_MESSAGE);
         System.exit(0);
      }
      catch(IOException exc)
      {
         JOptionPane.showMessageDialog(null,error,errortype,JOptionPane.ERROR_MESSAGE);
         System.exit(0);
      }
    }
 }
  1. 通过使用tools.jar中的java sun.jvmstat包。

只需查看代码链接即可

  1. 通过使用Launch4j应用程序。 它是为您的应用程序创建EXE的第三方工具。 它为您提供了创建单实例应用程序的function。 去尝试一下。 这是完美的工具。

只需看看launch4j应用程序文档http://launch4j.sourceforge.net/

在unix系统中经常进行的方式是创建一个文件,这是一个primefaces操作,然后检查是否可以创建文件。 如果可以创建该文件,则该进程具有锁定并允许运行。 如果无法创建该文件,则其他人必须拥有该锁,并且该实例会立即终止。 这样的事情的代码

 private boolean lock() { try { final File file=new File("bpmdj.lock"); if (file.createNewFile()) { file.deleteOnExit(); return true; } return false; } catch (IOException e) { return false; } } 

然后在应用程序的主要部分开始

  if (!lock()) { System.out.println("Cannot lock database. Check that no other instance of BpmDj is running and if so, delete the file bpmdj.lock"); return; } 

当然,有两点值得一提。 首先:如果应用程序崩溃很难,那么该文件很可能不会被删除,从而给用户带来一些不便(他需要自己删除锁文件)。

其次: java文档说明如下:

createNewFile以primefaces方式创建一个新的空文件…当且仅当具有此名称的文件尚不存在时。 检查文件是否存在以及文件的创建(如果不存在)是针对可能影响文件的所有其他文件系统活动的primefaces操作。 注意:此方法不应用于文件锁定,因为无法使生成的协议可靠地工作。 应该使用FileLock工具。

特别是最后一个注释很有意思,因为在这种情况下我们并不真正使用它来进行文件锁定,只是为了检查是否存在同一应用程序的其他实例。 然而,我有点好奇理解为什么他们写道’由此产生的协议无法使其工作可靠’

您可以使用JUnique库。 它为运行单实例java应用程序提供支持,并且是开源的。 它基于文件锁,但也使用随机端口来发送/接收来自其他正在运行的java实例的消息。

http://www.sauronsoftware.it/projects/junique/

另请参阅如何实现单实例Java应用程序的完整答案?