大家好,最近在用java做后台程序。这个后台程序是系统无关的,可以运行在Windows,也可以运行在Linux。这个java程序,被我用可运行的jar进行执行,要求每个执行jar只能被启动一个进程。为了达到这个目的,我找了资料,有的朋友说启动一个端口,每次启动的时候都做检查,发现端口被占,则说明已经存在该jar的进程在系统中。但是我觉得一个程序占用一个端口,浪费资源。所以继续查找资料,发现用nio的文件锁可以实现。我写了代码,在windows上面运行正常。但是在Linux上面(red hat)上面却运行失败,依然启动了N个进程,而我期望的就是一个经常,在启动更多的进程时会有警告信息。请教高手,该如何处理?下面是我的代码。请指教。
/**
 * 
 */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;
public class Test {
private static Logger logger = Logger.getLogger(Test.class); /**
 * @param args
 */
public static void main(String[] args) {
lockSingletonProgramFile(Test.class.getName());
ExecutorService exec = Executors.newSingleThreadExecutor();
exec.execute(new Runnable(){ @Override
public void run() {
while(true){
try {
TimeUnit.SECONDS.sleep(30);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}});
exec.shutdown();
}

/**
 * method destination : privent starting more than one program process in
 * system processes
 * 
 * @param programName
 */
private static void lockSingletonProgramFile(String programName) { final String startFailureMessage = "Error:start " + programName
+ " application";
String lockFile = System.getProperty("lockFile");
logger.info("start " + programName + " application with [lockFile] : "
+ lockFile);
if (null == lockFile) {
String userDir = System.getProperty("user.dir");
File userDirFile = new File(userDir);
lockFile = userDirFile.getParent() + 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);
}
}}

解决方案 »

  1.   

    当我启动的程序挂了,它会退出程序。如果内部挂死,用kill杀掉进程,在重新启动,就OK。但是我现在的问题是,在Windows上面能用,在Linux上面不能用
      

  2.   

    找了很久,老外也遇到了: https://forums.oracle.com/forums/thread.jspa?threadID=1245629&start=0&tstart=0
    老外说
    Some operating systems doesn't support the concept of shared locking.
    就是Linux不支持共享锁。所以没法用文件锁的办法来保证jar的唯一进程
      

  3.   

    linux的权限管理复杂于WINDOW,还是用端口吧,而且也不会有浪费一学,你用个5位数的端口就好
      

  4.   

    问题描述:java程序被打成jar包来运行,很常见。在一个计算机上面通常需要这个jar包的程序只能运行一个实例。如果启动多个实例,则会出现问题。例如:加载程序,调度程序等等。所以,我想找出一种方法,防止jar被启动多个进程。找到的方法如下:
    1、用Socket占用一个端口号,每次启动程序检查异常。如果有异常,说明该程序已经被启动。
    2、用java的NIO,创建一个临时文件,并加锁。如果启动多个进程,会因为锁的互斥而启动失败,达到目的。
    问题如下:
    1、占用端口号,可以跨平台,缺点是:需要占用端口资源。如果在一台Linux上面部署很多jar的应用程序,那么要给每一个程序分配一个端口号,浪费端口资源。而且,很容易与现有的程序端口冲突。不应该采用这个办法。
    2、java的NIO文件锁。启动一个文件的文件锁,很好的解决了这个问题。但是:Java的NIO文件锁,依赖于OS操作系统。Windows支持,而Linux是不支持的。所以,实现之后,只能用于windows,而不能用于Linux,缺乏跨平台性。
    有更好的办法么?