防止JAVA程序重復(fù)啟動(dòng)的解決辦法

防止JAVA程序重復(fù)啟動(dòng)的解決辦法,針對(duì)這個(gè)問題,這篇文章詳細(xì)介紹了相對(duì)應(yīng)的分析和解答,希望可以幫助更多想解決這個(gè)問題的小伙伴找到更簡(jiǎn)單易行的方法。

公司主營(yíng)業(yè)務(wù):成都網(wǎng)站制作、成都網(wǎng)站建設(shè)、外貿(mào)營(yíng)銷網(wǎng)站建設(shè)、移動(dòng)網(wǎng)站開發(fā)等業(yè)務(wù)。幫助企業(yè)客戶真正實(shí)現(xiàn)互聯(lián)網(wǎng)宣傳,提高企業(yè)的競(jìng)爭(zhēng)能力。成都創(chuàng)新互聯(lián)公司是一支青春激揚(yáng)、勤奮敬業(yè)、活力青春激揚(yáng)、勤奮敬業(yè)、活力澎湃、和諧高效的團(tuán)隊(duì)。公司秉承以“開放、自由、嚴(yán)謹(jǐn)、自律”為核心的企業(yè)文化,感謝他們對(duì)我們的高要求,感謝他們從不同領(lǐng)域給我們帶來(lái)的挑戰(zhàn),讓我們激情的團(tuán)隊(duì)有機(jī)會(huì)用頭腦與智慧不斷的給客戶帶來(lái)驚喜。成都創(chuàng)新互聯(lián)公司推出工農(nóng)免費(fèi)做網(wǎng)站回饋大家。

我們項(xiàng)目中有一個(gè)后臺(tái)任務(wù)處理程序,是java開發(fā)application,用以處理網(wǎng)站提交的一些批量數(shù)據(jù)文件,因?yàn)檫@些數(shù)據(jù)文件數(shù)據(jù)量一般都比較大,所以寫了這個(gè)批量處理程序,用以異步處理這些批量數(shù)據(jù)文件。這個(gè)程序設(shè)計(jì)成插件式的,處理各種不同數(shù)據(jù)文件的功能單獨(dú)作為一個(gè)插件,然后使用Spring來(lái)粘合各個(gè)組件,這樣就可以很方便地對(duì)該程序進(jìn)行擴(kuò)展。
       今天客戶提出一個(gè)要求:需要控制這個(gè)程序在同一主機(jī)上只能啟動(dòng)一個(gè)實(shí)例。
       為了實(shí)現(xiàn)客戶要求,我首先想到就是在數(shù)據(jù)庫(kù)中建一張表,程序啟動(dòng)時(shí)往該表中寫入一個(gè)標(biāo)志,等程序結(jié)束時(shí)再刪除標(biāo)志。但這種方式存在一個(gè)問題就是,如果程序是非正常停止或被殺進(jìn)程,那么這個(gè)標(biāo)志就不可能被清除,那下一次啟動(dòng)就會(huì)誤判為重復(fù)啟動(dòng);另外,如果用數(shù)據(jù)庫(kù)來(lái)記錄啟動(dòng)標(biāo)志的話,還把該程序跟數(shù)據(jù)庫(kù)緊密耦合起來(lái),感覺很別扭。
       排除了第一種方案之后,我以想到了用文件來(lái)保存啟動(dòng)標(biāo)志(好象一些大型的程序,諸如weblogic好象就是采用在文件中記錄啟動(dòng)標(biāo)志方式來(lái)控制重復(fù)啟動(dòng)的)??土髁咳贿@種方式不需要與數(shù)據(jù)庫(kù)耦合在一起,但也存在程序異常中止而無(wú)法清除啟動(dòng)標(biāo)志的問題,所以這個(gè)方案也被槍斃了。
       我想到的第三種方案就是在JAVA中調(diào)用操作系統(tǒng)的查看系統(tǒng)進(jìn)程的方式來(lái)取得系統(tǒng)進(jìn)程,然后再檢測(cè)系統(tǒng)進(jìn)程有特殊的進(jìn)程標(biāo)志來(lái)判斷是否重復(fù)啟動(dòng)。但這種方式一是看起來(lái)很別扭,再者就是Window和 *nix系統(tǒng)中查看系統(tǒng)進(jìn)程的命令不一樣,分成幾種情況來(lái)處理,無(wú)端地增加了程序的復(fù)雜性,也不可取。
       能不能在內(nèi)存中記錄一個(gè)啟動(dòng)標(biāo)志呢?理論上這應(yīng)該是不可行的,因?yàn)榭鏙VM來(lái)相互操作內(nèi)存數(shù)據(jù)是不可能。我在網(wǎng)上搜了一下,也沒找到相關(guān)的例子。
       那能不能占用一點(diǎn)系統(tǒng)共享資源,來(lái)?yè)Q取我們的目標(biāo)呢?比較容易想到的系統(tǒng)資源并且不能重復(fù)使用的資源就是端口。我嘗試采用如下方案:在程序中指定一個(gè)不常用的端口(比如:12345),在程序啟動(dòng)時(shí),就指定的端口啟動(dòng)一個(gè)ServerSocket,這個(gè)Socket只是為了占用這個(gè)端口,不接受任何網(wǎng)絡(luò)連接。如果試圖啟動(dòng)第二個(gè)實(shí)例時(shí),程序在該指定端口啟動(dòng)ServerSocket時(shí)就會(huì)拋異常,這時(shí)我們就可以認(rèn)為系統(tǒng)已經(jīng)啟動(dòng)過(guò)了,然后打印提示并直接退出程序即可。這種方式在理論上分析應(yīng)該可以的,我開始動(dòng)手修改程序。程序修改如下:

