Параллелизм Java с чтением / записью

1

Я делаю клиентское серверное приложение на Java. Короче говоря, на сервере есть несколько файлов. Клиент может отправить файл на Сервер, и Клиент может запросить загрузку всех файлов с Сервера. Я использую RMI для взаимодействия с сервером и клиентом, и я использую библиотеку IO RMI для отправки файлов между клиентом и сервером.

Пример кода:

Сервер:

class Server implements ServerService {

// private Map<String, File> files;
private ConcurrentHashMap<String, File> files // Solution

// adding a file to the server
public synchronized void addFile(RemoteInputStream inFile, String filename) 
    throws RemoteException, IOException {

    // From RMI IO library
    InputStream istream = RemoteInputStreamClient.wrap(inFile);
    File f = new File(dir, filename); 
    FileOutputStream ostream = new FileOutputStream(f);
    while (istream.available() > 0) {
        ostream.write(istream.read());
    }
    istream.close();
    ostream.close();
    files.put(filename, f);
}

// requesting all files
public requestFiles(ClientService stub) 
    throws RemoteException, IOException {

    for(File f: files.values()) {
        //Open a stream to this file and give it to the Client
        RemoteInputStreamServer istream = null; 
        istream = new SimpleRemoteInputStream(new BufferedInputStream(
                new FileInputStream(f)));
        stub.receiveFile(istream.export());
    }
}

Обратите внимание, что это всего лишь пример кода для демонстрации.

Мои вопросы касаются одновременного доступа к файлам на сервере. Как вы можете видеть, я сделал метод addFile synchronized потому что он изменяет ресурсы на моем Сервере. Мой метод requestFiles не synchronized.

Мне интересно, может ли это вызвать некоторые проблемы. Когда клиент A добавляет файл и клиент B, одновременно запрашивает все файлы или наоборот, это вызовет проблемы? Или будет addFile метод addFile ждать (или заставить другой метод ждать), потому что он synchronized?

Заранее спасибо!

Теги:
concurrency
client-server
synchronized

1 ответ

1
Лучший ответ

Да, это может вызвать проблемы. Другие потоки могут обращаться к requestFiles(), в то время как один поток выполняет метод addFile().

Невозможно чередование двух вызовов синхронизированных методов на одном объекте. Когда один поток выполняет синхронизированный метод для объекта, все другие потоки, которые вызывают синхронизированные методы для одного и того же блока объектов (приостанавливают выполнение) до тех пор, пока первый поток не будет выполнен с объектом.

[Источник] http://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html

Таким образом, методы, объявленные syncronized, блокируют экземпляр для всех синхронизированных методов в этом экземпляре (в вашем случае экземпляр сервера). Если бы у вас также был синхронизирован метод requestFiles(), вы бы полностью синхронизировали доступ к экземпляру Server. Таким образом, у вас не было бы этой проблемы.

Вы также можете использовать синхронизированные блоки на карте файлов. См. Этот вопрос stackoverflow: синхронизированный блок Java vs. Collections.synchronizedMap


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

В зависимости от остальной части вашего дизайна и при условии, что каждый файл, который вы пишете с помощью метода addFile(), имеет другое имя, и вы не переписываете файлы. Я бы изучил что-то вроде следующего:

Удалите карту полностью и каждый метод взаимодействует с файловой системой отдельно.

Я бы использовал временное расширение (.tmp) для файлов, написанных "addFile()", а затем (после того, как файл был записан) выполните переименование атомного файла, чтобы преобразовать расширение в файл ".txt".

Files.move(src, dst, StandardCopyOption.ATOMIC_MOVE);

Затем ограничьте весь метод requestFiles() до только файлов ".txt". Таким образом, записи файлов и чтения файлов могут происходить параллельно.

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

  • 0
    Возможно, файлы перезаписаны в моем дизайне. Как вы думаете, это хорошая идея, чтобы сделать карту синхронизированной (как в вопросе stackoverflow, на который вы ссылались?)
  • 0
    Я бы использовал ConcurrentHashMap, операции put являются атомарными, а операции чтения действуют как чтение изменчивых переменных. ConcurrentHashMap <String, File> files = new ConcurrentHashMap <String, File> ();
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню