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