保证只启动一个应用,通常可以使用两种方法
- 获取 一个 文件锁,并且在应用 运行期间都不进行 释放
- 绑定一个端口,并且在运行期间都不进行释放
绑定端口要浪费一个端口,因此不推荐.
下面是java获取一个文件锁的操作.
@SneakyThrows
public static boolean lock(String file) {
Path path = Paths.get(file);
FileChannel channel = FileChannel.open(path, StandardOpenOption.CREATE, StandardOpenOption.WRITE);
FileLock fileLock = channel.tryLock();
return fileLock != null;
}
按照文件锁的逻辑,在一个应用已经占用了文件锁的情况下,第二个应用无法获取到文件锁.这里指的是排他锁.
下面是使用方式
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.concurrent.TimeUnit;
public class ProgressInstanceLock {
/**
* 在linux无法运行
* 应该是jdk的bug
* @param file
* @return
*/
public static boolean lock(String file) throws Exception {
Path path = Paths.get(file);
FileChannel channel = FileChannel.open(path, StandardOpenOption.CREATE, StandardOpenOption.WRITE);
FileLock fileLock = channel.tryLock();
return fileLock != null;
}
public static void main(String[] args) throws Exception {
String file="instance";
boolean lock = ProgressInstanceLock.lock(file);
System.out.println(lock);
while (lock){
TimeUnit.SECONDS.sleep(1);
}
System.out.println("bye");
}
}
JDK1.8.0_144在windows下这段代码可以正常运行,其他版本未测试
而linux中JDK11.0.4无法按照预期运行.
使用相同的逻辑编写一段c++代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>
#include <unistd.h>
#define LOCK_FILE "instance"
void alreadyRunning(){
int lock_file = open(LOCK_FILE, O_CREAT|O_RDWR, 0666);
int flags = fcntl(lock_file, F_GETFD);
//设置子进程关闭该引用
flags |= FD_CLOEXEC;
fcntl(lock_file, F_SETFD, flags);
////
int rc = flock(lock_file, LOCK_EX|LOCK_NB);
if (rc)
{
if (EWOULDBLOCK == errno)
{
printf("该实例已经运行!\nExit...");
exit(1);
}
}else{
char buffer[64];
sprintf(buffer, "%d\n", getpid());
write(lock_file, buffer, strlen(buffer));
// close(lock_file); // 不要忘记释放文件指针
}
}
int main(int argc,char** args){
alreadyRunning();
while(1){
sleep(1);
}
return 1;
}
使用g++ main.cpp 进行编译,然后./a.out就可以运行.
此时启动两个a.out的进程后,第二个进程会打印该实例已经 运行.
不知道是我使用的方式有问题还是怎么样,java代码在Windows下是正常的,而在linux下会重复锁定,从而导致无法正常工作.
发现JDK 13 2019-09-17已经修复了这个问题.