Java:线程安全的RandomAccessFile

时间:2010-05-21 12:52:56

标签: java multithreading locking thread-safety

经过一些严肃的googleing后,我发现RandomAccessFile-class不是线程安全的。现在我可以使用一个信号量来锁定所有的读写操作,但我不认为它表现得非常好。理论上,应该可以一次执行多次读取和一次写入。 我怎么能用Java做到这一点?它有可能吗?

谢谢!

5 个答案:

答案 0 :(得分:7)

  

我可以使用一个信号量来锁定所有信号量   读写,但我不认为   表现得非常好。

关于表现,永远不要想。总是衡量。

那就是说,java.util.concurrent.locks.ReentrantReadWriteLock正是你要找的。

答案 1 :(得分:2)

文件的部分锁定是一项复杂的业务,许多操作系统都避免这样做。但是,如果您坚持这样做,一种方法是设计自己的锁定机制对象,记录文件的哪些部分被锁定。基本上在读取或写入对象之前,必须请求锁定文件的特定字节范围。如果锁在字节范围内完全重叠,则认为它们发生冲突。读写锁的处理方式不同:读取可以安全地与任意数量的读锁重叠,但写锁必须与其他锁,读或写重叠。如果你无法获得锁定,是否等待或中止,以及是否在写入等待时阻止读取,有很多问题,但只有你可以回答它们关于你的应用程序。

鉴于此复杂性,锁定整个文件可能更好。检查您是否获得足够的性能 - 并且不要忘记只要没有写入就可以一次允许多次读取。

答案 2 :(得分:2)

考虑这种方法 - 它允许无限的读者,当作家想要写作时,它等待当前读者完成写作。

class readWriteSemaphore() {
    private Object lock;
    List<Thread> readers;
    Thread writer;

    readWriteSemaphore() {
        readers = new LinkedList<Thread>(); // Linked list is inefficient for many threads, FYI
        writer = null;
    }

    /**
    * Returns true if and only if you have acquired a read
    * maybe use while(!rws.acquireRead(Thread.currentThread())) Thread.sleep(50); // or something
    */
    boolean acquireRead(Thread t) {
        synchronized(lock) {
            if(writer == null) {
                readers.add(t);
                return true;
            }
            return false; // yes this could go outside the synch block... oh well
        }
    }

    void releaseRead(Thread t) {
        synchronized(lock) {
            while(readers.remove(t)); // remove this thread completely
        }
    }

    boolean acquireWrite(Thread t) {
        synchronized(lock) {
            if(writer == null) return false;
            writer = t;
        }
        while(readers.size() > 0) Thread.sleep(50); // give readers time to finish. 
        //They can't re-enter yet because we set the writer,
        // if you attempt to acquire a write, future reads will be false until you're done
        return true;
    }

    void releaseWrite(Thread t) {
        synchronized(lock) {
            if(t != writer) throw new IllegalArgumentException("Only writer can release itself");
            writer = null;
        }
    }

}

答案 3 :(得分:2)

如果整个文件上的简单互斥锁会给您带来性能瓶颈,并且RandomAccessFile在没有互斥锁的情况下不是线程安全的,那么您需要查看RandomAccessFile的替代方法。

另一种方法是将文件作为MappedBuffer映射到内存中,并使用缓冲区片段允许不同的线程访问文件而不会相互干扰。单个编写器/多个读卡器锁定在整个粒度将很容易实现。您还可以进一步实现并发读取和写入文件的非重叠部分,但这会更复杂。

听到某个人已经将其作为可重用的库实现,我不会感到惊讶。

答案 4 :(得分:0)

java.nio.channels.FileChannel 正是这样做的,即安全的并发读取和单线程写入。