最近在項目中遇到防止多重新開機動的問題 ,這也使得我開始關注解決這個問題的方法。下面我就說一下我所知道的解決多重新開機動的方法。當然,思想都來自網上,我這裡就是總結并給出相應的實作。
當然你可能需要在同一個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中可能還有很多的不足,如有發現,還望指出。