问题:【备注:发现java的NIO是平台相关的,目前只能在Windows上面实现文件锁,而Linux是不支持的。我正在寻找更好的解决办法,有解决方案的朋友,可以在这里留言。谢谢】
【备注:今天在网上找了一个开源的,防止程序启动多进程的jar包。地址: http://www.sauronsoftware.it/projects/junique/manual.php
用起来,很不错。我看了源码,也是nio的文件锁和Socket绑定端口号实现的。不过,他为了防止文件锁不起作用,下面接着用了socket占用端口号,来了一个双重保险。我也懒的自己写了,就用了他的。】
【目前没有好的办法。只能用占用端口号的解决方案】
以前一直在做WEB开发,对于后台程序不是很了解。现在做后台的部分系统开发,发现一个问题:java程序打成jar包之后进行运行,有时候因为人为的原因,会多次启动该jar运行程序。很多情况下,这是不允许的。为了解决java程序被启动多个进程,我找了一些资料,里面说的五花八门。有的说用数据库,有的说用文件写入一个标识。这些方法都可以防止程序被多次启动,但是存在一个很大的问题:如果程序的进程是被 kill 掉的,那么再次启动程序,就会发生问题,因为标志位没有被清空。所以这不是彻底解决问题的方法。
又开始找了一些资料,终于发现了不错的方案。下面给我现在使用的方案,利用Java NIO的文件锁(File Lock)来实现的。还有朋友用的是占用一个不经常用的端口,来实现,这也是一个不错的解决方案。占用端口号的方案,我在这里给出链接: http://sheng.iteye.com/blog/37732
这里是我写的文件锁的解决方案:
package com.concurrency.chapter1; import java.io.File; import java.io.FileWriter; import java.io.RandomAccessFile; import java.nio.channels.FileChannel; import java.nio.channels.FileLock; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import org.apache.log4j.Logger; /** * <pre> * with java NIO file lock to prevent starting more than on process * @author kanpiaoxue * @date 2012-02-02 * </pre> */ public class SingletonProgram { private static Logger logger = Logger.getLogger(SingletonProgram.class); private static final String PROGRAMA_NAME = "Singleton"; /** * @param args */ public static void main(String[] args) { String startMessage = "start " + PROGRAMA_NAME + " application"; logger.info(startMessage); lockSingletonProgramFile(PROGRAMA_NAME); try {// simulate running program ExecutorService exec = Executors.newSingleThreadExecutor(); exec.execute(new Runnable() { @Override public void run() { logger.info("start to run test thread."); while (true) { try { long sleepTime = 10L; logger.info("run test thread successfully. It will sleep " + sleepTime + " seconds"); TimeUnit.SECONDS.sleep(sleepTime); } catch (InterruptedException e) { e.printStackTrace(); } } } }); exec.shutdown(); } catch (Exception ex) { ex.printStackTrace(); } logger.info(startMessage + " successfully!"); } /** * method destination : privent starting more than one program process in * system processes * * @param programName */ private static void lockSingletonProgramFile(String programName) { // java -DlockFile=D:\lock\tmplock\application.lock -jar // SingletonProgram.jar final String startFailureMessage = "Error:start " + programName + " application"; String lockFile = System.getProperty("lockFile"); logger.info("start " + programName + " application with [lockFile] : " + lockFile); if (null == lockFile) { lockFile = System.getProperty("user.dir") + File.separator + programName + ".lock"; logger.warn("does not provide lockFile, it will use default lockFile which is [" + lockFile + "]"); } RandomAccessFile raf = null; FileChannel fileChannel = null; FileLock flock = null; FileWriter writer = null; try { File file = new File(lockFile); if (!file.exists()) { String parent = file.getParent(); File folder = new File(parent); if (!folder.exists() || !folder.isDirectory()) { if (!folder.mkdirs()) { logger.error(startFailureMessage + " failure: create lock file folder failure:" + parent); System.exit(-1); } } if (!file.createNewFile()) { logger.error(startFailureMessage + " failure: create lock file failure:" + lockFile); System.exit(-1); } } writer = new FileWriter(file); writer.write(programName); /** * Here,we force flush data into lock file. If there already has a * process in system processes, it will catch Exception. */ writer.flush(); writer.close(); raf = new RandomAccessFile(file, "rw"); fileChannel = raf.getChannel(); flock = fileChannel.tryLock();// start to try locking lock file /** * <pre> * Note: * Here, at first time, you cann't release or close these resources. * If you do it, you will find that it cann't prevent more than one program process * running in system processes. * </pre> */ } catch (Exception e) { logger.error(startFailureMessage + " failure: lock file is [" + lockFile + "]:" + e.getMessage(), e); try { /** * <pre> * Note: * If you start program process failure, * you need to try releasing and closing these resources. * </pre> */ if (null != writer) { writer.close(); } if (null != flock) { flock.release(); } if (null != fileChannel) { fileChannel.close(); } if (null != raf) { raf.close(); } } catch (Exception ex) { logger.error( "Error: close resource failure:" + ex.getMessage(), ex); } logger.error("There is a " + programName + " application process in system processes. Now exit starting!"); System.exit(-1); } } }