Spec-Zone .ru
спецификации, руководства, описания, API
|
Вычислить механизм является относительно простой программой: это выполняет задачи, которые вручаются этому. Клиенты для вычислить механизма более сложны. Клиент должен вызвать вычислить механизм, но он также должен определить задачу, которая будет выполняться вычислить механизмом.
Два отдельных класса составляют клиент в нашем примере. Первый class, ComputePi
, ищет и вызывает a Compute
объект. Второй class, Pi
, реализации Task
взаимодействуйте через интерфейс и определяет работу, которая будет сделана вычислить механизмом. Задание Pi
class должен вычислить значение к некоторому числу десятичных разрядов.
Неудаленное
интерфейс определяется следующим образом:Task
package compute; public interface Task<T> { T execute(); }
Код, который вызывает a Compute
методы объекта должны получить ссылку на тот объект, создать a Task
объект, и затем запрашивает, чтобы задача была выполнена. Определение задачи class Pi
показывается позже. A Pi
объект создается с единственным параметром, требуемой точностью результата. Результатом выполнения задачи является a java.math.BigDecimal
представление вычисленного к указанной точности.
Вот исходный код для
, основной клиент class:client.ComputePi
package client; import java.rmi.registry.LocateRegistry; import java.rmi.registry.Registry; import java.math.BigDecimal; import compute.Compute; public class ComputePi { public static void main(String args[]) { if (System.getSecurityManager() == null) { System.setSecurityManager(new SecurityManager()); } try { String name = "Compute"; Registry registry = LocateRegistry.getRegistry(args[0]); Compute comp = (Compute) registry.lookup(name); Pi task = new Pi(Integer.parseInt(args[1])); BigDecimal pi = comp.executeTask(task); System.out.println(pi); } catch (Exception e) { System.err.println("ComputePi exception:"); e.printStackTrace(); } } }
Как ComputeEngine
сервер, клиент начинает, устанавливая менеджера безопасности. Этот шаг необходим, потому что процесс получения тупика удаленного объекта сервера мог потребовать загрузки определения class от сервера. Для RMI, чтобы загрузить классы, менеджер безопасности должен быть в силе.
После установки менеджера безопасности клиент создает имя, чтобы использовать, чтобы искать a Compute
удаленный объект, используя то же самое имя, используемое ComputeEngine
связывать его удаленный объект. Кроме того, клиент использует LocateRegistry.getRegistry
API, чтобы синтезировать удаленную ссылку на реестр на узле сервера. Значение первого параметра командной строки, args[0]
, имя удаленного узла на который Compute
объектные выполнения. Клиент тогда вызывает lookup
метод на реестре, чтобы искать удаленный объект по имени в реестре узла сервера. Определенная перегрузка LocateRegistry.getRegistry
используемый, у которого есть сингл String
параметр, возвращает ссылку на реестр в именованном узле и порту реестра значения по умолчанию, 1099. Следует использовать перегрузку, которая имеет int
параметр, если реестр создается на порту кроме 1099.
Затем, клиент создает новое Pi
объект, передавая к Pi
конструктор значение второго параметра командной строки, args[1]
, проанализированный как целое число. Этот параметр указывает на число десятичных разрядов, чтобы использовать в вычислении. Наконец, клиент вызывает executeTask
метод Compute
удаленный объект. Объект, который передают в executeTask
вызов возвращает объект типа BigDecimal
, который программа хранит в переменной result
. Наконец, программа печатает результат. Следующее число изображает поток сообщений среди ComputePi
клиент, rmiregistry
, и ComputeEngine
.
Pi
class реализует Task
взаимодействуйте через интерфейс и вычисляет значение к конкретному количеству десятичных разрядов. Для этого примера фактический алгоритм незначителен. То, что важно, - то, что алгоритм в вычислительном отношении дорог, означая, что Вы хотели бы выполнить его на способном сервере.
Вот исходный код для
, class, который реализует client.Pi
Task
интерфейс:
package client; import compute.Task; import java.io.Serializable; import java.math.BigDecimal; public class Pi implements Task<BigDecimal>, Serializable { private static final long serialVersionUID = 227L; /** constants used in pi computation */ private static final BigDecimal FOUR = BigDecimal.valueOf(4); /** rounding mode to use during pi computation */ private static final int roundingMode = BigDecimal.ROUND_HALF_EVEN; /** digits of precision after the decimal point */ private final int digits; /** * Construct a task to calculate pi to the specified * precision. */ public Pi(int digits) { this.digits = digits; } /** * Calculate pi. */ public BigDecimal execute() { return computePi(digits); } /** * Compute the value of pi to the specified number of * digits after the decimal point. The value is * computed using Machin's formula: * * pi/4 = 4*arctan(1/5) - arctan(1/239) * * and a power series expansion of arctan(x) to * sufficient precision. */ public static BigDecimal computePi(int digits) { int scale = digits + 5; BigDecimal arctan1_5 = arctan(5, scale); BigDecimal arctan1_239 = arctan(239, scale); BigDecimal pi = arctan1_5.multiply(FOUR).subtract( arctan1_239).multiply(FOUR); return pi.setScale(digits, BigDecimal.ROUND_HALF_UP); } /** * Compute the value, in radians, of the arctangent of * the inverse of the supplied integer to the specified * number of digits after the decimal point. The value * is computed using the power series expansion for the * arc tangent: * * arctan(x) = x - (x^3)/3 + (x^5)/5 - (x^7)/7 + * (x^9)/9 ... */ public static BigDecimal arctan(int inverseX, int scale) { BigDecimal result, numer, term; BigDecimal invX = BigDecimal.valueOf(inverseX); BigDecimal invX2 = BigDecimal.valueOf(inverseX * inverseX); numer = BigDecimal.ONE.divide(invX, scale, roundingMode); result = numer; int i = 1; do { numer = numer.divide(invX2, scale, roundingMode); int denom = 2 * i + 1; term = numer.divide(BigDecimal.valueOf(denom), scale, roundingMode); if ((i % 2) != 0) { result = result.subtract(term); } else { result = result.add(term); } i++; } while (term.compareTo(BigDecimal.ZERO) != 0); return result; } }
Отметьте, что все сериализуемые классы, реализуют ли они Serializable
взаимодействуйте через интерфейс прямо или косвенно, должен объявить a private
static
final
поле называют serialVersionUID
гарантировать совместимость сериализации между версиями. Если никакая предыдущая версия class не была выпущена, то значение этого поля может быть любым long
значение, подобное 227L
используемый Pi
, пока значение последовательно используется в будущих версиях. Если предыдущая версия class была выпущена без явного serialVersionUID
объявление, но совместимость сериализации с той версией важно, тогда значение по умолчанию, неявно вычисленное значение для предыдущей версии должно использоваться для значения явного объявления новой версии. serialver
инструмент может быть выполнен против предыдущей версии, чтобы определить значение по умолчанию вычисленное значение для этого.
Самая интересная функция этого примера то, что Compute
объект реализации никогда не нуждается Pi
Определение class до a Pi
в объекте передают как параметр executeTask
метод. В той точке код для class загружается RMI в Compute
виртуальная машина Java объекта, execute
метод вызывается, и код задачи выполняется. Результат, который в случае Pi
задачей является a BigDecimal
возразите, возвращается клиенту вызова, где это используется, чтобы напечатать результат вычисления.
Факт, что предоставленный Task
объект вычисляет значение Pi
не важно ComputeEngine
объект. Вы могли также реализовать задачу, которая, например, генерирует случайное простое число при использовании вероятностного алгоритма. Та задача также была бы в вычислительном отношении интенсивна и поэтому хороший кандидат на передачу к ComputeEngine
, но это потребовало бы совсем другого кода. Этот код мог также быть загружен когда Task
объект передают к a Compute
объект. Только способом, которым алгоритм для того, чтобы вычислить вводится при необходимости, код, который генерирует случайное простое число, был бы введен при необходимости. Compute
объект знает только, что каждый объект получает реализации execute
метод. Compute
объект не знает, и не должен знать, что делает реализация.