您好,登錄后才能下訂單哦!
防止JAVA程序重復(fù)啟動的解決辦法,針對這個問題,這篇文章詳細介紹了相對應(yīng)的分析和解答,希望可以幫助更多想解決這個問題的小伙伴找到更簡單易行的方法。
我們項目中有一個后臺任務(wù)處理程序,是java開發(fā)application,用以處理網(wǎng)站提交的一些批量數(shù)據(jù)文件,因為這些數(shù)據(jù)文件數(shù)據(jù)量一般都比較大,所以寫了這個批量處理程序,用以異步處理這些批量數(shù)據(jù)文件。這個程序設(shè)計成插件式的,處理各種不同數(shù)據(jù)文件的功能單獨作為一個插件,然后使用Spring來粘合各個組件,這樣就可以很方便地對該程序進行擴展。
今天客戶提出一個要求:需要控制這個程序在同一主機上只能啟動一個實例。
為了實現(xiàn)客戶要求,我首先想到就是在數(shù)據(jù)庫中建一張表,程序啟動時往該表中寫入一個標志,等程序結(jié)束時再刪除標志。但這種方式存在一個問題就是,如果程序是非正常停止或被殺進程,那么這個標志就不可能被清除,那下一次啟動就會誤判為重復(fù)啟動;另外,如果用數(shù)據(jù)庫來記錄啟動標志的話,還把該程序跟數(shù)據(jù)庫緊密耦合起來,感覺很別扭。
排除了第一種方案之后,我以想到了用文件來保存啟動標志(好象一些大型的程序,諸如weblogic好象就是采用在文件中記錄啟動標志方式來控制重復(fù)啟動的)??土髁咳贿@種方式不需要與數(shù)據(jù)庫耦合在一起,但也存在程序異常中止而無法清除啟動標志的問題,所以這個方案也被槍斃了。
我想到的第三種方案就是在JAVA中調(diào)用操作系統(tǒng)的查看系統(tǒng)進程的方式來取得系統(tǒng)進程,然后再檢測系統(tǒng)進程有特殊的進程標志來判斷是否重復(fù)啟動。但這種方式一是看起來很別扭,再者就是Window和 *nix系統(tǒng)中查看系統(tǒng)進程的命令不一樣,分成幾種情況來處理,無端地增加了程序的復(fù)雜性,也不可取。
能不能在內(nèi)存中記錄一個啟動標志呢?理論上這應(yīng)該是不可行的,因為跨JVM來相互操作內(nèi)存數(shù)據(jù)是不可能。我在網(wǎng)上搜了一下,也沒找到相關(guān)的例子。
那能不能占用一點系統(tǒng)共享資源,來換取我們的目標呢?比較容易想到的系統(tǒng)資源并且不能重復(fù)使用的資源就是端口。我嘗試采用如下方案:在程序中指定一個不常用的端口(比如:12345),在程序啟動時,就指定的端口啟動一個ServerSocket,這個Socket只是為了占用這個端口,不接受任何網(wǎng)絡(luò)連接。如果試圖啟動第二個實例時,程序在該指定端口啟動ServerSocket時就會拋異常,這時我們就可以認為系統(tǒng)已經(jīng)啟動過了,然后打印提示并直接退出程序即可。這種方式在理論上分析應(yīng)該可以的,我開始動手修改程序。程序修改如下:
java 代碼
package cn.com.pansky.xmdswz.application.scheduler;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.quartz.SchedulerException;
import org.quartz.impl.StdScheduler;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import cn.com.pansky.xmdswz.system.cache.CachedTableMgr;
import cn.com.pansky.xmdswz.system.config.SystemConfig;
import cn.com.pansky.xmdswz.utility.DateUtil;
import org.quartz.JobDetail;
import org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean;
import java.net.ServerSocket;
import java.io.*;
/**
* Title: XXXXXXX
* Description: XXXXXXXXXXXX
* Copyright: Copyright (c) 2006
* Company: www.pansky.com.cn
*
* @author Sheng Youfu
* @version 1.0
*/
publicclass Scheduler {
privatestatic Log log = LogFactory.getLog(Scheduler.class);
privatestatic ServerSocket srvSocket = null; //服務(wù)線程,用以控制服務(wù)器只啟動一個實例
privatestaticfinalint srvPort = 12345; //控制啟動唯一實例的端口號,這個端口如果保存在配置文件中會更靈活
/**
* 定時任務(wù)配置文件
*/
privatestatic String CONFIG_FILE = "cn/com/pansky/xmdswz/application/scheduler/Scheduling-bean.xml";
public Scheduler() {
//檢測系統(tǒng)是否只啟動一個實例
checkSingleInstance();
//下面讀取Spring的配置文件
SystemConfig cfg = new SystemConfig();
String config = cfg.parseParam("SCHEDULER.CONFIG_FILE", false);
if(config!=null && !"".equals( config.trim()))
CONFIG_FILE = config;
log.debug("CONFIG_FILE: "+CONFIG_FILE);
}
/**
* 主函數(shù)
* @param args String[]
* @throws Exception
*/
publicstaticvoid main(String[] args) throws Exception{
Scheduler sch = new Scheduler();
sch.execute();
}
/**
* 運行定時任務(wù)
*/
publicvoid execute() {
ClassPathXmlApplicationContext appContext = new ClassPathXmlApplicationContext(new String[] {CONFIG_FILE});
BeanFactory factory = (BeanFactory) appContext;
/**
* 裝載任務(wù)調(diào)度
*/
StdScheduler scheduler = (StdScheduler) factory.getBean("schedulerFactoryBean");
//先暫停所有任務(wù),等待裝載緩存代碼表
try {
scheduler.pauseAll();
} catch (SchedulerException ex) {
log.error("",ex);
}
/**
* 裝載緩存代碼表
*/
CachedTableMgr cachedtableMgr = (CachedTableMgr) factory.getBean("cachedTableMgr");
try {
cachedtableMgr.loadCodeTable();
} catch (Exception ex) {
log.fatal("Load cached table failed. System will exit.", ex);
System.exit(0);
}
//重新恢復(fù)所有任務(wù)
try {
scheduler.resumeAll();
} catch (SchedulerException ex) {
log.error("",ex);
}
}
/**
* 檢測系統(tǒng)是否只啟動了一個實例
*/
protectedvoid checkSingleInstance() {
try {
srvSocket = new ServerSocket(srvPort); //啟動一個ServerSocket,用以控制只啟動一個實例
} catch (IOException ex) {
if(ex.getMessage().indexOf("Address already in use: JVM_Bind")>=0)
System.out.println("在一臺主機上同時只能啟動一個進程(Only one instance allowed)。");
log.fatal("", ex);
System.exit(0);
}
}
}
關(guān)于防止JAVA程序重復(fù)啟動的解決辦法問題的解答就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關(guān)注億速云行業(yè)資訊頻道了解更多相關(guān)知識。
免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。