многопоточность Java на дом apis - PullRequest
3 голосов
/ 18 ноября 2010

У меня есть функция, которая выполняет анализ XML. Я хочу сделать функцию потока безопасной, но также максимально оптимизированной (меньше блокирующих).
В кратком коде это что-то следующее:

public Document doXML(InputStream s)
{
//Some processing.
  DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
  DocumentBuilder parser = factory.newDocumentBuilder();
  Document xmlDoc = parser.parse(is);
  return xmlDoc;

}

Но я не хочу создавать новый DocumentBuilderFactory или DocumentBuilder при каждом вызове.
Я хочу повторно использовать фабрику и парсер, но я не уверен, что они потокобезопасны. Так какой же самый оптимальный подход?
1) Кэшировать DocumentBuilderFactory в поле класса и синхронизировать factory.newDocumentBuilder (); так что каждый поток имеет свой экземпляр DocumentBuilder
2) Кэширование DocumentBuilderFactory и DocumentBuilder и синхронизация parser.parse (is); для потока
Я думаю (2) лучше, но безопасно ли это делать? Также я могу избежать блокировки синхронизированными? Я бы хотел, чтобы это было как можно быстрее.

Спасибо

Ответы [ 4 ]

4 голосов
/ 18 ноября 2010

Если вы повторно используете поток (как в пуле потоков), вы можете объявить ваш DocumentBuilderFactory как локальный поток.Существуют издержки на создание нового набора для каждого потока, но, как я уже сказал, если вы пересматриваете, последующие издержки очень малы.

final ThreadLocal<DocumentBuilderFactory> documentBuilderFactor = new ThreadLocal<DocumentBuilderFactory>(){
     public DocumentBuilderFactory  initialValue(){
       return  DocumentBuilderFactory.newInstance();
     }
}

public Document doXML(InputStream s)
{
//Some processing.
  DocumentBuilderFactory factory = documentBuilderFactor.get();
  DocumentBuilder parser = factory.newDocumentBuilder();
  Document xmlDoc = parser.parse(is);
  return xmlDoc;

}

Здесь вы создадите только один DocumentBuilderFactory для каждого потока.

Я не знаю, является ли DocumentBuilder потокобезопасным при разборе (является ли он неизменным?).Но если DocumentBuilder является потокобезопасным при синтаксическом анализе, вы можете использовать тот же механизм, что и я.

Это разрешение сделает общую пропускную способность максимально быстрой.

Примечание. Это не было проверено или скомпилированопросто дает представление о том, что я имею в виду.

2 голосов
/ 18 ноября 2010

2) будет поточно-ориентированным, но ваше приложение сможет анализировать только один документ за раз.

Почему бы просто не использовать ваш код?Имеет ли

DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder parser = factory.newDocumentBuilder();

явно неприемлемые издержки?

1 голос
/ 18 ноября 2010

Я столкнулся с некоторыми проблемами с производительностью в аналогичной ситуации. Я создавал фабричные объекты при каждом использовании, чтобы избежать проблем с потоками (10 секунд в секунду). Реализация XML в этой (по общему признанию) платформе выполняла довольно медленную логику поиска для класса поставщика услуг.

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

-Djavax.xml.parsers.DocumentBuilderFactory=com.example.FactoryClassName
-Djavax.xml.transform.TransformerFactory=com.example.OtherFactoryClassName

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

Это все еще нужно? Требует тестирования в вашей среде. Я использовал ферму в Solaris, чтобы заметить очень частые файловые операции, возникающие в результате этой логики поиска.

1 голос
/ 18 ноября 2010

Если вы хотите избежать синхронизированной блокировки, убедитесь, что вы используете атомарные операции.Поведение javax.xml.parser.* зависит от реализации (вы можете указать реализацию, используя системные свойства, или вызвать код реализации).В зависимости от количества потоков и веса нагрузки для каждого потока может быть целесообразно контролировать создание объекта синтаксического анализатора.Вы должны выбрать между созданием нового парсера или ожиданием парсера.Код может создать пул парсеров при запуске, а затем потоки получают парсеры из пула, который блокируется, когда нет свободного парсера.Как только поток получает анализатор, он анализирует данные, сбрасывает анализатор и возвращает его в пул.Вы всегда можете контролировать время / использование памяти по длине пула.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...