让程序只有一个进程实例在运行

用过金山词霸的人可能都会发现,当你把金山词霸打开,如果再去双击金山词霸的快捷方式来启动它的时候,系统没有为我们再启动一个新的进程而是激活了前面我们已经打开的金山词霸程序,也就是说我们在一台计算机上同一时刻只能运行一个金山词霸的实例。这样的软件现在也很多,典型的还有winamp,暴风影音等…..这样的好处可以避免用户因为误点而启动了原本不想启动的程序,同时也使得我们的软件不会出现因为访问同一个资源而引起内部冲突问题。那么我们能不能在Java中也实现同样的功能呢?
      有的人可能会说了,我用单一模式去实现我的Java类不就好了吗?其实单一模式只是保证了一个类在其他的类中只能构造一个实例,并不能实现只有一个系统进程在运行的功能。要实现这个功能的话,其实只要考虑一下用C++应该怎么样实现就好了,因为有了JNI,只要能用C++实现,稍微变一下的话就可以在Java中实现了。下面我就以一个例子来说明我自己的实现方法。如果用户试图运行这个程序的第二个实例,那么就会弹出一个“只能有一个程序的实例被运行!”的警告然后终止进程。具体的效果图如下:



在Java程序中
先要定义一个将要在C++中具体实现的本地方法

// 得到当前本程序正在运行的实例的数目
private native int getInstanceSum();

然后再在Java程序的构造函数中去调用这个方法,如果函数返回值不为0,说明已经有实例在运行了,这个时候就要做相应的处理,否则正常进行构造函数的执行。具体的代码如下:

  1.  1 package com.caokai.jni;
    2 import javax.swing.JFrame;
    3 import javax.swing.JOptionPane;
    4 public class SingletonInstance extends JFrame {
    5
    6 static
    7 {
    8 try
    9 {
    10 System.loadLibrary(\"SingletonInstance\");
    11 }
    12 catch(Exception ex)
    13 {
    14 ex.printStackTrace();
    15 }
    16 }
    17
    18 private native int getInstanceSum();
    19
    20 /**
    21 * Method main
    22 *
    23 *
    24 * @param args
    25 *
    26 */
    27 public static void main(String[] args)
    28 {
    29
    30 SingletonInstance instance = new SingletonInstance();
    31 instance.pack();
    32 instance.setVisible(true);
    33 }
    34 /**
    35 * Method SingletonInstance
    36 *
    37 * Defult constructor.
    38 */
    39 public SingletonInstance()
    40 {
    41
    42 super(\"SingletonInstance\");
    43 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    44 checkRunning();
    45 }
    46
    47 /**
    48 * Method checkRunning
    49 *
    50 * Check whether one instance of this program is running.
    51 */
    52 public void checkRunning()
    53 {
    54 if(getInstanceSum() == 1)
    55 {
    56 JOptionPane.showMessageDialog(null, \"只能有一个程序的实例被运行!\");
    57 System.exit(0);
    58 }
    59 }
    60 }


在C++程序中

具体的去实现前面声明的getInstanceSum() 函数。我们知道每一个windows程序在运行的时候,系统就会为其启动的进程分配4G的虚拟空间,然后再这个空间里面去启动进程里面的线程去完成程序具体的功能。当然首先启动的就是main 函数的线程,就是主线程,然后再由主线程去启动其他的子现程。只要我们为主线程创建一个命名的互斥对象,这样当有第二个实例在运行的时候,当其创建同一个名字的互斥对象时就会返回一个ERROR_ALREADY_EXISTS错误,如果我们调用GetLastError() 方法返回的错误和 ERROR_ALREADY_EXISTS相同,就说明已经有一个实例在运行了,这样就可以判断是否只有一个实例在运行了。具体的代码如下:

  1.  1 #include <windows.h>
    2 #include \"SingletonInstance.h\"
    3 HANDLE hMutex;
    4 JNIEXPORT jint JNICALL Java_com_caokai_jni_SingletonInstance_getInstanceSum
    5 (JNIEnv *env, jobject obj)
    6 {
    7 hMutex = CreateMutex(NULL, FALSE, \"SingletonInstance\");
    8 if(hMutex)
    9 {
    10 if(GetLastError() == ERROR_ALREADY_EXISTS)
    11 {
    12 return JNI_TRUE;
    13 }
    14 }
    15 return JNI_FALSE;
    16 }


说明:
      以上程序用到了JNI的有关知识,其中生成的头文件我没有列出源代码.
      至于具体的JNI编程知识,我以前有相关文档说明.
      你可以再做相应的处理来达到激活先前打开的实例而不是弹出那个警告对话框.
      如果有更好的方法实现,欢迎你和我探讨,我的QQ:415764553
      这里我把本程序的所有C++和Java代码都附上.


转自:http://bbs.ccidnet.com/forum.php?mod=viewthread&tid=297156&extra=page%3D1

原文地址:https://www.cnblogs.com/viviancc/p/2380801.html