5

私は何かが欠けていると思いますが、Java でファイル ロックがどのように機能するかを理解できません。より正確に言えば、それがどのように実装されているかです。

単一の JVM 内の同じファイルに対して 2 つ以上のロックを取得できない (取得しようとすることさえできない) ようです。最初のロックは正常に取得されます。さらにロックを取得しようとすると、OverlapingFileLockException が発生します。それにもかかわらず、それは別々のプロセスで機能します。

複数の同時要求(読み取りと書き込みの両方)で動作することを目的としたファイルシステムに基づくデータストレージを実装したいと考えています。ファイル ロックを使用して、ストレージ内の特定のファイルをロックしたいと考えています。

この例外を回避するには、JVM レベルでもう 1 つの同期 (排他的) を導入してから、ファイルを同期する必要があるようです。

誰かがそのようなことをしましたか?

私の問題が何であるかを示すために、簡単なテストケースを用意しました。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();
    }
}
4

3 に答える 3

8

Javadoc から:

ファイル ロックは、Java 仮想マシン全体に代わって保持されます。これらは、同じ仮想マシン内の複数のスレッドによるファイルへのアクセスを制御するのには適していません。

于 2011-04-20T12:21:57.627 に答える
2

ドキュメントを確認しましたか?このFileChannel.lock()メソッドは、ファイル全体に排他ロックを返します。異なるスレッド間で複数のロックを同時にアクティブにしたい場合、この方法は使用できません。

FileChannel.locklock(long position, long size, boolean shared)代わりに、ファイルの特定の領域をロックするために使用する必要があります。これにより、それぞれがファイルの異なる領域に適用される場合、複数のロックを同時にアクティブにすることができます。ファイルの同じ領域を 2 回ロックしようとすると、同じ例外が発生します。

于 2011-04-19T11:17:30.517 に答える
2

ファイルごとに 1 回だけロックを取得できます。ロックは再入可能ではありません。

私見:ファイルを使用してプロセス間で通信することは、非常に悪い考えです。おそらく、これを確実に機能させることができるでしょう。できれば教えてください ;)

1 つのプロセスだけで 1 つのスレッドだけが読み取り/書き込みを行うことになります。

于 2011-04-19T11:08:10.343 に答える