大家好,最近在用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);
}
}}
/**
*
*/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);
}
}}
解决方案 »
- 关于java编程思想
- Java集合类中为什么没有顺序Set,像ArrayList一样的,而是直接HashSet呢?
- 关于 jndi 的问题,请大家帮忙~~~我是刚接触java
- 关于JUnit
- 简单得键盘事件
- 老师布置的一道题目,不知道该咋作,请高手帮帮忙。
- 各位帅哥,动态加载菜单的事件如何捕捉
- 关于JDK的小版本号,那位高人能详细解释一下么??
- 本人学习java,对这几种布局Layout不是很清楚,请哪位可以解释说明下么?
- java简单问题再问,是不会还是不帮?
- 关于Random() 和net.mindView.util.Print
- emma统计覆盖率时报错:RPC failure while executing [coverage.get]
老外说
Some operating systems doesn't support the concept of shared locking.
就是Linux不支持共享锁。所以没法用文件锁的办法来保证jar的唯一进程
1、用Socket占用一个端口号,每次启动程序检查异常。如果有异常,说明该程序已经被启动。
2、用java的NIO,创建一个临时文件,并加锁。如果启动多个进程,会因为锁的互斥而启动失败,达到目的。
问题如下:
1、占用端口号,可以跨平台,缺点是:需要占用端口资源。如果在一台Linux上面部署很多jar的应用程序,那么要给每一个程序分配一个端口号,浪费端口资源。而且,很容易与现有的程序端口冲突。不应该采用这个办法。
2、java的NIO文件锁。启动一个文件的文件锁,很好的解决了这个问题。但是:Java的NIO文件锁,依赖于OS操作系统。Windows支持,而Linux是不支持的。所以,实现之后,只能用于windows,而不能用于Linux,缺乏跨平台性。
有更好的办法么?