Содержание


Мультиарендность для виртуальных машин Java: конфигурационные опции, жизненный цикл арендатора и изоляция "в действии"

Углубленное рассмотрение мультиарендности, реализованной в продукте IBM SDK Java Technology Edition, Version 7 Release 1

Comments

Мультиарендная виртуальная машина JVM доступна со статусом tech preview в рамках пакета IBM SDK Java™ Technology Edition, Version 7 Release 1. Применение этой функции при развертывании приложений позволяет повысить производительность и улучшить изоляцию по сравнению с совместным использованием традиционной виртуальной машины JVM. Предыдущая статья по этой теме на сайте developerWorks, Введение в мультиарендность для виртуальных машин Java, содержит общий обзор следующих тем:

  • Издержки и выгоды мультиарендной JVM
  • Использование мультиарендной JVM
  • Изоляция статических полей
  • Изоляция ресурсов посредством ограничения ресурсов

В данной статье наглядно демонстрируется простота применения мультиарендности. Чтобы запустить свое Java-приложение в качестве арендатора в мультиарендной JVM, вам достаточно добавить в командной строке опцию -Xmt:

./java -Xmt Hello

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

  • Передача опций в приложение-арендатор.
  • Передача опций в демон-процесс JVM (javad), который исполняет приложения-арендаторы.
  • Ориентация приложения-арендатора на определенный демон-процесс JVM

Затем мы продемонстрируем преимущества изоляции "статики" в исполняющихся приложениях.

Учебное приложение и конфигурационные опции

Для демонстрации конфигурационных опций и для последовательного рассмотрения жизненного цикла мы будем использовать учебное приложение (которое можно компилировать и исполнять). Мы также представим командную строку для исполнения этого приложения и файл javad.options для конфигурирования демон-процесса JVM (обратитесь к разделу Материалы для загрузки, чтобы получить программный код всех примеров для этой статьи, а также команды и скрипты).

Программный код учебного приложения показан в листинге 1.

Листинг 1. Учебное приложение
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class Hello {

   public static void main(String[] args) {

      InputStreamReader inputStream = new InputStreamReader(System.in);
      BufferedReader reader = new BufferedReader(inputStream);

      System.out.println("What is your name?");

      try {
         String name = reader.readLine();
         System.out.println("Hello " + name);
      } catch (IOException e) {
         e.printStackTrace();
      }
   }
}

Командная строка для запуска приложения в качестве арендатора имеет следующий вид:

java -Xmt -Djavad.home=/tmp/multitenant_daemons -Xmx100M 
-Xlimit:netIO=5M-100M -DexampleProperty=1 -jar hello.jar

Опции командной строки java -Xmt влияют только на приложение-арендатор. Посмотрим, что делают эти опции.

-Xmt
Дает указание модулю запуска Java (Java launcher) запустить данное приложение в качестве приложения-арендатора.
-Djavad.home=/tmp/multitenant_daemons
Задает конкретный демон-процесс JVM. Если опция -Djavad.home не используется, то все арендаторы, исполняемые данным пользователем, будут исполняться одним и тем же демоном JVM.
-Xmx100M
Дает указание демон-процессу JVM ограничить выделяемую этому арендатору долю кучи объектов JVM величиной 100 МБ. Общий размер кучи объектов JVM задается в файле javad.options. Если этот арендатор попытается использовать в куче более 100 МБ, он получит ошибку OutOfMemoryError (OOME), однако это не повлияет ни на каких других арендаторов, исполняемых данным демоном.
-Xlimit:netIO=5M-10M
Дает указание демону JVM зарезервировать для этого арендатора пропускную способность сетевого ввода/вывода в размере 5 МБ/с (но не более 10 МБ/с). Если демон JVM не сможет зарезервировать эту минимальную пропускную способность, то модуль запуска этого арендатора (tenant launcher) получит сообщение об ошибке, в результате чего данное приложение-арендатор не будет запущено.
-DexampleProperty=1
Делает это свойство Java видимым только этому арендатору. Ни один из других арендаторов, исполняющихся в этом экземпляре демон-процесса JVM, не сможет увидеть данное свойство.

