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

时间:2011-04-19 11:03:04

标签: java nio file-locking

我想我错过了一些东西,但我无法理解文件锁如何在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();
    }
}

3 个答案:

答案 0 :(得分:8)

来自Javadoc:

  

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

答案 1 :(得分:2)

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

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

我只能在一个进程中读取/写入一个且只有一个线程。

答案 2 :(得分:2)

您检查了documentation吗? FileChannel.lock()方法在整个文件中返回独占锁。如果要在不同的线程上同时激活多个锁,则不能使用此方法。

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