java 代碼

  1. package cn.com.pansky.xmdswz.application.scheduler;  

  2.  

  3. import org.apache.commons.logging.Log;  

  4. import org.apache.commons.logging.LogFactory;  

  5. import org.quartz.SchedulerException;  

  6. import org.quartz.impl.StdScheduler;  

  7. import org.springframework.beans.factory.BeanFactory;  

  8. import org.springframework.context.support.ClassPathXmlApplicationContext;  

  9. import cn.com.pansky.xmdswz.system.cache.CachedTableMgr;  

  10. import cn.com.pansky.xmdswz.system.config.SystemConfig;  

  11. import cn.com.pansky.xmdswz.utility.DateUtil;  

  12. import org.quartz.JobDetail;  

  13. import org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean;  

  14. import java.net.ServerSocket;  

  15. import java.io.*;  

  16.  

  17. /**

  18. * Title: XXXXXXX

  19. * Description: XXXXXXXXXXXX

  20. * Copyright: Copyright (c) 2006

  21. * Company: www.pansky.com.cn

  22. *

  23. * @author Sheng Youfu

  24. * @version 1.0

  25. */  

  26. publicclass Scheduler {  

  27.  privatestatic Log log = LogFactory.getLog(Scheduler.class);  

  28.  

  29.  privatestatic ServerSocket srvSocket = null; //服務(wù)線程,用以控制服務(wù)器只啟動(dòng)一個(gè)實(shí)例  

  30.  

  31.  privatestaticfinalint srvPort = 12345;     //控制啟動(dòng)唯一實(shí)例的端口號(hào),這個(gè)端口如果保存在配置文件中會(huì)更靈活  

  32.  

  33.  /**

  34.   * 定時(shí)任務(wù)配置文件

  35.   */  

  36.  privatestatic String CONFIG_FILE = "cn/com/pansky/xmdswz/application/scheduler/Scheduling-bean.xml";  

  37.  

  38.  

  39.  public Scheduler() {  

  40.    //檢測(cè)系統(tǒng)是否只啟動(dòng)一個(gè)實(shí)例  

  41.    checkSingleInstance();  

  42.  

  43.    //下面讀取Spring的配置文件  

  44.    SystemConfig cfg = new SystemConfig();  

  45.    String config = cfg.parseParam("SCHEDULER.CONFIG_FILE", false);  

  46.    if(config!=null && !"".equals( config.trim()))  

  47.      CONFIG_FILE = config;  

  48.    log.debug("CONFIG_FILE: "+CONFIG_FILE);  

  49.  }  

  50.  

  51.  /**

  52.   * 主函數(shù)

  53.   * @param args String[]

  54.   * @throws Exception

  55.   */  

  56.  publicstaticvoid main(String[] args) throws Exception{  

  57.    Scheduler sch = new Scheduler();  

  58.    sch.execute();  

  59.  }  

  60.  

  61.  /**

  62.   * 運(yùn)行定時(shí)任務(wù)

  63.   */  

  64.  publicvoid execute() {  

  65.    ClassPathXmlApplicationContext appContext = new ClassPathXmlApplicationContext(new String[] {CONFIG_FILE});  

  66.    BeanFactory factory = (BeanFactory) appContext;  

  67.  

  68.    /**

  69.     * 裝載任務(wù)調(diào)度

  70.     */  

  71.    StdScheduler scheduler = (StdScheduler) factory.getBean("schedulerFactoryBean");  

  72.    //先暫停所有任務(wù),等待裝載緩存代碼表  

  73.    try {  

  74.      scheduler.pauseAll();  

  75.    } catch (SchedulerException ex) {  

  76.      log.error("",ex);  

  77.    }  

  78.  

  79.    /**

  80.     * 裝載緩存代碼表

  81.     */  

  82.    CachedTableMgr cachedtableMgr = (CachedTableMgr) factory.getBean("cachedTableMgr");  

  83.    try {  

  84.      cachedtableMgr.loadCodeTable();  

  85.    } catch (Exception ex) {  

  86.      log.fatal("Load cached table failed. System will exit.", ex);  

  87.      System.exit(0);  

  88.    }  

  89.  

  90.    //重新恢復(fù)所有任務(wù)  

  91.    try {  

  92.      scheduler.resumeAll();  

  93.    } catch (SchedulerException ex) {  

  94.      log.error("",ex);  

  95.    }  

  96.  }  

  97.  

  98.  /**

  99.   * 檢測(cè)系統(tǒng)是否只啟動(dòng)了一個(gè)實(shí)例

  100.   */  

  101.  protectedvoid checkSingleInstance() {  

  102.    try {  

  103.      srvSocket = new ServerSocket(srvPort); //啟動(dòng)一個(gè)ServerSocket,用以控制只啟動(dòng)一個(gè)實(shí)例  

  104.    } catch (IOException ex) {  

  105.      if(ex.getMessage().indexOf("Address already in use: JVM_Bind")>=0)  

  106.        System.out.println("在一臺(tái)主機(jī)上同時(shí)只能啟動(dòng)一個(gè)進(jìn)程(Only one instance allowed)。");  

  107.      log.fatal("", ex);  

  108.      System.exit(0);  

  109.    }  

  110.  }  

  111. }  

關(guān)于防止JAVA程序重復(fù)啟動(dòng)的解決辦法問題的解答就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道了解更多相關(guān)知識(shí)。

當(dāng)前標(biāo)題:防止JAVA程序重復(fù)啟動(dòng)的解決辦法
文章路徑:http://muchs.cn/article48/ijdpep.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供移動(dòng)網(wǎng)站建設(shè)、網(wǎng)站策劃響應(yīng)式網(wǎng)站、ChatGPT定制網(wǎng)站、企業(yè)建站

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

搜索引擎優(yōu)化