Java: потокобезопасный RandomAccessFile - PullRequest
8 голосов
/ 21 мая 2010

После некоторых серьезных поисков я обнаружил, что класс RandomAccessFile не является поточно-ориентированным. Теперь я могу использовать один семафор для блокировки всех операций чтения и записи, но я не думаю, что это работает очень хорошо. Теоретически должно быть возможно делать несколько чтений и одну запись за раз. Как я могу сделать это на Java? Возможно ли это вообще?

Спасибо!

Ответы [ 4 ]

7 голосов
/ 21 мая 2010

Я мог бы использовать один семафор, чтобы заблокировать все читает и пишет но я не думаю это очень хорошо работает.

Что касается производительности, НИКОГДА не думайте. ВСЕГДА измеряй.

Тем не менее, java.util.concurrent.locks.ReentrantReadWriteLock это то, что вы ищете.

2 голосов
/ 21 мая 2010

Если простой мьютекс во всем файле создаст вам узкое место в производительности, а RandomAccessFile не является поточно-ориентированным без мьютекса, то вам нужно поискать альтернативы RandomAccessFile.

Одна альтернатива - отобразить файл в память как MappedBuffer и использовать фрагменты буфера, чтобы разные потоки могли обращаться к файлу, не мешая друг другу. Простая блокировка записи / множественного чтения на уровне детализации всего будет легко осуществима. Вы также можете пойти дальше и реализовать одновременное чтение и запись непересекающихся разделов файла, но это будет более сложным.

Я бы не удивился, узнав, что кто-то где-то уже реализовал это как библиотеку многократного использования.

2 голосов
/ 21 мая 2010

Рассмотрим этот подход - он позволяет неограниченному количеству читателей, и когда писатель хочет писать, он ждет, пока текущие читатели завершат свою запись.

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

}
2 голосов
/ 21 мая 2010

Частичная блокировка файла - сложное дело, которого избегают многие операционные системы. Однако, если вы настаиваете на этом, одним из способов является создание собственного объекта механизма блокировки, который записывает, какие части файла заблокированы. По сути, перед чтением или записью объекта необходимо запросить блокировку для определенного диапазона байтов файла. Блокировки считаются конфликтующими, если они вообще перекрываются в диапазоне байтов. Блокировки чтения и записи обрабатываются по-разному: чтение может перекрываться с любым количеством блокировок чтения безопасно, но блокировка записи должна перекрываться без других блокировок чтения или записи. Существует множество вопросов о том, стоит ли ждать или прерывать работу, если вы не можете получить блокировку, а также следует ли блокировать чтение во время ожидания записи, но только вы можете ответить на них о вашем приложении.

Учитывая сложность этого, может быть лучше заблокировать весь файл. Проверьте, получаете ли вы адекватную производительность, и не забывайте, что вы можете разрешить несколько операций чтения одновременно, если нет записей.

...