简体   繁体   中英

Java: thread-safe RandomAccessFile

After some serious googleing I found out that the RandomAccessFile-class is not thread-safe. Now I could use one semaphore to lock all reads and writes but I don't think that performs very well. In theory it should be possible to do multiple reads and one write at a time. How can I do this in Java? Is it possible at all?

Thanks!

I could use one semaphore to lock all reads and writes but I don't think that performs very well.

With respect to performance, NEVER think. ALWAYS measure.

That said, java.util.concurrent.locks.ReentrantReadWriteLock is what you are looking for.

Partial locking of a file is a complex business which a lot of operating systems avoid doing. However if you insist on doing it, one way is to design your own locking mechanism object that records which parts of the file are locked. Essentially before reading or writing an object must request a lock for a specific byte range of the file. Locks are considered to clash if they overlap at all in byte range. Read and write locks are treated differently: a read can overlap with any number of read locks safely, but a write lock must overlap with no other locks, read or write. There are a lot of questions about whether to wait or abort if you can't get the lock, and whether to block reads while a write is waiting, but only you can answer them about your application.

Given the complexity of this it may be better to lock the entire file. Check to see if you get adequate performance - and don't forget you can allow multiple reads at once, as long as there are no writes.

Consider this approach - it allows unlimited readers, and when a writer wants to write, it waits for current readers to finish to do its write.

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;
        }
    }

}

If a simple mutex on the entire file is going to give you a performance bottleneck, and RandomAccessFile is not thread-safe without a mutex, then you need to look at alternatives to RandomAccessFile .

One alternative is to map the file into memory as a MappedBuffer and use slices of the buffer to allow different threads to access the file without interfering with each other. Single writer / multiple reader locking at the granularity of the entire would be easy to implement. You could also go further and implement concurrent reading and writing of non-overlapping sections of the file, but that would be more complicated.

I would not be surprised to hear that someone, somewhere has already implemented this as a reusable library.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM