Java: ориентированный на многопотоковое исполнение RandomAccessFile

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

Спасибо!

8
задан Andrew Grimm 7 October 2010 в 07:10
поделиться

4 ответа

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

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

2
ответ дан 5 December 2019 в 12:56
поделиться

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

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
ответ дан 5 December 2019 в 12:56
поделиться

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

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

Учитывая это, java.util.concurrent.locks.ReentrantReadWriteLock - это то, что вы ищете.

7
ответ дан 5 December 2019 в 12:56
поделиться

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

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

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

2
ответ дан 5 December 2019 в 12:56
поделиться
Другие вопросы по тегам:

Похожие вопросы: