Java RMI и вопросы синхронизации потоков - PullRequest
5 голосов
/ 16 февраля 2010

На самом деле у меня есть два вопроса о Java RMI и синхронизации потоков:

1) Если я реализую свои удаленные методы RMI как синхронизированные, гарантированно ли они будут взаимоисключающими? Мне нужно убедиться, что ни один из моих методов RMI (методов, предлагаемых клиентам) не выполняется одновременно.

2) У меня есть метод, который сервер периодически выполняет. Он используется для очистки. Я должен убедиться, что этот конкретный метод не выполняется, когда какой-либо метод RMI запускается / используется удаленными клиентами. Кроме того, когда этот метод работает, вызовы RMI не должны быть возможными. То есть Клиенты должны ждать. Есть идеи, как я могу это сделать? Я читал о замках, но не знаю, как их использовать в этом сценарии.

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

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

Спасибо за ваше время и ответы.

Ответы [ 4 ]

11 голосов
/ 16 февраля 2010

1) Если я реализую свой пульт RMI методы как синхронизированы, они гарантированно будет взаимоисключающим? я нужно убедиться, что нет двух моих Методы RMI (методы, предлагаемые для клиенты) выполняют одновременно.

RMI не предоставляет такой гарантии самостоятельно (в отличие от EJB), и два вызова одного и того же удаленного объекта могут выполняться одновременно, если вы не реализуете некоторую синхронизацию. Ваш подход верен, и синхронизация всех методов действительно гарантирует, что никакие два из них не будут работать одновременно на одном и том же объекте. Примечание. Одно ключевое слово synchronized эквивалентно synchronized( this ).

.

2) У меня есть метод, который сервер выполняется периодически. Используется для делать уборки. Я должен убедиться, что этот конкретный метод не выполнить, когда есть какой-либо метод RMI выполняется / используется удаленными клиентами.

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

protected Object lock = new Object();

По соглашению, люди используют Object для этой цели. Затем вам нужно захватить блокировку вашей периодической работы с помощью synchronized( remoteObj.lock ) { ... }, предполагая, что она находится в том же пакете.

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

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

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

Если я хорошо понимаю, вы хотели бы, чтобы логика очистки была статическим методом? Статический метод только с synchronized захватывает блокировку класса. «Обычный» метод с synchronized захватывает блокировку экземпляра объекта. Это не те же самые скрытые блокировки!

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

Скелет:

public class MyRemoteClass {
   public static Object lock = new Object();

   public void doStuff()
   {
       synchronized( lock ) { ... }
   }
}

public class Cleanup {
   public static void doIt()
   {
       synchronized( MyRemoteClass.lock ) { ... }
   }
}
2 голосов
/ 16 февраля 2010
  1. Для каждого вызова от клиента RMI сервер RMI будет выполнять вызов в новом потоке.Вам нужно только синхронизировать доступ к общим объектам.

  2. Другой поток или таймер не остановит ваш сервер от приема вызовов со стороны клиента.Это требует синхронизации, наилучшая практика зависит от того, как долго выполняется задание очистки, может ли оно быть прервано, или будет ли возможность поместить запросы в очередь и т. Д. Самый простой способ - позволить методам RMI ожидать блокировки, как уже было выполнено.описывается ewernli.

РЕДАКТИРОВАТЬ: Согласно вашему комментарию, скелет, который демонстрирует, как достичь этого вида базовой синхронизации.Поскольку все теперь является взаимоисключающим, вы не можете ожидать высокой производительности с участием нескольких клиентов.В любом случае это будет соответствовать вашим требованиям.(Я надеюсь).Если ваш проект расширяется, вы должны прочитать Учебник по параллелизму

Object mutex = new Object();

int rmiMethod1() {
    synchronized (mutex) {
        doWhatNeeded1();
    }
}

int rmiMethod2() {
    synchronized (mutex) {
        doWhatNeeded2();
    }
}

// in your cleanup thread
void run() {
    synchronized (mutex) {
        cleanUp();
    }
}
0 голосов
/ 16 мая 2011

Чтобы прояснить всю эту путаницу:

  1. Если вы синхронизируете свои реализации удаленных методов, одновременно может выполняться только один клиент.

  2. Если вы синхронизируете задачу очистки на удаленном объекте, она присоединяется (1).

  3. Вы не можете определять удаленные методы как статические.

0 голосов
/ 13 ноября 2010

Следует помнить, что RMI создает иллюзию «удаленного объекта», но на самом деле существует не менее трех объектов: локальная заглушка, удаленный скелет и фактический удаленный объект. В качестве компромиссного решения эта иллюзия не завершена и блокирует только локальную заглушку . Синхронизация по сети отсутствует. Поищите в интернете синхронизированные RMI + заглушка +, и вы найдете множество объяснений, например, таких:

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

Так что вам нужно самостоятельно реализовать не-RMI, чисто серверную синхронизацию. Затем вы можете вызывать эти чистые блокировки на стороне сервера из ваших удаленных методов; но вам нужен дополнительный уровень косвенности.

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

...