SAXParser线程变量化提高xml解析性能和吞吐量 SAXParser线程变量化提高xml解析性能和吞吐量

SAXParser线程变量化提高xml解析性能和吞吐量

xml的解析是Java程序员平常遇到的一个问题。对于解析性能也是我们比较关注的。下面是其中的一个优化点。

  1. package bestree.love;
  2. import java.io.IOException;
  3. import java.io.InputStream;
  4. import javax.xml.parsers.ParserConfigurationException;
  5. import javax.xml.parsers.SAXParser;
  6. import javax.xml.parsers.SAXParserFactory;
  7. import org.xml.sax.SAXException;
  8. import org.xml.sax.helpers.DefaultHandler;
  9. /**
  10. * XML解析性能优化。
  11. *
  12. * @author bestree007
  13. *
  14. */
  15. public class ParserThreadLocal {
  16. // usually we parse XML in this way.
  17. public void parseXml(InputStream input) {
  18. SAXParserFactory factory = SAXParserFactory.newInstance();
  19. factory.setNamespaceAware( true);
  20. try {
  21. DefaultHandler handler = new DefaultHandler();
  22. SAXParser parser = factory.newSAXParser();
  23. parser.parse(input, handler);
  24. // next use the parser to parse the xml source.
  25. } catch (ParserConfigurationException e) {
  26. e.printStackTrace();
  27. } catch (SAXException e) {
  28. e.printStackTrace();
  29. } catch (IOException e) {
  30. e.printStackTrace();
  31. }
  32. }
  33. }

通常我们使用类似的方式进行xml的sax的解析,这里需要关注的是每次完成factory和parser的初始化,这块是比较耗费性能的。在进行高并发性能测试时,多数的线程会在初始化parser时blocked住。

我们首先会想到的一个问题是,复用parser,这里需要关注是saxparser并不是线程安全的, 非线程安全的意思是,多线程访问同一个saxparser实例时会导致实例状态从单个线程的角度来看是错乱的不可预期的。

      通过查阅很多资料,最终发现除了在初始化时配置一下xml解析的参数提高性能外(这里不进行讨论),另一个办法是将saxparser作为线程本地变量,即ThreadLocal变量,特别适用于线程池下多线程调用时,由于线程的复用,对于同一个线程来说,可以只初始化一次,大幅度提高解析性能。

下面是事例。

  1. package bestree.love;
  2. import java.io.IOException;
  3. import java.io.InputStream;
  4. import javax.xml.parsers.ParserConfigurationException;
  5. import javax.xml.parsers.SAXParser;
  6. import javax.xml.parsers.SAXParserFactory;
  7. import org.xml.sax.SAXException;
  8. import org.xml.sax.helpers.DefaultHandler;
  9. /**
  10. * XML解析性能优化。
  11. *
  12. * @author bestree007
  13. *
  14. */
  15. public class ParserThreadLocalCase {
  16. /**
  17. * 将parser作为线程变量。
  18. */
  19. private ThreadLocal<SAXParser> parser = new ThreadLocal<SAXParser>() {
  20. protected SAXParser initialValue() {
  21. SAXParser newParser = null;
  22. SAXParserFactory factory = SAXParserFactory.newInstance();
  23. factory.setNamespaceAware( true);
  24. try {
  25. newParser = factory.newSAXParser();
  26. } catch (ParserConfigurationException e) {
  27. e.printStackTrace();
  28. } catch (SAXException e) {
  29. e.printStackTrace();
  30. }
  31. return newParser;
  32. };
  33. };
  34. // now we parse XML in this way.
  35. public void parseXml(InputStream input) {
  36. try {
  37. DefaultHandler handler = new DefaultHandler();
  38. // next use the parser to parse the xml source.
  39. parser.get().parse(input, handler);
  40. } catch (SAXException e) {
  41. e.printStackTrace();
  42. } catch (IOException e) {
  43. e.printStackTrace();
  44. }
  45. }
  46. }

注:

在Java多线程著名书籍Brian Goetz的著作《Java Concurrency in Practice》中提到,使用ThreadLocal来维持线程封闭,对每个线程来说它只看到和操作了与其对应的变量副本,这个是个很好用的特性。

猜你喜欢

转载自blog.csdn.net/golden_soft/article/details/81012414