Единственный способ передачи опций в сам демон-процесс JVM состоит в использовании файла javad.options. В листинге 2 показан файл javad.options для демона JVM, который будет исполнять наше учебное приложения.

Листинг 2. Файл javad.options
# Option file for javad
-Xtenant
-Xrcm:consumer=autotenant
-Djavad.persistAfterEmptyTime=1
-Xmx2G
-Xdump:java:label=/tmp/multitenant_daemons/javacore.%pid.%seq.txt

Теперь посмотрим, что делают опции файла javad.options.

-Xtenant -Xrcm:consumer=autotenant
Дает экземпляру JVM, который служит демон-процессом, указание исполняться в мультиарендном режиме.
-Djavad.persistAfterEmptyTime=1
Дает демон-процессу JVM указание завершиться спустя одну минуту после выключения последнего арендатора.
-Xmx2G
Задает максимальный размер кучи объектов для демона JVM, равный 2 ГБ. Все арендаторы, исполняемые данным демоном JVM, будут использовать части этой кучи объектов, общий объем которой составляет 2 ГБ.
-Xdump:java:label=/tmp/multitenant_daemons/javacore.%pid.%seq.txt
Присваивает указанное имя файла javacore-файлам, которые генерирует демон JVM. Более подробные сведения об этой опции содержатся в разделе справочной системы user guide (Использование опции -Xdump).

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

Настройка среды

Поскольку в командной строке для исполнения нашего приложения задана опция -Djavad.home (чтобы ориентировать его на определенный демон-процесс JVM), вам необходимо создать каталог -Djavad.home:

mkdir /tmp/multitenant_daemons

Затем перейдите в каталог /tmp/multitenant_daemons, скопируйте в этот каталог файл javad.options (включенный в пакет SDK) и добавьте наши дополнительные опции.

cd /tmp/multitenant_daemons
cp /tmp/Java7R1_SR1/jre/bin/javad.options .
echo -Djavad.persistAfterEmptyTime=1 >> javad.options
echo -Xdump:java:label=/tmp/multitenant_daemons/javacore.%pid.%seq.txt >> javad.options
echo -Xmx2G >> javad.options

Запустите cat javad.options и исследуйте содержимое файла javad.options, чтобы убедиться в его корректности.

# Файл опций для демона javad
-Xtenant
-Xrcm:consumer=autotenant
-Djavad.persistAfterEmptyTime=1
-Xdump:java:label=/tmp/multitenant_daemons/javacore.%pid.%seq.txt
-Xmx2G

На данный момент созданный нами каталог -Djavad.home содержит только файл javad.options. После запуска демон-процесса JVM он запишет в этот каталог информацию о соединении.

Исследование жизненного цикла арендатора

Теперь, когда вы сконфигурировали свою среду, а также имеете пример приложения и конфигурацию, мы можем приступить к исследованию жизненного цикла. Основные стадии жизненного цикла перечислены ниже.

  1. Модуль запуска арендатора и запуск демона JVM
  2. Исполнение приложения
  3. Завершение работы арендатора
  4. Завершение работы демона JVM

Стадия 1. Модуль запуска арендатора и запуск демона JVM

При запуске Java-приложения в качестве арендатора (с помощью опции командной строки -Xmt) модуль запуска арендатора проверяет наличие исполняющегося демон-процесса JVM. Если этот процесс не исполняется, модуль запуска арендатора запускает его. После запуска демон-процесса JVM между ним и модулем запуска арендатора производится определенное "квитирование". В рамках этого квитирования опции среды процесса запуска и командной строки арендатора передаются демону JVM. И, наконец, демон-процесс JVM осуществляет исполнение приложения-арендатора.

Рассмотрим эту последовательность более подробно в контексте нашего учебного приложения. Начнем с исполнения командной строки для модуля запуска арендатора (вводится в одну строку):

