Java程序单实例运行的简单实现

网友投稿 236 2022-10-03


Java程序单实例运行的简单实现

目录需求实现方式代码实现第一种实现(端口控制)第二种实现(文件锁)第三种方式(端口+文件锁)

需求

最近做了个java项目,功能完成后打包安装了,发现可以点开多个实例,因为桌面显示托盘,所以点一次就会出现一个托盘,并且系统也多了好几个javaw进程,这样的话就不能保证程序的健壮性了,所以需要做一个判断让程序只运行一个实例。

实现方式

Java没有提供这样的机制。从操作系统的观点来看,一个启动的Java Application仅仅是一个JVM的运行实例。运行相同Application的两个实例,仅仅是运行两个无关的JVM。

只有让多个运行实例之间有一个既定的通讯机制就可以保证只有一个实例运行。

因为要考虑平台无关,java程序的实例控制不应该使用系统的内核对象来完成,那么我们就必须找到其它的、可以独享的资源。实际上,一台机器无论是在什么操作系统上,网络端口都是独享的,也就是说基于网络端口这个独享的原理,我们可以很方便地让我们的Java程序实现在内存里面只有一个运行实例这个功能,而且这个功能的实现是与平台无关的。

使用端口号控制的方式,先创建端口,运行的时候再判断端口是否被占用来判断是否启动新实例。

文件锁的方式,这种方式的用法在于运行程序的时候将文件上锁,然后判断这个文件是否被锁进而来判断是否要运行一个新实例。

使用端口号+文件的方式,这种方式的用法在于启动的时候创建一个文件,关闭的时候删掉这个文件,当然仅仅这么一个操作不能起到上述要求的,如果非法关闭的话,文件还存在就不能满足要求,只能是再加上一个端口的控制,即当端口被占用并且文件存在的情况下就停止运行新实例,否则启动一个实例,经试验这种方式可以得到满足。

代码实现

第一种实现(端口控制)

//方案:使用java.net.ServerSocket

//问题:打开服务端口可能会受到防火墙的影响;可能和http://别的端口冲突。

import java.io.*;

import java.net.*;

public class OneInstance_2

{

private static ServerSocket listenerSocket;

public static void main(String[] args)

{

try

{

listenerSocket = new ServerSocket(2004);

//At thhttp://is point, no other socket may listen on port 2004.

}

catch(java.net.BindException e)

{

System.err.println("A previous instance is already running....");

System.exit(1);

}

catch(final IOException e) // an unexpected exception occurred

{

System.exit(1);

}

// Do some work here.....

}

}

第二种实现(文件锁)

/*方案:使用Java的加锁文件机制,idea相当简单,让运行实例通过java.nio.channels.FileLock获得一个"well-known"文件的互斥锁。*/

//存在的问题:平台相关

import java.io.*;

import java.nio.channels.*;

public class OneInstance_1 {

public static void main(String[] args) throws Exception {

FileLock lck = new FileOutputStream("C:\\flagFile").getChannel().tryLock();

if(lck == null) {

System.out.println("A previous instance is already running....");

System.exit(1);

}

System.out.println("This is the first instance of this program...");

// Do some work here.....

}

}

//方案3:使用File.createNewFile() and File.deleteOnExit()

//问题:文件可能因为某些原因不能被删除,即使利用Runtime.addShutdownHook()也有可能产生这种情况。

import java.io.*;

public class OneInstance_3

{

public static void main(String[] args) throws Exception

{

File flagFile = new File("C:\\flagFile");

if(false == flagFile.createNewFile())

{

System.out.println("A previous instance is already running....");

System.exit(1);

}

flagFile.deleteOnExit();

System.out.println("This is the first instance of this program..."); // Do some work here.....

}

}

第三种方式(端口+文件锁)

public static void main(String[] args) throws IOException

{

//创建lock.java文件

String filePath = new File("IDRCallDll").getAbsolutePath().substring(0,

new File("IDRCallDll").getAbsolutePath().lastIndexOf("\\"));

File getFile = new File(filePath + "\\" + "lock.java");

System.out.println(getFile.getPath());

//判断端口是否被占用

boolean flag = isLoclePortUsing(20520http://);

System.out.println(flag);

//如果文件存在并且端口被占用则退出

if (getFile.exists() && flag)

{

new MyTray().showDialog();

System.exit(0);

}

try

{

Socket sock = new Socket("127.0.0.1", 20520);// 创建socket,连接20520端口

}

catch (Exception e)

{

System.out.println("端口被占用!");

}

final Class> clazz = (Class>) JavaCall.class;

final boolean isWindows = System.getProperty("os.name").contains(

"Windows");

final List args1 = new ArrayList();

args1.add(isWindows ? "javaw" : "java");

args1.add("-Xmx" + 128 + "M");

args1.add("-cp");

args1.add(System.getProperty("java.class.path"));

args1.add("-Djava.library.path="

+ System.getProperty("java.library.path"));

args1.add(clazz.getCanonicalName());

// logger.info("start " + args1.toString());

final ProcessBuilder pb = new ProcessBuilder(args1);

pb.redirectErrorStream(true);

try

{

/**

* 读身份证信息程序

*/

pb.start();

}

catch (Exception e)

{

// TODO Auto-generated catch block

e.printStackTrace();

}

RandomAccessFile r = new RandomAccessFile(

filePath + "\\" + "lock.java", "rws");

FileChannel temp = r.getChannel();

FileLock fl = temp.lock();

}

/**

* 判断端口是否被占用

* @param port

* @return

*/

public static boolean isLoclePortUsing(int port)

{

boolean flag = true;

try

{

flag = isPortUsing("127.0.0.1", port);

}

catch (Exception e)

{

}

return flag;

}

public static boolean isPortUsing(String host, int port) throws UnknownHostException

{

boolean flag = false;

InetAddress theAddress = InetAddress.getByName(host);

System.out.println(theAddress);

try

{

ServerSocket socket = new ServerSocket(port);

flag = true;

}

catch (IOException e)

{

System.out.println("beizhanyong");

}

return flag;

}


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:SpringMVC中的网络安全知识
下一篇:安全攻防-01 XSS实现会话身份劫持 漏洞原理利用防御(安全攻防工程师)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~