在单个JVM和多个JVM中使用java文件锁



我想我错过了一些东西,但我无法理解文件锁在Java中的工作原理。更确切地说——它是如何实现的。

似乎我无法在单个JVM中为同一个文件获取(甚至无法尝试获取)两个或多个锁。第一个锁将成功获取,所有进一步尝试获取更多锁将导致OverlapingFileLockException。然而,它适用于单独的进程。

我想实现由文件系统支持的数据存储,旨在处理多个并发请求(读和写)。我想使用文件锁来锁定存储中的特定文件。

似乎我必须在jvm级别引入更多的同步(排他性),并且只有在文件上同步才能避免这种异常。

有人做过那样的事吗?

我准备了简单的测试用例来显示我的问题是什么。我用的是Mac OS X, Java 6。
import junit.framework.*;
import javax.swing.*;
import java.io.*;
import java.nio.channels.*;
/**
 * Java file locks test.
 */
public class FileLocksTest extends TestCase {
    /** File path (on Windows file will be created under the root directory of the current drive). */
    private static final String LOCK_FILE_PATH = "/test-java-file-lock-tmp.bin";
    /**
     * @throws Exception If failed.
     */
    public void testWriteLocks() throws Exception {
        final File file = new File(LOCK_FILE_PATH);
        file.createNewFile();
        RandomAccessFile raf = new RandomAccessFile(file, "rw");
        System.out.println("Getting lock...");
        FileLock lock = raf.getChannel().lock();
        System.out.println("Obtained lock: " + lock);
        Thread thread = new Thread(new Runnable() {
            @Override public void run() {
                try {
                    RandomAccessFile raf = new RandomAccessFile(file, "rw");
                    System.out.println("Getting lock (parallel thread)...");
                    FileLock lock = raf.getChannel().lock();
                    System.out.println("Obtained lock (parallel tread): " + lock);
                    lock.release();
                }
                catch (Throwable e) {
                    e.printStackTrace();
                }
            }
        });
        thread.start();
        JOptionPane.showMessageDialog(null, "Press OK to release lock.");
        lock.release();
        thread.join();
    }
    /**
     * @throws Exception If failed.
     */
    public void testReadLocks() throws Exception {
        final File file = new File(LOCK_FILE_PATH);
        file.createNewFile();
        RandomAccessFile raf = new RandomAccessFile(file, "r");
        System.out.println("Getting lock...");
        FileLock lock = raf.getChannel().lock(0, Long.MAX_VALUE, true);
        System.out.println("Obtained lock: " + lock);
        Thread thread = new Thread(new Runnable() {
            @Override public void run() {
                try {
                    RandomAccessFile raf = new RandomAccessFile(file, "r");
                    System.out.println("Getting lock (parallel thread)...");
                    FileLock lock = raf.getChannel().lock(0, Long.MAX_VALUE, true);
                    System.out.println("Obtained lock (parallel thread): " + lock);
                    lock.release();
                }
                catch (Throwable e) {
                    e.printStackTrace();
                }
            }
        });
        thread.start();
        JOptionPane.showMessageDialog(null, "Press OK to release lock.");
        lock.release();
        thread.join();
    }
}

From Javadoc:

文件锁代表整个Java虚拟机。他们是不适合控制访问一个文件由多个线程组成

每个文件只能获得一次锁。锁是不可重入的。

恕我直言:使用文件在进程之间进行通信是一个非常糟糕的主意。也许你将能够让这个工作可靠,让我知道如果你可以;)

我将在一个进程中只有一个线程读写。

你看过文档了吗?FileChannel.lock()方法在整个文件上返回一个排他的锁。如果希望跨不同线程并发地激活多个锁,则不能使用此方法。

相反,您需要使用FileChannel.locklock(long position, long size, boolean shared)来锁定文件的特定区域。这将允许您同时激活多个锁,前提是每个锁应用于文件的不同区域。如果您尝试锁定文件的同一区域两次,您将遇到相同的异常。

最新更新