4

データベースファイルへの同時読み取り/書き込み要求を処理するために何かを書いています。

ReentrantReadWriteLockはうまくマッチしているように見えます。すべてのスレッドが共有RandomAccessFileオブジェクトにアクセスする場合、同時読み取りのファイル ポインターについて心配する必要はありますか? 次の例を検討してください。

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class Database {

    private static final int RECORD_SIZE = 50;
    private static Database instance = null;

    private ReentrantReadWriteLock lock;
    private RandomAccessFile database;

    private Database() {
        lock = new ReentrantReadWriteLock();

        try {
            database = new RandomAccessFile("foo.db", "rwd");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    };

    public static synchronized Database getInstance() {
        if(instance == null) {
            instance = new Database();
        }
        return instance;
    }

    public byte[] getRecord(int n) {
        byte[] data = new byte[RECORD_SIZE];
        try {
            // Begin critical section
            lock.readLock().lock();
            database.seek(RECORD_SIZE*n);
            database.readFully(data);
            lock.readLock().unlock();
            // End critical section
        } catch (IOException e) {
            e.printStackTrace();
        }
        return data;
    }

}

getRecord() メソッドでは、複数の同時リーダーで次のインターリーブが可能ですか?

スレッド 1 -> getRecord(0)
スレッド 2 -> getRecord(1)
スレッド 1 -> 共有ロックを取得する
スレッド 2 -> 共有ロックを取得する
スレッド 1 -> レコード 0 をシークする
スレッド 2 -> レコード 1 をシークする
スレッド 1 ->ファイル ポインタでレコードを読み取ります (1)
スレッド 2 -> ファイル ポインタでレコードを読み取ります (1)

ReentrantReadWriteLock と RandomAccessFile を使用して同時実行の問題が発生する可能性がある場合、代替手段は何ですか?

4

5 に答える 5

4

これは、ファイルをロックし、ファイルのロックを解除するサンプル プログラムです。

try { // Get a file channel for the file 

    File file = new File("filename");

    FileChannel channel = new RandomAccessFile(file, "rw").getChannel(); // Use the file channel to create a lock on the file.

    // This method blocks until it can retrieve the lock. 

    FileLock lock = channel.lock(); // Try acquiring the lock without blocking. This method returns // null or throws an exception if the file is already locked. 

    try { 

        lock = channel.tryLock();

    } catch (OverlappingFileLockException e){}


    lock.release(); // Close the file 

    channel.close();
} 

catch (Exception e) { } 
于 2010-09-13T13:35:26.280 に答える
2

独自のロックを管理する代わりに、ファイル システム ロックの使用を検討することをお勧めします。

getChannel().lock()RandomAccessFile を呼び出して、FileChannelクラスを介してファイルをロックします。これにより、制御外のプロセスからの書き込みアクセスも防止されます。

于 2009-10-19T13:48:53.720 に答える
2

はい、あなたが概説したように、このコードは適切に同期されていません。書き込みロックが取得されない場合、読み取り/書き込みロックは役に立ちません。まるでロックがないかのようです。

従来のsynchronizedブロックを使用して、シークと読み取りが他のスレッドに対してアトミックに見えるようにするかRandomAccessFile、単一のスレッドの排他的使用のために借用されてから返されるインスタンスのプールを作成します。(または、スレッドが多すぎない場合は、単に各スレッド専用のチャネルを割り当てます。)

于 2009-10-19T06:36:52.377 に答える
1

ReentrantReadWriteLock は、メソッドではなく単一のロック オブジェクトを操作するため、最大 65535 の再帰書き込みロックと 65535 の読み取りロックをサポートできます。

読み取りおよび書き込みロックを割り当てる

private final Lock r = rwl.readLock();
private final Lock w = rwl.writeLock();

次に、それらに取り組みます...

また、ロック後の例外とロック解除の失敗に対応していません。メソッドに入るときにロックを呼び出し (mutex ロッカーのように)、finally セクションでロック解除を使用して try/catch ブロックで作業を行います。次に例を示します。

public String[] allKeys() {
  r.lock();
  try { return m.keySet().toArray(); }
  finally { r.unlock(); }
}
于 2009-10-19T07:15:55.387 に答える