Многопоточный доступ к файлам в Java - PullRequest
0 голосов
/ 07 февраля 2019

Я работаю на многопоточном сервере на Java.Сервер контролирует каталог файлов.Клиенты могут попросить сервер:

  • загрузить файл из каталога сервера
  • , чтобы загрузить новую версию уже существующего файла на сервер, перезаписав старую версию на сервере.directory.

Для выполнения переносов я планирую использовать FileChannels и SocketChannels, используя методы TransferFrom и TransferTo.Согласно документации, эти два метода являются потокобезопасными.Дело в том, что одного вызова этих двух функций может быть недостаточно для полного чтения / записи файла.

Проблема возникает, если к одному и тому же файлу одновременно относятся несколько запросов.В этом сценарии несколько потоков могут выполнять операции чтения / записи для одного и того же файла.Теперь отдельные вызовы TransferFrom / TransferTo являются потокобезопасными, согласно документации Java.Но одного вызова этих двух функций может быть недостаточно для полного чтения / записи файла.Если поток A отвечает на запрос загрузки, а поток B отвечает на запрос загрузки, ссылающийся на тот же файл, может случиться так, что:

  1. Поток A начинает чтение из файла
  2. В потоке A по какой-то причине вызов чтения возвращается до EOF
  3. Поток B перезаписывает весь файл одним вызовом записи
  4. Поток A продолжает чтение из файла

В этом случае загружающий клиент получает часть старой версии и часть новой версии.


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

Лучшее решение, которое я имею в виду, это использовать чередование замков.Перед выполнением любой операции чтения / записи вычисляется хеш на основе имени файла.Затем получается блокировка в позиции lockArr [hash% numOfLocks].Я также считаю, что мне следует использовать ReadWriteLocks, поскольку следует разрешить несколько одновременных чтений.

Теперь это мой анализ проблемы, и я могу ошибаться.Есть ли лучшее решение для этого?

1 Ответ

0 голосов
/ 07 февраля 2019

Блокировка означает, что кто-то должен ждать кого-то другого - не лучшее решение.

Когда клиент загружает файл, вы должны записать его во временный файл на том же диске (обычно втот же каталог), а затем, когда загрузка файла будет завершена:

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

В типичной реализации вам потребуется централизованный класс (давайте назовем его ConcurrentFileAccessor) для управления взаимодействиями между потоками.

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

...