Java RMI и расширенная многопоточность - PullRequest
0 голосов
/ 26 августа 2018

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

1) Можно ли каким-либо образом управлять многопоточностью?

2) Создан ли поток для каждого удаленного вызова (на стороне сервера) или используются пулы потоков?

3) В целом, используя RMI, как я могу гарантировать, что некоторые вызовы rmi ожидают завершения других вызовов?

4) Есть ли другой подход без RMI, с тем же удобством и эффективностью, который бы работал лучше для этого?

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

Если, например, поток создается при каждом вызове, то я могу использовать метод соединения java для упорядочениявыполнение заявления.С другой стороны, если используются пулы потоков, то метод соединения не будет работать (поскольку потоки не завершаются).

Ответы [ 2 ]

0 голосов
/ 27 августа 2018

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

Координация зависимых задач являетсяЦентральная проблема асинхронного программирования .Поддержка асинхронного программирования в JDK не полная, но достаточная для вашей проблемы.Вам нужно использовать 2 вещи: CompletableFuture и Executor.Обратите внимание, что вызов RMI блокирует поток, в котором он выполняется, поэтому использование Исполнителя с ограниченным числом потоков может привести к взаимоблокировке определенного вида, называемой «истощение потока», когда вычисление не может продолжаться, поскольку все доступные потоки заблокированы.Так что используйте исполнителя с неограниченным количеством потоков, самый простой - тот, который создает новый поток для каждой задачи:

Executor newThreadExecutor = (Runnable r)->new Thread(r).start();

Затем для каждого вызова RMI (или любой другой задачи), объявите метод задачи.Если задача не зависит от других задач, то метод не должен иметь параметров.Если задача зависит от результатов, полученных другими задачами, объявите один или два параметра (большее количество параметров не поддерживается непосредственно CompletableFuture).Пусть у нас есть:

String m0a() {return "ok";}  // no args
Integer m0b() {return 1;}  // no args
Double m2(String arg, Integer arg2) {return arg2/2.0;}  // 2 args

Позвольте нам вычислить следующий результат:

String r0a = m0a();
Integer r0b = m0b();
Double r2 = m2(r0a, r0b);

, но асинхронно, так что вызовы m0a и m0b выполняются параллельно,и вызов m2 начинается, как только m0a и m0b завершены.

Затем заключите каждый метод задачи в экземпляр CompletableFuture В зависимости от сигнатуры метода задачи, различныеиспользуются методы CompletableFuture:

 CompletableFuture<String> t0a = CompletableFuture.supplyAsync(this::m0a, newThreadExecutor)
 CompletableFuture<Integer> t0b = CompletableFuture.supplyAsync(this::m0b, newThreadExecutor)
 CompletableFuture<Double> t2 = t0a.thenCombineAsync(t0b, this::m2, newThreadExecutor)

Выполнение задач начинается сразу после объявления, вызов специального метода start не требуется.

Для получения окончательного результата из последнегоможно использовать задачу t2, метод get() интерфейса Future:

 Double res = t2.get();
0 голосов
/ 27 августа 2018

Обзор

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

Вопрос 1 - Можно ли каким-либо образом управлять многопоточностью?

Да! Ваша реализация многопоточности может быть такой, какой вы хотите. Реализация RMI - это только взаимодействие между отдельными JVM с достаточной абстракцией, чтобы чувствовать, что они существуют в 1 JVM; таким образом, не влияет на многопоточность, поскольку это только уровень связи.

Вопрос 2. Создается ли поток для каждого удаленного вызова (на стороне сервера) или используются пулы потоков?

См. Документацию здесь . Краткий ответ, если они находятся в разных темах - нет.

Метод, передаваемый средой выполнения RMI реализации удаленного объекта, может выполняться или не выполняться в отдельном потоке. Среда выполнения RMI не дает никаких гарантий относительно отображения вызовов удаленных объектов в потоки. Поскольку удаленный вызов метода для одного и того же удаленного объекта может выполняться одновременно, реализация удаленного объекта должна убедиться, что его реализация является поточно-ориентированной.

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

Вопрос 3 - Используя RMI , как я могу гарантировать, что некоторые вызовы RMI ожидают завершения других вызовов?

Это довольно расплывчатый вопрос, но я думаю, что вы спрашиваете, как правильно блокировать синхронизацию в RMI . Это идет с вашим дизайном приложения. Давайте рассмотрим сценарий, в котором вы пытаетесь получить доступ к базе данных, и вы должны синхронизировать DB доступ. Если клиент попытается вызвать доступ через RMI , он вызовет метод удаленного сервера, который удерживает всю синхронизацию, и, таким образом, ожидает блокировки, если это необходимо. Поэтому Клиент будет ждать своей очереди для доступа к DB через сервер. Итак, в вашем текущем сценарии вы хотите, чтобы ваша синхронизация DB присутствовала на серверной стороне .

Вопрос 4 - Есть ли другой подход, не относящийся к RMI, с тем же удобством и эффективностью, который бы работал лучше для этого?

Абсолютно. Ниже приведен краткий список реализаций связи, которые можно использовать для связи.

1) RESTful

2) RMI

3) Розетки

4) gRPC

Я рекомендую использовать RESTful, поскольку он является наиболее простым и имеет множество реализаций / документации в Интернете. Эффективность, кажется, вызывает у вас серьезную озабоченность, но ваши операции манипулируют БД только стандартным образом. Поэтому я считаю, что реализация Restful обеспечит более чем достаточную эффективность.

Думайте об этом так; у вас N клиентов N, балансировщик нагрузки и M серверов. Между клиентами и серверами не существует постоянной связи, что снижает сложность и объем вычислений. По мере роста N клиентов балансировщик нагрузки создает больше экземпляров серверов и распределяет нагрузку соответствующим образом. Обратите внимание, что запросы между клиентами и серверами на самом деле довольно малы, поскольку они будут иметь полезную нагрузку и тип запроса. Кроме того, серверы будут получать запросы и вычислять операции в обычном режиме и параллельно. Оптимизация может быть выполнена на стороне сервера с помощью потоковых пулов или сред, таких как spring.

...