防止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)域給我們帶來的挑戰(zhàn),讓我們激情的團(tuán)隊(duì)有機(jī)會(huì)用頭腦與智慧不斷的給客戶帶來驚喜。成都創(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來粘合各個(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ù)來記錄啟動(dòng)標(biāo)志的話,還把該程序跟數(shù)據(jù)庫(kù)緊密耦合起來,感覺很別扭。
排除了第一種方案之后,我以想到了用文件來保存啟動(dòng)標(biāo)志(好象一些大型的程序,諸如weblogic好象就是采用在文件中記錄啟動(dòng)標(biāo)志方式來控制重復(fù)啟動(dòng)的)??土髁咳贿@種方式不需要與數(shù)據(jù)庫(kù)耦合在一起,但也存在程序異常中止而無法清除啟動(dòng)標(biāo)志的問題,所以這個(gè)方案也被槍斃了。
我想到的第三種方案就是在JAVA中調(diào)用操作系統(tǒng)的查看系統(tǒng)進(jìn)程的方式來取得系統(tǒng)進(jìn)程,然后再檢測(cè)系統(tǒng)進(jìn)程有特殊的進(jìn)程標(biāo)志來判斷是否重復(fù)啟動(dòng)。但這種方式一是看起來很別扭,再者就是Window和 *nix系統(tǒng)中查看系統(tǒng)進(jìn)程的命令不一樣,分成幾種情況來處理,無端地增加了程序的復(fù)雜性,也不可取。
能不能在內(nèi)存中記錄一個(gè)啟動(dòng)標(biāo)志呢?理論上這應(yīng)該是不可行的,因?yàn)榭鏙VM來相互操作內(nèi)存數(shù)據(jù)是不可能。我在網(wǎng)上搜了一下,也沒找到相關(guān)的例子。
那能不能占用一點(diǎn)系統(tǒng)共享資源,來?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)過了,然后打印提示并直接退出程序即可。這種方式在理論上分析應(yīng)該可以的,我開始動(dò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ù)器只啟動(dòng)一個(gè)實(shí)例
privatestaticfinalint srvPort = 12345; //控制啟動(dòng)唯一實(shí)例的端口號(hào),這個(gè)端口如果保存在配置文件中會(huì)更靈活
/**
* 定時(shí)任務(wù)配置文件
*/
privatestatic String CONFIG_FILE = "cn/com/pansky/xmdswz/application/scheduler/Scheduling-bean.xml";
public Scheduler() {
//檢測(cè)系統(tǒng)是否只啟動(dòng)一個(gè)實(shí)例
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();
}
/**
* 運(yùn)行定時(shí)任務(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);
}
}
/**
* 檢測(cè)系統(tǒng)是否只啟動(dòng)了一個(gè)實(shí)例
*/
protectedvoid checkSingleInstance() {
try {
srvSocket = new ServerSocket(srvPort); //啟動(dòng)一個(gè)ServerSocket,用以控制只啟動(dòng)一個(gè)實(shí)例
} catch (IOException ex) {
if(ex.getMessage().indexOf("Address already in use: JVM_Bind")>=0)
System.out.println("在一臺(tái)主機(jī)上同時(shí)只能啟動(dòng)一個(gè)進(jìn)程(Only one instance allowed)。");
log.fatal("", ex);
System.exit(0);
}
}
}
關(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://jinyejixie.com/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í)需注明來源: 創(chuàng)新互聯(lián)