java -Xmt -Djavad.home=/tmp/multitenant_daemons -Xmx100M -Xlimit:netIO=5M-100M 
-DexampleProperty=1 -jar /tmp/hello.jar

Модуль запуска Java видит в этой командной строке опцию -Xmt и превращается в модуль запуска арендатора.

Модуль запуска арендатора видит опцию -Djavad.home=/tmp/multitenant_daemons в результате чего обращается в каталог /tmp/multitenant_daemons, чтобы определить, не ассоциирован ли какой-либо демон-процесс JVM с этим пользователем и с этим каталогом. Установив, что такого демон-процесса JVM не существует, модуль запуска запускает соответствующий процесс. Напоминаем, что опции, содержащиеся в файле javad.options, передаются в демон-процесс JVM.

После запуска демон-процесса JVM он извещает о себе, записывая информацию о соединении в каталог -Djavad.home. Для хранения этой информации о соединении он создает новый каталог вида .java.uid. Например, в данном случае новый каталог имеет имя .javad.4068, где 4068 — это идентификатор текущего пользователя (UID).

dave /tmp/multitenant_daemons  $ ls -altr
total 32
-rwxr-xr-x 1 dave bgroup 164 Jun 26 17:04 javad.options
drwxrwxrwt. 10 root root 20480 Jun 26 17:05 ..
drwxr-xr-x 3 dave bgroup 4096 Jun 26 17:05 .
drwxr-xr-x 2 dave bgroup 4096 Jun 26 17:05 .javad.4068
dave /tmp/multitenant_daemons $

Этот идентификатор UID используется для ассоциирования демон-процесса JVM с текущим пользователем. Другие пользователи не имеют возможности соединиться с этим демон-процессом JVM, поскольку доступ к содержимому каталога.java.4068 разрешен только тому пользователю, который инициировал создание этого демона JVM.

dave /tmp/multitenant_daemons $ ls -altr .javad.4068
total 12
drwxr-xr-x 3 dave bgroup 4096 Jun 26 17:05 ..
drwxr-xr-x 2 dave bgroup 4096 Jun 26 17:05 .
-rw------- 1 dave bgroup 103 Jun 26 17:05 4068
dave /tmp/multitenant_daemons $

Модуль запуска арендатора читает информацию о соединении в каталоге .javad.4068 и создает сокет для соединения с демон-процессом JVM. Все последующее взаимодействие между модулем запуска арендатора и демон-процессом JVM происходит через этот сокет при посредстве заданного внутри него wire-протокола.

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

Демон JVM прочитывает опцию -Xlimit:netIO=5M-100M и проверяет, способен ли он удовлетворить минимальное требование к пропускной способности (5 МБ/с). Демон выполняет эту проверку, удостоверяясь, что сумма минимальных потребностей всех арендаторов в пропускной способности не превышает значения, заданного в файле rcm.xml.

После этого демон JVM создает арендатора для запуска Java-приложения, указанного модулем запуска арендатора.

На заключительном этапе запуска осуществляется перенаправление файлов приложения арендатора System.out, System.in и System.err в канал сокета, который связывает модуль запуска арендатора и демон-процесс JVM.

Стадия 2. Исполнение приложения

К этому моменту JVM готова к исполнению приложения, поэтому демон JVM осуществляет вызов метода main в недавно созданном арендаторе. Посмотрим, что происходит в каждом разделе кода в листинге 1.

В первом разделе выполняется контрольное считывание сообщения.

