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

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

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

Фон

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

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

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

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

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

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 класс был ранее властным, или в технических терминах, не достаточно гранулированным. Запрос, чтобы загрузить класс, синхронизируемый на всем ClassLoader объект, который сделал это склонным к мертвой блокировке.

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

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

В предыдущем сценарии, используя 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)

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

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

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

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

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

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

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

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

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

Ссылки

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

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

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

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


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