Использование блокировок файлов Java в одной JVM и в нескольких JVM - PullRequest
5 голосов
/ 19 апреля 2011

Думаю, я что-то упустил, но не могу понять, как работают блокировки файлов в 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 ]

8 голосов
/ 20 апреля 2011

Из Javadoc:

Блокировки файлов хранятся от имени всей виртуальной машины Java.Они не подходят для управления доступом к файлу несколькими потоками на одной виртуальной машине.

2 голосов
/ 19 апреля 2011

Вы проверили документацию ? Метод FileChannel.lock() возвращает эксклюзивную блокировку для файла весь . Если вы хотите иметь несколько активных блокировок одновременно в разных потоках, вы не можете использовать этот метод.

Вместо этого вам нужно использовать FileChannel.locklock(long position, long size, boolean shared) для блокировки определенной области файла. Это позволит вам одновременно активировать несколько блокировок, при условии, что каждая из них применяется к отдельной области файла. Если вы попытаетесь заблокировать один и тот же регион файла дважды, вы столкнетесь с тем же исключением.

2 голосов
/ 19 апреля 2011

Вы можете получить блокировку только один раз для каждого файла. Замки не повторяющиеся AFAIK.

ИМХО: использование файлов для связи между процессами - очень плохая идея. Возможно, вы сможете заставить это работать надежно, дайте мне знать, если сможете;)

Я бы имел один и только один поток для чтения / записи только в одном процессе.

...