Spec-Zone .ru
спецификации, руководства, описания, API
Содержание документации

Многопоточные Пользовательские Загрузчики Класса в Java SE 7

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

Фон

Функция a java.lang.ClassLoader должен определить местоположение байт-кода для определенного class, затем преобразовать тот байт-код в применимый class в системе времени выполнения. Система времени выполнения обеспечивает загрузчики class, которые могут определить местоположение классов начальной загрузки, классов расширения, и пользовательских классов. CLASSPATH переменная окружения является одним способом указать к системе времени выполнения, где байт-код располагается.

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

Пользовательские загрузчики class не будут сталкиваться с мертвыми блокировками, если они будут придерживаться нециклической модели делегации загрузчика class. Нециклическая делегация что архитекторы ClassLoader предполагаемый. В этой модели у каждого загрузчика class есть родитель (делегат). Когда class требуют, загрузчик class сначала проверяет, был ли class загружен ранее. Если class не находится, загрузчик class просит, чтобы его родитель определил местоположение class. Если родитель не может найти class, загрузчик class пытается определить местоположение class непосредственно.

Сценарий мертвой блокировки

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

Class Hierarchy:
  class A extends B
  class C extends D

ClassLoader Delegation Hierarchy:

Custom Classloader CL1:
  directly loads class A 
  delegates to custom ClassLoader CL2 for class B

Custom Classloader CL2:
  directly loads class C
  delegates to custom ClassLoader CL1 for class D

Thread 1:
  Use CL1 to load class A (locks CL1)
    defineClass A triggers
      loadClass B (try to lock CL2)

Thread 2:
  Use CL2 to load class C (locks CL2)
    defineClass C triggers
      loadClass D (try to lock CL1)

Синхронизация в ClassLoader class был ранее властным, или в технических терминах, не достаточно гранулированным. Запрос, чтобы загрузить class, синхронизируемый на всем ClassLoader объект, который сделал это склонным к мертвой блокировке.

Синхронизация Загрузчика класса в Java SE 7 Выпусков

Java SE 7 выпусков включает понятие параллельного способного загрузчика class. Загрузка class параллельным способным загрузчиком class теперь синхронизируется на паре, состоящей из загрузчика class и имени class.

В предыдущем сценарии, используя Java SE 7 выпусков, больше не заводятся в тупик потоки, и все классы загружаются успешно:

Thread 1:
  Use CL1 to load class A (locks CL1+A)
    defineClass A triggers
      loadClass B (locks CL2+B)

Thread 2:
  Use CL2 to load class C (locks CL2+C)
    defineClass C triggers
      loadClass D (locks CL1+D)

Рекомендации для Многопоточных Пользовательских Загрузчиков Класса

Пользовательские загрузчики class, у которых нет истории мертвых блокировок, не требуют никаких изменений. В частности Вы не должны изменить пользовательские загрузчики class, которые следуют за рекомендуемой нециклической иерархической моделью делегации, то есть, делегируя сначала к их родительскому class. Для обратной совместимости Java SE 7 выпусков продолжают блокировать объект загрузчика class, если это не регистрируется как способная параллель.

Чтобы создать новые пользовательские загрузчики class, процесс подобен в Java SE 7 выпусков как в предыдущих выпусках. Создайте подкласс ClassLoader, тогда переопределите findClass() метод и возможно loadClass(). Переопределение loadClass() делает Вашу жизнь более трудной, но это - единственный способ использовать различную модель делегации.

Если у Вас есть пользовательский загрузчик class с риском заведения в тупик с Java SE 7 выпусков, можно избежать мертвых блокировок следующим эти правила:

  1. Гарантируйте, что Ваш пользовательский загрузчик class мультиориентирован на многопотоковое исполнение для параллельной загрузки class.
    1. Выберите внутреннюю схему блокировки. Например, java.lang.ClassLoader использует схему блокировки, основанную на требуемом имени class.
    2. Удалите всю синхронизацию на одной только блокировке объекта загрузчика class.
    3. Гарантируйте, что критические разделы безопасны для многократных потоков, загружающих различные классы.
  2. В статическом инициализаторе загрузчика Вашего пользовательского class вызвать java.lang.ClassLoader's статический метод registerAsParallelCapable(). Эта регистрация указывает, что все экземпляры Вашего пользовательского загрузчика class мультиориентированы на многопотоковое исполнение.
  3. Проверьте, что все классы загрузчика class, которые этот пользовательский загрузчик class расширяет также, вызывают registerAsParallelCapable() метод в их инициализаторах class. Гарантируйте, что они мультиориентированы на многопотоковое исполнение для параллельной загрузки class.

Если Ваш пользовательский загрузчик class переопределяет только findClass(String), Вы не нуждаетесь в дальнейших изменениях. Это - рекомендуемый механизм, чтобы создать пользовательский загрузчик class.

Если Ваш пользовательский загрузчик class переопределяет любого protected loadClass(String, boolean) метод или public loadClass(String) метод, следует также гарантировать что защищенный defineClass() однажды метод вызывают только для каждого загрузчика class и пары имени class.

Поиск и устранение неисправностей

Если у Вашего продукта поставляет и, кажется, есть проблемы из-за неполной обработки критических разделов, можно использовать новый флаг VM -XX:+AlwaysLockClassLoader. Этот флаг возвращается к блокировке блокировки загрузчика class прежде, чем вызвать Ваш пользовательский загрузчик class findClass() или loadClass() метод, даже для загрузчиков class, которые регистрируются как способная параллель.

Ссылки

Модификации API Загрузчика класса для Мертвой блокировки Фиксируют в OpenJDK

Ошибка Базы данных ошибки 4670071 Деталь

Внутренности Загрузки Класса Java, Binildas Christudas, О'Райли Медия onJava.com

Демистифицируя проблемы загрузки class, Часть 4: Мертвые блокировки и ограничения, Саймон Бернс и Лакшми Шанкар, IBM developerWorks


Oracle и/или его филиалы Авторское право © 1993, 2012, Oracle и/или его филиалы. Все права защищены.
Свяжитесь с Нами