无法使用java.nio.channels.FileLock在Linux上锁定文件

无法使用java.nio.channels.FileLock在Linux上锁定文件,java,linux,filelock,Java,Linux,Filelock,我正在用Java创建一个应用程序,我只希望运行一个实例。为此,我创建了一个文件,并在应用程序运行时获得了一个锁 我有以下代码在Windows上运行,但在Linux上失败了:一旦我获得了一个锁而没有解锁它,我就可以获得另一个锁 import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; import java.nio.channels.FileChannel; import java.nio.c

我正在用Java创建一个应用程序,我只希望运行一个实例。为此,我创建了一个文件,并在应用程序运行时获得了一个锁

我有以下代码在Windows上运行,但在Linux上失败了:一旦我获得了一个锁而没有解锁它,我就可以获得另一个锁

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;

public class MyApp {

private static File f;
private static FileChannel channel;
private static FileLock lock;

public static void main(String[] args) {
    try {
        f = new File("RingOnRequest.lock");
        // Check if the lock exist
        if (f.exists()) {
            // if exist try to delete it
            f.delete();
        }
        // Try to get the lock
        channel = new RandomAccessFile(f, "rw").getChannel();
        lock = channel.tryLock();
        if(lock == null)
        {
            // File is lock by other application
            channel.close();
            throw new RuntimeException("Only 1 instance of MyApp can run.");
        }
        // Add shutdown hook to release lock when application shutdown
        ShutdownHook shutdownHook = new ShutdownHook();
        Runtime.getRuntime().addShutdownHook(shutdownHook);

        //Your application tasks here..
        System.out.println("Running");
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }
    catch(IOException e)
    {
        throw new RuntimeException("Could not start process.", e);
    }

}

public static void unlockFile() {
    // release and delete file lock
    try {
        if(lock != null) {
            lock.release();
            channel.close();
            f.delete();
        }
    } catch(IOException e) {
        e.printStackTrace();
    }
}

static class ShutdownHook extends Thread {

    public void run() {
        unlockFile();
    }
}

}

为什么不将PID保存到一个文件中,而不是锁定该文件,验证是否有具有该ID的进程。如果有,并且它是您的应用程序的一个实例,您知道它已经在运行

套接字也可能是一个好主意,因为您可以使用它与正在运行的实例进行通信

编辑:

此外,来自:

锁是否确实阻止另一个程序访问 锁定区域的内容取决于系统,因此 未指明


我使用了和您相同的示例,在Mac OS X上遇到了相同的问题。似乎文件锁定并不能阻止POSIX系统上的文件删除。在你解锁之前,你的应用程序仍然会对该文件进行某种处理。因此,请考虑在文件名(或文件内)使用带有PID的锁文件。

您每次运行时都会删除锁文件,因此只有一个进程可以对它进行锁定。
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;

public class MyApp {

private static File f;
private static FileChannel channel;
private static FileLock lock;

public static void main(String[] args) {
    try {
        f = new File("RingOnRequest.lock");
        // Check if the lock exist
        if (f.exists()) {
            // if exist try to delete it
            f.delete();
        }
        // Try to get the lock
        channel = new RandomAccessFile(f, "rw").getChannel();
        lock = channel.tryLock();
        if(lock == null)
        {
            // File is lock by other application
            channel.close();
            throw new RuntimeException("Only 1 instance of MyApp can run.");
        }
        // Add shutdown hook to release lock when application shutdown
        ShutdownHook shutdownHook = new ShutdownHook();
        Runtime.getRuntime().addShutdownHook(shutdownHook);

        //Your application tasks here..
        System.out.println("Running");
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }
    catch(IOException e)
    {
        throw new RuntimeException("Could not start process.", e);
    }

}

public static void unlockFile() {
    // release and delete file lock
    try {
        if(lock != null) {
            lock.release();
            channel.close();
            f.delete();
        }
    } catch(IOException e) {
        e.printStackTrace();
    }
}

static class ShutdownHook extends Thread {

    public void run() {
        unlockFile();
    }
}

}
当您使用
FileLock
时,纯粹是建议您在文件上获取锁可能不会阻止您执行任何操作…即使另一个进程已获取锁,也可以读取、写入和删除文件。有时,在特定平台上,锁可能做的不止这些,但这种行为是未指定的,依赖于类文档中保证的以外的东西会导致失败

“通知锁”只是一个信号,其他进程可以看到它,而这些进程需要寻找它。如果您对它的依赖不止这些,那么当您的程序在其他平台上运行时,它就会崩溃


为什么要删除锁文件?锁定文件就像一个布尔标志,系统上的每个进程都可以看到它。将您的协议设计为这样使用,您将拥有可靠的跨平台锁定机制。

使用
mkdir
。在unix系统上,这是一个错误–如果成功创建新目录,它将成功,否则将失败

例如:

File lockFile = new File("/path/to/lockdir");
boolean hasLock = lockFile.mkdir();
if (!hasLock) {
  throw new IOException("could not get lock");
}
// do stuff
lockFile.delete();

我在Windows和Linux上都进行了测试。很好。当应用程序正常关闭时,锁定文件将自动删除。因此,当您重新启动应用程序时,您不必担心锁文件会留在那里。只需注释掉以下几行:

if (f.exists()) {
    // if exist try to delete it
    f.delete();
}

<>但是,你可能想考虑如果你的应用程序崩溃并没有以正常的方式关闭会发生什么。

最近我遇到了同样的问题,但在我的例子中,我有一个优势:我的应用程序只在超时后查询了一些目录。由于我的应用程序没有立即轮询目录,我编写了一个特殊类,该类在init方法中使用自己的PID创建锁文件,之后在尝试使用目录之前,它需要调用
ownedLock()
-如果返回true,则我们可以以其他方式退出(代码在Kotlin中,但您将了解主要内容):


一旦我获得了一个锁而没有解锁它,我就可以获得另一个锁。这是因为你正在删除文件。不要删除该文件。当你为每个程序实例创建一个新文件时,你不能希望在一个文件上获得独占锁。我如何以编程方式做到这一点?我在这里得到了解决方案,如果你运行“advanceinstaller”,这实际上是正确的,而不是在任何普通的java应用程序中。-internet上没有其他对secondaryMain的引用,我对它进行了测试,每次都会调用main()。通过在java.io.tmpdir目录中创建该文件,使锁工作。-1:pidfiles的创建和修改不是原子的,验证它们指向的内容的过程也不是原子的(必须在读取后异步完成). 这使得它们在实际锁定时不安全。在文件名中添加“PID”会有什么不同?这是实现锁定文件的另一种方法。您的程序创建了一个文件,其名称(
myprogram.PID
)或内部带有PID。下一个启动的实例将检查与所用模式匹配的文件,提取PID并检查是否存在具有该PID的进程。如果进程存在-当前实例是第二个,必须关闭,否则-它是唯一的实例,它将创建一个新的PID文件并继续运行。-1:PID文件不提供真正的锁定,因为它们的创建、修改、读取和c。不是原子的,因此容易受到竞争条件的影响。因此,它们需要与另一种锁定机制结合使用,以确保它们的安全。如果应用程序因任何原因意外停止运行而没有删除lockFile文件夹,该怎么办。。下次运行应用程序时,它将不会运行,因为文件夹存在!