public static void main(String[] args) {

   InputStreamReader inputStream = new InputStreamReader(System.in);
   BufferedReader reader = new BufferedReader(inputStream);

   System.out.println("What is your name?");

Демон JVM перехватывает запись этого сообщения в файл System.out и перенаправляет ее по сокету в модуль запуска арендатора. Модуль запуска арендатора пишет в своей консоли фразу "What is your name?" (Как твое имя?).

dave /tmp/multitenant_daemons $ /tmp/Java7R1_SR1/jre/bin/java 
-Xmt -Djavad.home=/tmp/multitenant_daemons -Xmx100M -Xlimit:netIO=5M-100M 
-DexampleProperty=1 -jar /tmp/hello.jar
What is your name?

В следующем разделе осуществляется чтение стандартной входной информации.

String name = reader.readLine();

Демон JVM перехватывает этот запрос к файлу System.in и отсылает в модуль запуска арендатора сообщение о том, что он ждет ввода информации от пользователя.

Сбор информации для отладки

Пока приложение ждет ввода информации от пользователя, позволим себе немного отклониться от основного маршрута и рассмотрим возможности получения информации об исполняющемся приложении, которая может быть полезна при отладке. Начнем с отображения модуля запуска арендатора на демон-процесс JVM (javad), который исполняет наше приложение. Это отображение полезно, если вы хотите сгенерировать javacore-файл, чтобы видеть, что делает демон-процесс JVM.

Используйте команду ps -ef для нахождения идентификатора ID демон-процесса JVM, который соответствует модулю запуска арендатора. Этот демон и этот модуль запуска могут быть отображены друг на друга, поскольку они имеют один и тот же каталог -Djavad.home. Затем подайте команду SIGQUIT:

dave /tmp/multitenant_daemons $ ps -ef | grep javad
dave 5092 3632 0 17:05 pts/1 00:00:00 /tmp/Java7R1_SR1/jre/bin/java -Xmt 
-Djavad.home=/tmp/multitenant_daemons -Xmx100M 
-Xlimit:netIO=5M-100M -DexampleProperty=1 -jar /tmp/hello.jar
dave 5094 5092 2 17:05 ? 00:00:01 /tmp/Java7R1_SR1/jre/bin/javad -Djavad.home=/tmp/multitenant_daemons
dave 5164 3543 0 17:07 pts/0 00:00:00 grep javad
dave /tmp/multitenant_daemons $ kill -QUIT 5094
dave /tmp/multitenant_daemons $

Демон-процесса JVM получает SIGQUIT и генерирует файл javacore в каталоге, который задает опция -Xdump в файле javad.options. Сообщения JVMDUMP транслируются в модуль запуска арендатора.

dave /tmp/multitenant_daemons $ /tmp/Java7R1_SR1/jre/bin/java -Xmt 
-Djavad.home=/tmp/multitenant_daemons -Xmx100M -Xlimit:netIO=5M-100M 
-DexampleProperty=1 -jar /tmp/hello.jar
What is your name?
JVMDUMP039I Processing dump event "user", detail "" at 2014/06/26 17:07:20 - please wait.
JVMDUMP032I JVM requested Java dump using 
'/tmp/multitenant_daemons/javacore.5094.0001.txt' in response to an event
JVMDUMP010I Java dump written to /tmp/multitenant_daemons/javacore.5094.0001.txt
JVMDUMP013I Processed dump event "user", detail "".

Все сообщения JVMDUMP транслируются всем модулям запуска арендатора, которые соединены с данным демоном JVM. Таким образом, в случае сбоя демона-процесса JVM все модули запуска арендатора получают соответствующее уведомление.

Идентифицировав демон-процесс JVM (javad) и настроив опции дампа в файле javad.options, вы можете использовать этот способ для получения любых стандартных диагностических сведений JVM при исполнении мультиарендной JVM.

Возвращение к исполнению

Теперь вернемся к рассмотрению исполнения метода main. Введите слово Dave, которое модуль запуска арендатора отсылает демон-процессу JVM.

Демон-процесс JVM принимает слово Dave и направляет его в файл System.in для приложения-арендатора.

После этого приложение-арендатор пишет фразу Hello Dave в файл System.out:

System.out.println("Hello " + name);

Демон JVM перехватывает эту запись в файл System.out и перенаправляет ее по сокету в модуль запуска арендатора.

Модуль запуска арендатора получает фразу Hello Dave и выводит ее в своей консоли. Теперь метод main выполнен, и арендатор переходит к стадии завершения работы.

Стадия 3. Завершение работы арендатора

Основное различие между завершением работы приложения, исполняющегося в мультиарендной среде, и завершением работы приложения, исполняющегося в обычной JVM, состоит в том, в случае мультиаренды демон-процесс JVM, исполняющий Java-приложение, не завершается вместе с этим приложением.

Однако с точки зрения Java-приложения, которое исполняется как арендатор, его поведение является точно таким же.

  1. Приложение ждет завершения своих потоков, не относящихся к демонам.
  2. Демон JVM исполняет shutdown-ловушки приложения (shutdown hook).
  3. Демон JVM завершает все оставшиеся потоки демонов приложения.
  4. Модуль запуска арендатора завершается с кодом выхода, который задается Java-приложением.

Четвертый шаг выполняет демон JVM, который отсылает в модуль запуска арендатора сообщение с кодом выхода приложения. В данном примере модуль запуска арендатора завершается с кодом выхода 0.

dave /tmp/multitenant_daemons $ /tmp/Java7R1_SR1/jre/bin/java -Xmt -Djavad.home=
/tmp/multitenant_daemons -Xmx100M -Xlimit:netIO=5M-100M -DexampleProperty=1 -jar /tmp/hello.jar
What is your name?
JVMDUMP039I Processing dump event "user", detail "" at 2014/06/26 17:07:20 - please wait.
JVMDUMP032I JVM requested Java dump using '/tmp/multitenant_daemons/javacore.5094.0001.txt' 
in response to an event
JVMDUMP010I Java dump written to /tmp/multitenant_daemons/javacore.5094.0001.txt
JVMDUMP013I Processed dump event "user", detail "".
Dave
Hello Dave
dave /tmp/multitenant_daemons $ echo $?
0
dave /tmp/multitenant_daemons $

Стадия 4. Завершение работы демона JVM

По умолчанию продолжительность функционирования демона JVM не ограничена. Однако в этом примере в файле javad.options задана опция -Djavavd.persistAfterTime=1. Вследствие этого демон-процесс JVM завершается спустя одну минуту после того, как приложение-арендатор заканчивает свою работу. Если до истечения тайм-аута подключится другой модуль запуска арендатора, одноминутный таймер будет запущен снова, когда к нему не будет подключено никаких арендаторов.

На этом мы завершаем наше "погружение" в жизненный цикл арендатора. В следующем разделе мы рассмотрим принудительную изоляцию между арендаторами, исполняемыми в одном и том же демоне JVM.

Изоляция "в действии"

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

Мультиарендная JVM создает уровень изоляции между арендаторами, ограничивая возможности конкретного приложения непосредственно влиять на функционирование других приложений. В этом разделе преимущества этой ключевой функции рассматриваются на примерах программного кода, которые вы можете скомпилировать и выполнить самостоятельно. Чтобы выполнить эти примеры, загрузите поддерживающий Java-код и Linux-скрипты.

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

Листинг 3. Два простых приложения
public class StillHere extends ExampleBase {
   public static void main(String[] args) {
      while(notDone()) {
         println(args, "Still Here");
         sleep(SECONDS_2);
      }
      println(args, "Done");
   }
}

public class Goodbye extends ExampleBase {
   public static void main(String[] args) {
      println(args, "Hello");
      sleep(SECONDS_4);
      println(args, "About to exit, Goodbye");
      System.exit(-1);
   }
}

Первое приложение печатает слова Still Here каждые две секунды вплоть до момента своего завершения. Второе приложение печатает слово Hello, а затем ждет четыре секунды и осуществляет вызов System.exit(). Эти (несомненно, "игрушечные") приложения представляют собой примеры следующих категорий приложений.

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

Эти два приложения исполняются одновременно в одном и том же процессе javad, если они были запущены с помощью следующих командных строк:

./java -Xmt -cp isolationExamples.jar StillHere app1 & 
./java -Xmt -cp isolationExamples.jar Goodbye app2

В качестве альтернативного варианта эти два приложения можно было бы исполнять в обычной JVM. Сначала эти приложения необходимо поместить в класс-обертку (см. листинг 4).

Листинг 4. Класс-обертка для исполнения двух вышеупомянутых приложений в обычной JVM
public class HelloGoodBye extends StandardJVMRunner{
   public static void main(final String[] args) {
      Thread stillHereThread = new Thread() {
         public void run() { StillHere.main(APP1); }
      };
      
      Thread goodByeThread = new Thread() {
         public void run() { Goodbye.main(APP2); }
      };
      stillHereThread.start();
      goodByeThread.start();
   }
}

Затем их нужно запустить на исполнение с помощью следующей командной строки.

./java -cp isolationExamples.jar HelloGoodBye

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

Run in normal JVM
app1 [Still Here]
app2 [Hello]
app1 [Still Here]
app2 [About to exit, Goodbye]
app1 [Still Here]
app1 [Still Here]

Обратите внимание, что вскоре после того, как приложение app2 осуществляет вызов System.exit(), вы перестаете видеть выходную информацию от приложения app1. Это объясняется тем, что вызов System.exit() в приложении app2 приводит к завершению совместно используемого процесса JVM, что включает в себя завершение работы приложения app1. Это предельный случай способности одного приложения непосредственно влиять на другое приложение. Отсутствие изоляции приводит к тому, что приложение Goodbye завершает приложение Still Here.

Теперь запустим оба этих приложения в мультиарендной JVM.

Run in MT JVM
app1 [Still Here]
app2 [Hello]
app1 [Still Here]
app1 [Still Here]
app2 [About to exit, Goodbye]
dave /tmp/dave/apr16/jre/bin $ app1 [Still Here]
app1 [Still Here]
app1 [Still Here]
app1 [Still Here]
app1 [Still Here]
app1 [Done]

Можно видеть, что приложение app1 продолжает исполняться после вызова System.exit() в приложении app2, вплоть до момента своего нормального завершения и вывода на печать слова Done. Изоляция, обеспечиваемая мультиарендной JVM, позволяет приложению Goodbye исполнять существующий код и завершать свою работу, не оказывая влияния на другое приложение, которое исполняется в том же процессе.

Мультиарендная JVM предоставляет одиночный процесс в совместное пользование. Это позволяет приложению осуществлять вызовы, которые влияют на этот процесс JVM обычным образом, но при этом ограничивает их последствия для самого приложения. System.exit()— это простой пример, однако этот же принцип действует и в других случаях (shutdown-ловушки, системный ввод/вывод и т. д.). Как можно видеть в этом примере, данная функция ограничивает способность одного приложения влиять на другие приложения, не требуя изменений в самих приложениях. Возможность исполнения приложений в неизменном виде или с весьма ограниченными изменениями — это одно из ключевых преимуществ, которые дает изоляция.

Теперь рассмотрим несколько более сложный пример: поддержку разных (естественных) языков в каждом из двух приложений. В листинге 5 показаны оба этих приложения.

Листинг 5. Приложения, использующие различные языки
 public class OutputInDefaultLocale extends ExampleBase {
   public static void main(String[] args) {
      while(notDone()) {
         Locale localeToUse = Locale.getDefault(); 
         ResourceBundle messages = ResourceBundle.getBundle("Messages",localeToUse);
         println(args, messages.getString( "HELLO_KEY"));
         sleep(SECONDS_2);
      }
      println(args, "Done");
   }
}
public class ChangeLocale extends ExampleBase {
   public static void main(String[] args) {
      try { Thread.sleep(SECONDS_4); } catch (Exception e) {};
      println(args, "Changing default locale from:" + Locale.getDefault());
      Locale.setDefault(new Locale("fr","CA"));
      println(args, "Locale is now:" + Locale.getDefault());
      OutputInDefaultLocale.main(args);
   }
}

Пакетные файлы:

Messages.properties  -  content ? HELLO_KEY=Hello
Messages_fr.properties? content ? HELLO_KEY=Bonjour

Первое приложение (OutputInDefaultLocale) получает локаль по умолчанию и каждые две секунды выводит слово Hello на языке по умолчанию вплоть до момента своего завершения. Второе приложение (ChangeLocale) ждет четыре секунды, а затем изменяет локаль по умолчанию на локаль для французского языка, в результате чего его последующие записи Hello выводятся как Bonjour.

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

./java -Xmt -cp isolationExamples.jar OutputInDefaultLocale app1 & 
./java -Xmt -cp isolationExamples.jar ChangeLocale app2

Кроме того, эти приложения также можно исполнять в стандартной JVM с использованием обертки, показанной в листинге 6.

Листинг 6. Обертка для исполнения приложений OutputInDefaultLocale и ChangeLocale
public class LocaleIssues extends StandardJVMRunner {
   public static void main(final String[] args) {
      Thread outputInDefaultLocalThread = new Thread() {
         public void run() { OutputInDefaultLocale.main(APP1); }
      };
      
      Thread changeLocaleThread = new Thread() {
         public void run() { ChangeLocale.main(APP2); }
      };
      
      outputInDefaultLocalThread.start();
      changeLocaleThread.start();
   }
}

Командная строка для исполнения приложений без использования мультиарендности имеет следующий вид:

./java -cp isolationExamples.jar LocaleIssues

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

Run in normal JVM
app1 [Hello]
app1 [Hello]
app2 [Changing default locale from:en_US]
app2 [Locale is now:fr_CA]
app2 [Bonjour]
app1 [Bonjour]
app2 [Bonjour]
app1 [Bonjour]
app2 [Bonjour]
app1 [Bonjour]
app2 [Done]
app1 [Done]

Первое приложение начинает исполняться и выводит информацию на английском языке, поскольку по умолчанию применяется локаль en_US. После того, как второе приложение завершает свое четырехсекундное ожидание, оно изменяет текущую локаль на локаль для французского языка fr_CA. Начиная с этого момента оба приложения выводят информацию на французском языке. Подождите — мы хотели совсем не этого! Тем не менее этот результат вполне закономерен, поскольку оба приложения используют JVM совместно, имеется лишь одна локаль по умолчанию.

Теперь запустим эти же приложения с функцией мультиарендности.

Run in MT JVM
app1 [Hello]
app1 [Hello]
app2 [Changing default locale from:en_US]
app2 [Locale is now:fr_CA]
app2 [Bonjour]
app1 [Hello]
app2 [Bonjour]
app1 [Hello]
app2 [Bonjour]
app1 [Hello]
app1 [Done]
app2 [Bonjour]
app2 [Done]

После того как второе приложение изменяет локаль по умолчанию, первое приложение продолжает выводить сообщение на английском языке, в то время как второе приложение осуществляет вывод на французском языке. Это именно то, чего мы хотели. Изоляция, обеспечиваемая мультиарендной JVM, позволяет этим приложениям совместно использовать один и тот же процесс с корректным поведением и без необходимости внесения изменений в приложения. В этом случае локаль по умолчанию хранится в статическом виде, а изоляция статики, обеспечиваемая функцией мультиарендности, позволяет каждому приложению (арендатору) использовать свою собственную локаль.

Заключение

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

Мы настоятельно рекомендуем вам загрузить мультиарендную JVM, опробовать демонстрационные примеры, получить документацию и написать свои собственные приложения. Кроме того, вы можете присоединиться к сообществу IBM multitenant JVM community, чтобы всегда быть в курсе последней доступной информации и представлять свои рекомендации, которые помогут сформировать направление дальнейшего развития этой технологии.


Ресурсы для скачивания


Похожие темы


Комментарии

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

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=Технология Java, Облачные вычисления
ArticleID=996863
ArticleTitle=Мультиарендность для виртуальных машин Java: конфигурационные опции, жизненный цикл арендатора и изоляция "в действии"
publish-date=02042015