Java RMI и синхронизированные методы

Я изучаю книгу "Распределенные системы" (Tanenbaum и Van Steen), и они говорят что-то, что, похоже, противоречит тому, что, по-видимому, многие думают о Java RMI и синхронизированных методах.

Я думал, что использование синхронизированного метода в реализации удаленного объекта (так что реальная реализация, выполняемая на сервере) одновременное выполнение этого метода предотвращается даже тогда, когда вызовы этого метода разные машины клиентов (вызов метода через прокси-сервер... aka the Stub).

Я видел, что у многих людей одинаковое мнение, посмотрите здесь: Вопросы Java RMI и Thread Synchronization

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

Вот соответствующий отрывок из книги (вы можете прочитать только смелое предложение, но вы можете прочитать контекст, если хотите):

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

Альтернативным подходом было бы разрешить блокировку только на сервере. В принцип, это прекрасно работает, но проблемы возникают при сбое клиента в то время как его обращение обрабатывается сервером. Как мы обсуждали в Глава. 8, мы можем потребовать относительно сложные протоколы для обработки этого ситуации, и которая может существенно влияют на общий производительность удаленного метода вызовы.

Поэтому разработчики Java RMI решили ограничить блокировку удаленные объекты только для прокси (Wollrath et al., 1996). Это означает что потоки в одном и том же процессе будут быть предотвращено одновременно доступа к одному и тому же удаленному объекту, но потоки в разных процессах будут не. Очевидно, что эта синхронизация семантика сложна: при синтаксисе уровень (т.е. при чтении исходного кода) мы можем видеть красивый, чистый дизайн. Только когда распределенное приложение фактически выполненный, непредвиденный может наблюдаться поведение, которое должно были рассмотрены во время разработки. [...]

Я думаю, что статья "Распределенная объектная модель для Java-системы" (доступна здесь) упоминается в тексте примечанием Wollrath et all, 1996 между скобками. Однако единственный соответствующий абзац, который я нашел на этом документе, следующий:

Из-за различных режимов отказа локального и удаленного объекты, распределенное ожидание и уведомление требуют более сложный протокол между участвующими субъектами (так что, например, авария клиента не заставляют удаленный объект блокироваться навсегда), и как такие, не могут быть легко установлены в локальную резьбу модель в Java. Следовательно, клиент может использовать оповещение и ждать методы на удаленной ссылке, но этот клиент должен быть что такие действия не будут связаны с фактическим удаленным объект, только локальный прокси (заглушка) для удаленного объект.

Я интерпретирую текст неправильно или на самом деле заявлено, что синхронизированные методы "не так синхронизированы" при использовании RMI?

Ответы

Ответ 1

В вашей первой ссылке говорится, что внутри одного экземпляра виртуальной машины вызовы на RMI-сервере (клиент на RMI-сервер) будут внутренне синхронизированы. То есть, заглушка (или прокси-сервер, поскольку текст, похоже, вызывает это) сама по себе предотвратит одновременный вызов нескольких потоков на удаленном сервере. Однако он поясняет, что две виртуальные машины, каждая из которых имеет заглушки для удаленного сервера, не будут блокироваться при одновременном вызове удаленного сервера (что очевидно, поскольку они не могут совместно использовать блокировку, а сам RMI не предотвращает concurrency на сервере), Если это нежелательно, сервер RMI должен будет реализовать механизм блокировки для предотвращения множественных одновременных вызовов.

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

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

Ответ 2

Насколько я знаю, каждый вызов сервера RMI создаст новый поток (засвидетельствованный моими файлами журнала с 2000 года) на стороне сервера. Если вы выполняете синхронизацию на стороне сервера, вы должны быть в безопасности. Я столкнулся с некоторыми древними предупреждениями из литературы, которые вы опубликовали. Как практик, я предпочитал запускать программное обеспечение в течение месяца или около того и решил, что он достаточно стабилен для производства. Я сожалею, если это не удовлетворяет.

Ответ 3

Вы также должны знать, что многопоточность Java значительно изменилась с 1996 года. Методы notify() и wait(), которые были частью оригинального языка, получили много средств от экспертов concurrency и на Java 5 (2004, говорит wiki) объекты высокого уровня concurrency, такие как ReentrantLock, которые теперь являются предпочтительным способом делать вещи.

Итак, критика, которую вы упоминаете, вероятно, правильная, но устаревшая.

Ответ 4

Вы правы. Текст неправильный. Опоры RMI являются потокобезопасными и могут быть вызваны одновременно несколькими потоками внутри единой клиентской JVM. Я не знаю ни одного заявления или текста Wollrath et, в котором говорится что-то другое, и я слежу за этой темой с 1997 года.

В частности:

Я думал, что использование синхронизированного метода в реализации удаленного объекта (так что реальная реализация, выполняемая на сервере) одновременное выполнение этого метода предотвращается даже тогда, когда вызовы этого метода выполняются с разных компьютеров клиентов (вызов метода через прокси... aka a Stub).

Вы правы.

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

Книга не только ошибочна, но и заявляет о невозможности. Как точно RMI предотвращает работу синхронизации?

Логически, блокировка в удаленном объекте проста. Предположим, что клиент A вызывает синхронизированный метод удаленного объекта.

Затем блокирование происходит на сервере, при нормальной работе Java.

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

Мусор. Тот факт, что реализация удаленного метода synchronized делает все, что необходимо.

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

Снова это мусор.

В результате мы должны синхронизировать разные клиенты на разных машинах.

Мусор снова.

Альтернативным подходом было бы разрешить блокировку только на сервере.

'Разрешить'? Что это значит? A synchronized метод synchronized. Вы не можете запретить его.

В принципе, это работает отлично, но проблемы возникают, когда клиент падает, когда его вызов обрабатывается сервером.

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

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

Глупости.

Поэтому разработчики Java RMI решили ограничить блокировку удаленных объектов только прокси (Wollrath et al., 1996).

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

В любом случае дизайнеры RMI не сделали такого выбора. Такого выбора не было. synchronized synchronized независимо от того, что дизайнеры RMI могли или не пожелали, и аналогично notify() и wait() являются final. Они не были свободны делать какой-либо выбор. Цитата, которую вы предоставили, не является "выбором": это всего лишь утверждение о семантике Java.

Я интерпретирую текст неправильно или на самом деле заявлено, что синхронизированные методы "не так синхронизированы" при использовании RMI?

Я думаю, что вы читаете его правильно, и это совершенно и совершенно неправильно, и не только неправильно, но явно неправильно. Как это может быть правильно? Java RMI не поддерживает и не может, изменить или удалить или расширить семантику synchronized любым способом.