只启动一个进程,以及java的文件锁问题

保证只启动一个应用,通常可以使用两种方法

  1. 获取 一个 文件锁,并且在应用 运行期间都不进行 释放
  2. 绑定一个端口,并且在运行期间都不进行释放

绑定端口要浪费一个端口,因此不推荐.
下面是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已经修复了这个问题.

发布了27 篇原创文章 · 获赞 6 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/l1161558158/article/details/105122340