最近在项目中遇到防止多重启动的问题 ,这也使得我开始关注解决这个问题的方法。下面我就说一下我所知道的解决多重启动的方法。当然,思想都来自网上,我这里就是总结并给出相应的实现。
当然你可能需要在同一个JVM下防止多重启动, 很抱歉,这不是本篇所关注的重点,但是你可以通过单例模式很方便的实现,其他的实现方式,还待你的发现。
本篇仅针对在不同的JVM下防止对同一个画面的多重启动。
防止多重启动,目前我知道有以下3种方法:
1,绑定端口; 2,将启动信息保存到文件; 3,文件加锁
这三种方法也各有缺点,方法1的优点是控制通过编程来实现,没有依赖本地的文件,缺点是必须保证绑定的端口没有被其它应用程序所占用。方法2和方法3都需要依赖于一个本地文件,并且方法2还有一个致命的缺陷:程序在运行过程中断电,程序将再无法启动。比较后我认为,对文件加锁的方法是最可行的方案。
下面我就对上述的三种解决办法分别给出示例,请先看下图:

从上图中可以看出我们是要防止对FrameA的多重启动。这里用到一个接口MultipleStarted,它的两个方法分别用来注册和注销启动画面的信息。类ByFileLock,ByListenningToSocket,ByWriteInfoToFile分别表示用文件加锁,端口绑定,向文件写信息的方式来实现防止多重启动。
下面就是这次例子的source:
package multipleStartUp;
interface MultipleStarted ... {
public boolean registerPage();
public void unRegisterPage();
}
在FrameA中,你可以通过对multi 变量赋值的修改(注释处)来达到通过不同的方式控制多重启动。
package multipleStartUp;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JFrame;
import javax.swing.WindowConstants;
public class FrameA extends JFrame ... {
private static final long serialVersionUID = 1L;
MultipleStarted multi = null;
FrameA()...{
super();
// multi = new ByListenningToSocket();
// multi = new ByWriteInfoToFile();
multi = new ByFileLock();
initialize();
if(!multi.registerPage())...{
System.out.println("You have open a same page!");
System.exit(0);
}
}
private void initialize()...{
this.setSize(200, 300);
this.setTitle("FrameA");
this.addWindowListener(new WindowAdapter()...{
public void windowClosing(WindowEvent e)...{
multi.unRegisterPage();
}
});
}
public static void main(String[] args)...{
FrameA a = new FrameA();
a.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
a.setVisible(true);
}
}
package multipleStartUp;
import java.io.File;
import java.io.FileOutputStream;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
public class ByFileLock implements MultipleStarted ... {
private String fileName = "temp";
private FileOutputStream fos = null;
private FileChannel fChannel = null;
ByFileLock()...{
try...{
fos = new FileOutputStream(new File(fileName));
fChannel = fos.getChannel();
}catch(Exception e)...{
System.out.println("Error occur while getting fileChannel!");
}
}
@Override
public boolean registerPage() ...{
try...{
if(fChannel != null)...{
FileLock fLock = fChannel.tryLock();
if(fLock != null)...{
return true;
}else...{
unRegisterPage();
}
}
}catch(Exception e)...{
}
return false;
}
@Override
public void unRegisterPage() ...{
try...{
if(fChannel != null)...{
fChannel.close();
}
if(fos != null)...{
fos.close();
}
}catch(Exception e)...{
}
}
}
package multipleStartUp;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
public class ByWriteInfoToFile implements MultipleStarted ... {
private String fileName = "temp.serialize";
@Override
public boolean registerPage() ...{
try...{
File file = new File(fileName);
if(!file.exists())...{
file.createNewFile();
}
if(isPageStarted(file))...{
return false;
}
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(file));
boolean isOpen = true;
oos.writeBoolean(isOpen);
oos.close();
}catch(Exception e)...{
return false;
}
return true;
}
private boolean isPageStarted(File file)...{
try...{
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
boolean isOpen = ois.readBoolean();
if(isOpen)...{
return true;
}
}catch(Exception e)...{
return false;
}
return false;
}
@Override
public void unRegisterPage() ...{
try...{
File file = new File(fileName);
if(!file.exists())...{
file.createNewFile();
}
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(file));
boolean isOpen = false;
oos.writeBoolean(isOpen);
oos.flush();
oos.close();
}catch(Exception e)...{
}
}
}
package multipleStartUp;
import java.net.InetAddress;
import java.net.ServerSocket;
public class ByListenningToSocket implements MultipleStarted ... {
private int port = 4000;
private InetAddress local = null;
ServerSocket socket = null;
ByListenningToSocket()...{
}
@Override
public boolean registerPage() ...{
try ...{
local = InetAddress.getLocalHost();
socket = new ServerSocket(port,100,local);
} catch (Exception e)...{
//e.printStackTrace();
return false;
}
return true;
}
@Override
public void unRegisterPage() ...{
try...{
if(socket != null)...{
socket.close();
}
}catch(Exception e)...{
}
}
}
当然,这些仅仅是说明性的示范,告诉我们可以通过这种方法解决问题,至于实现中的细节问题,根据不同的情况,必定不同。
这也仅仅是防止多重启动多种方法中的3种而已,必定还有很多我不知道的解决方法,期待中......
说明:由于是示范性例子,上述source中没有对异常作统一的出理,并且source中可能还有很多的不足,如有发现,还望指出。