Spec-Zone .ru
спецификации, руководства, описания, API
|
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 выпусков, больше не заводятся в тупик потоки, и все классы загружаются успешно:
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 выпусков, можно избежать мертвых блокировок следующим эти правила:
java.lang.ClassLoader
использует схему блокировки, основанную на требуемом имени класса.java.lang.ClassLoader
's статический метод registerAsParallelCapable()
. Эта регистрация указывает, что все экземпляры Вашего пользовательского загрузчика класса мультиориентированы на многопотоковое исполнение.registerAsParallelCapable()
метод в их инициализаторах класса. Гарантируйте, что они мультиориентированы на многопотоковое исполнение для параллельной загрузки класса.Если Ваш пользовательский загрузчик класса переопределяет только findClass(String)
, Вы не нуждаетесь в дальнейших изменениях. Это - рекомендуемый механизм, чтобы создать пользовательский загрузчик класса.
Если Ваш пользовательский загрузчик класса переопределяет любого protected loadClass(String, boolean)
метод или public loadClass(String)
метод, следует также гарантировать что защищенный defineClass()
однажды метод вызывают только для каждого загрузчика класса и пары имени класса.
Если у Вашего продукта поставляет и, кажется, есть проблемы из-за неполной обработки критических разделов, можно использовать новый флаг VM -XX:+AlwaysLockClassLoader
. Этот флаг возвращается к блокировке блокировки загрузчика класса прежде, чем вызвать Ваш пользовательский загрузчик класса findClass()
или loadClass()
метод, даже для загрузчиков класса, которые регистрируются как способная параллель.