2010-05-21 3 views
6

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

Спасибо!

+0

Это зависит от того, как вы читаете и записываете из файла, но примитивы синхронизации из java.util.concurrent очень хорошо работают на современной JVM. –

+0

Я понимаю, если вы пытаетесь использовать тот же RandomAccessFile из разных потоков, но вам действительно нужно делать несколько чтений одновременно? Я не эксперт, но в большинстве случаев аппаратное обеспечение не сможет одновременно обслуживать несколько считываний (я не знаю, для больших массивов дисков). –

+0

Он будет работать с RAID-массивами. Также: когда данные поступают из кеша, его можно получить параллельно. –

ответ

1

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

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

+0

hmmm интересная идея. У меня есть readblock (int nr) и writeblock (int nr). теперь у меня мог бы быть массив Семафор [] locks = new Семафор [10]; then in readblock/writeblock() Я мог бы делать блокировки [nr% 10] .acquireUninterruptibly() не может думать о каких-либо проблемах с этим. По-прежнему я считаю, что базовый случайный случайный случай не будет работать с одновременным доступом. –

+0

Точка создания объекта блокировки заключается в предотвращении одновременного доступа. Вы должны закодировать так, чтобы все потоки должны были получить блокировку от объекта блокировки до доступа к файлу и освободить его после их завершения. – DJClayworth

7

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

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

Сказанное так, java.util.concurrent.locks.ReentrantReadWriteLock - это то, что вы ищете.

+1

Да, но тогда я буду делать 2 или более одновременных чтения, RandomAccessFile не справится с этим. См. Http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4193259 (часть оценки) –

+0

Итак, вы не можете использовать блокировку чтения, чтобы вы могли использовать синхронизацию. – EJP

1

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

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

} 
+0

Похоже на реализацию java.util.concurrent.locks.ReentrantReadWriteLock? Но все же: мне нужен способ для нескольких чтений и/или записи для успеха. А RandomAccessFile не допускает нескольких чтений. –

+0

Это позволяет выполнять множественные чтения. Просто не многократная запись. – corsiKa

+0

Да, но RandomAccessFile не допускает нескольких чтений. Я ищу другого класса. –

1

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

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

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

Смежные вопросы