Swing 程序 多次打开 运行在同一java虚拟机 的实现
问题描述:
用java swing写了个记事本程序,并打成了exe文件在windows下运行,但是每次启动,都会启动一个java虚拟机,每个java虚拟机的启动,都会大量消耗内存。特别是将系统txt文件的默认打开方式设置为本记事本程序时,每双击打开一个记事本,就启动一个jvm,内存消耗30于M,更重要的是,启动jvm很耗时间,在自己的机器上(i5处理器)启动该记事本程序需要2—5秒的时间,用着很不爽。
?
解决办法:
第一次启动程序时,同时启动一个监听,当以后再次启动记事本程序时,首先与监听器进行通信,并将用户操作信息发送给监听器,用户的操作由监听器所属的java虚拟机完成,如此则保证了所有记事本的相关操作在同一个jvm中进行。
?
代码:
public static void main(String args[]) {final String[] filePathArray = args;//设定端口、IPfinal String ip = "127.0.0.1";final int port = 12530;ObjectOutputStream out = null;Socket socket = null;try {//检测记事本程序是否已启动,如果已启动,则由已启动的记事本程序来新建或打开文档,如果未启动,则启动记事本程序,并启动监听。//连接本机指定端口,如果连接失败(表现形式,抛Connect异常),则说明记事本程序尚未启动。socket = new Socket(ip,port);out = new ObjectOutputStream(socket.getOutputStream()); //根据路径打开指定文档 if(filePathArray != null && filePathArray.length > 0){ out.writeObject(filePathArray); //新建空白文档 }else{ out.writeObject("new"); } SplashScreen ss = SplashScreen.getSplashScreen(); if (ss != null) { ss.close(); } //退出java虚拟机 System.exit(0); } catch (Exception e) {//-----------抛异常说明记事本程序尚未启动-------------//1、================初始化日志=================log = Logger.getLogger(Index.class);// 2、================验证应用程序同级目录下,log文件夹是否存在,如果不存在,则创建。================File file_log = new File("log");if (!file_log.exists() || !file_log.isDirectory()) {if (!file_log.mkdirs()) {JOptionPane.showMessageDialog(null, "创建log目录失败!");System.exit(0);}}// 3、================验证应用程序同级目录下,config文件夹是否存在,如果不存在,则创建。================File file_config = new File("config");if (!file_config.exists() || !file_config.isDirectory()) {if (!file_config.mkdirs()) {JOptionPane.showMessageDialog(null, "创建config目录失败!");System.exit(0);}} //4、================新启线程,监听socket连接================new Thread(){@Overridepublic void run() {ObjectInputStream serverIn = null;Socket clientSocket = null;try {ServerSocket serverSocket = new ServerSocket(port);while(true){//accept()会阻塞当前线程的继续执行,当有新客户端接入,才会向下运行。clientSocket = serverSocket.accept();serverIn = new ObjectInputStream(clientSocket.getInputStream());//取得客户端发送的数据 final Object getMsg = serverIn.readObject(); //每个记事本启动时,只会向服务器端发一条信息(new 或 要打开文档的地址),所以处理完请求则关闭相应资源。 try { serverIn.close();} catch (IOException e) {log.error(null, e);}try {clientSocket.close();} catch (Exception e) {log.error(null, e);} //如果客户端发送的信息是 new ,则新建空白文档 if(getMsg.toString().equals("new")){ SwingUtilities.invokeLater(new Runnable(){@Overridepublic void run() {MyNotePad note = new MyNotePad(null, null, null);note.setVisible(true);} }); }else{ //否则,根据客户端发送过来的路径,打开指定文档。 SwingUtilities.invokeLater(new Runnable(){@Overridepublic void run() {String[] files = (String[])getMsg; for(int i=0;i<files.length;i++){ MyNotePad note = new MyNotePad(null, null,files[i]); note.setVisible(true); }} }); }}} catch (Exception e2) {log.error(null, e2);}}}.start();}//5、================启动记事本程序================// 设置系统字体SysFontAndFace.setSysFontAndFace();// 设置输入中文时,不显示输入框System.setProperty("java.awt.im.style", "on-the-spot");try {//打开指定路径的文档if (filePathArray != null && filePathArray.length > 0) {SwingUtilities.invokeAndWait(new Runnable(){@Overridepublic void run() {for (int i = 0; i < filePathArray.length; i++) {MyNotePad note = new MyNotePad(null, null,filePathArray[i]);note.setVisible(true);}} });// 打开空白文档} else {SwingUtilities.invokeAndWait(new Runnable(){@Overridepublic void run() {MyNotePad note = new MyNotePad(null, null, null);note.setVisible(true);} });}} catch (Exception e) {JOptionPane.showMessageDialog(null, "出错了,请重新启动!");System.exit(1);}//6、================启动定时任务,负责执行gc================//创建定时器,一分钟后开始执行,以后每分钟执行一次。Timer timer = new Timer();timer.schedule(new TimerTask(){@Overridepublic void run() {System.gc() ;}}, 60*1000,60*1000);// 7、================关闭欢迎信息================SplashScreen ss = SplashScreen.getSplashScreen();if (ss != null) {ss.close();}}?
?效果:
经前后对比试验,数据如下:
双击启动时间:改造前(2--5秒),改造后(几乎无延迟,1秒内)
同时打开多个文档:改造前(打开一次30M,打开几次则几个30M),改造后(打开一次与打开多次差距不大,始终维持在40M左右)
?
不足:
监听程序会常驻内存,关闭记事本程序不会释放(这也正是启动迅速的原因),不过现在的机器配置都很高,30M的内存可以忽略。
http://huangqiqing123.iteye.com/blog/1674072
?