最近工做中碰到這個問題,用Java寫的一個系統托盤,要求只能有一個實例,當再次啓動程序的時候,須要激活並顯示已經啓動的實例。java
網上搜了一下,一個實例的問題網上已經有解決辦法(使用文件鎖),激活前一個實例的問題卻沒有頭緒,有人說用Win32 API,但搜了好多,搜到的都是VB,VC++等來實現的,沒有用Java的;還有一個方法是使用Socket,這個嘗試了下,確實可行,但缺點是須要佔用一個端口。app
這裏我把兩個問題寫到一個例子裏,供有須要的朋友參考:dom
其中:有一個系統托盤實例:SystemTray tray;一個窗體對象:JFrame frame;socket
在啓動系統托盤的main()方法裏,代碼以下:ide
- public class AppTest {
- private JFrame frame; //窗體
- private SystemTray tray; //系統托盤
- private MyServer server; //服務端socket
- public AppTest() {
- init();
- }
- private void init(){
- //若是當前操做系統不支持系統托盤,則退出
- if(!SystemTray.isSupported()){
- JOptionPane.showMessageDialog(null, "對不起,當前操做系統不支持系統托盤!");
- System.exit(0);
- }
- tray = SystemTray.getSystemTray();
- Image p_w_picpath = null;
- try {
- p_w_picpath = ImageIO.read(this.getClass().getClassLoader().getResourceAsStream("com/blog/icons.png"));
- } catch (IOException e) {
- JOptionPane.showMessageDialog(null, e.getMessage());
- System.exit(0);
- }
- final TrayIcon trayIcon = new TrayIcon(p_w_picpath);
- try {
- tray.add(trayIcon);
- } catch (AWTException e) {
- JOptionPane.showMessageDialog(null, e.getMessage());
- System.exit(0);
- }
- PopupMenu menu = new PopupMenu();
- MenuItem mi = new MenuItem("Exit");
- mi.addActionListener(new ActionListener() {
- @Override
- public void actionPerformed(ActionEvent e) {
- frame.setVisible(false);
- frame.dispose();
- frame = null;
- tray.remove(trayIcon);
- tray = null;
- server.closeServer();
- System.exit(0);
- }
- });
- menu.add(mi);
- trayIcon.setPopupMenu(menu);
- frame = new JFrame("AppTest");
- frame.setSize(new Dimension(200, 200));
- frame.setVisible(true);
- }
- /**
- * 顯示/隱藏 主窗體
- * */
- public void showHideFrame(boolean isVisible){
- frame.setVisible(isVisible);
- frame.setExtendedState(JFrame.NORMAL);
- }
- /**
- * 注入server對象,關閉server時使用
- * @param server
- */
- public void setServerSocket(MyServer server){
- this.server = server;
- }
- //檢查是否得到鎖,true:得到鎖,說明是第一次執行;false:沒有取得鎖,說明已經有一個程序在執行
- public static boolean checkLock() {
- FileLock lock = null;
- RandomAccessFile r = null;
- FileChannel fc = null;
- try {
- // 在臨時文件夾建立一個臨時文件,鎖住這個文件用來保證應用程序只有一個實例被建立.
- File sf = new File(System.getProperty("java.io.tmpdir") + "lock.single");
- sf.deleteOnExit();
- sf.createNewFile();
- r = new RandomAccessFile(sf, "rw");
- fc = r.getChannel();
- lock = fc.tryLock();
- if (lock == null||!lock.isValid()) {
- // 若是沒有獲得鎖,則程序退出.
- // 沒有必要手動釋放鎖和關閉流,當程序退出時,他們會被關閉的.
- return false;
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- return true;
- }
- public static void main(String[] args) {
- //檢查文件鎖,確保只有一個實例運行
- if(!checkLock()){
- //告知上一個程序激活主窗口
- try {
- new Socket(InetAddress.getLocalHost(),60098);
- } catch (Exception e) {
- e.printStackTrace();
- }
- //退出當前程序
- System.exit(0);
- }
- AppTest app = new AppTest();
- new MyServer(app);
- }
- static class MyServer{
- private ServerSocket server;//當前的socket
- private AppTest tray; //保存的前一個托盤實例
- public MyServer(AppTest tray) {
- this.tray = tray;
- tray.setServerSocket(this);
- initServerSocket();
- }
- private void initServerSocket(){
- try {
- server = new ServerSocket(60098);
- while(true){
- if(server.isClosed()){
- break;
- }
- //若是監聽到一個socket鏈接,說明程序啓圖再次打開一個實例,此時顯示前一個窗體
- Socket socket = server.accept();
- tray.showHideFrame(true);
- socket.close();
- }
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- public void closeServer(){
- try {
- server.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
- }