防止JAVA程序重复启动的解决办法

防止JAVA程序重复启动的解决办法,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。

公司主营业务:成都网站制作、成都网站建设、外贸营销网站建设、移动网站开发等业务。帮助企业客户真正实现互联网宣传,提高企业的竞争能力。成都创新互联公司是一支青春激扬、勤奋敬业、活力青春激扬、勤奋敬业、活力澎湃、和谐高效的团队。公司秉承以“开放、自由、严谨、自律”为核心的企业文化,感谢他们对我们的高要求,感谢他们从不同领域给我们带来的挑战,让我们激情的团队有机会用头脑与智慧不断的给客户带来惊喜。成都创新互联公司推出工农免费做网站回馈大家。

我们项目中有一个后台任务处理程序,是java开发application,用以处理网站提交的一些批量数据文件,因为这些数据文件数据量一般都比较大,所以写了这个批量处理程序,用以异步处理这些批量数据文件。这个程序设计成插件式的,处理各种不同数据文件的功能单独作为一个插件,然后使用Spring来粘合各个组件,这样就可以很方便地对该程序进行扩展。
       今天客户提出一个要求:需要控制这个程序在同一主机上只能启动一个实例。
       为了实现客户要求,我首先想到就是在数据库中建一张表,程序启动时往该表中写入一个标志,等程序结束时再删除标志。但这种方式存在一个问题就是,如果程序是非正常停止或被杀进程,那么这个标志就不可能被清除,那下一次启动就会误判为重复启动;另外,如果用数据库来记录启动标志的话,还把该程序跟数据库紧密耦合起来,感觉很别扭。
       排除了第一种方案之后,我以想到了用文件来保存启动标志(好象一些大型的程序,诸如weblogic好象就是采用在文件中记录启动标志方式来控制重复启动的)。客流量然这种方式不需要与数据库耦合在一起,但也存在程序异常中止而无法清除启动标志的问题,所以这个方案也被枪毙了。
       我想到的第三种方案就是在JAVA中调用操作系统的查看系统进程的方式来取得系统进程,然后再检测系统进程有特殊的进程标志来判断是否重复启动。但这种方式一是看起来很别扭,再者就是Window和 *nix系统中查看系统进程的命令不一样,分成几种情况来处理,无端地增加了程序的复杂性,也不可取。
       能不能在内存中记录一个启动标志呢?理论上这应该是不可行的,因为跨JVM来相互操作内存数据是不可能。我在网上搜了一下,也没找到相关的例子。
       那能不能占用一点系统共享资源,来换取我们的目标呢?比较容易想到的系统资源并且不能重复使用的资源就是端口。我尝试采用如下方案:在程序中指定一个不常用的端口(比如:12345),在程序启动时,就指定的端口启动一个ServerSocket,这个Socket只是为了占用这个端口,不接受任何网络连接。如果试图启动第二个实例时,程序在该指定端口启动ServerSocket时就会抛异常,这时我们就可以认为系统已经启动过了,然后打印提示并直接退出程序即可。这种方式在理论上分析应该可以的,我开始动手修改程序。程序修改如下:

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; //服务线程,用以控制服务器只启动一个实例  

  30.  

  31.  privatestaticfinalint srvPort = 12345;     //控制启动唯一实例的端口号,这个端口如果保存在配置文件中会更灵活  

  32.  

  33.  /**

  34.   * 定时任务配置文件

  35.   */  

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

  37.  

  38.  

  39.  public Scheduler() {  

  40.    //检测系统是否只启动一个实例  

  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.   * 主函数

  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.   * 运行定时任务

  63.   */  

  64.  publicvoid execute() {  

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

  66.    BeanFactory factory = (BeanFactory) appContext;  

  67.  

  68.    /**

  69.     * 装载任务调度

  70.     */  

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

  72.    //先暂停所有任务,等待装载缓存代码表  

  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.    //重新恢复所有任务  

  91.    try {  

  92.      scheduler.resumeAll();  

  93.    } catch (SchedulerException ex) {  

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

  95.    }  

  96.  }  

  97.  

  98.  /**

  99.   * 检测系统是否只启动了一个实例

  100.   */  

  101.  protectedvoid checkSingleInstance() {  

  102.    try {  

  103.      srvSocket = new ServerSocket(srvPort); //启动一个ServerSocket,用以控制只启动一个实例  

  104.    } catch (IOException ex) {  

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

  106.        System.out.println("在一台主机上同时只能启动一个进程(Only one instance allowed)。");  

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

  108.      System.exit(0);  

  109.    }  

  110.  }  

  111. }  

关于防止JAVA程序重复启动的解决办法问题的解答就分享到这里了,希望以上内容可以对大家有一定的帮助,如果你还有很多疑惑没有解开,可以关注创新互联行业资讯频道了解更多相关知识。


新闻标题:防止JAVA程序重复启动的解决办法
URL分享:http://ybzwz.com/article/ijdpep.html