开发者

Java: thread-safe RandomAccessFile

开发者 https://www.devze.com 2022-12-31 07:55 出处:网络
After some serious googleing I found out that the RandomAccessFile-class is not thread-safe. Now I could use one 开发者_如何学Pythonsemaphore to lock all reads and writes but I don\'t think that perfo

After some serious googleing I found out that the RandomAccessFile-class is not thread-safe. Now I could use one 开发者_如何学Pythonsemaphore 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 does exactly that, i.e safe concurrent reads and single-threaded writes.

0

精彩评论

暂无评论...
验证码 换一张
取 消